• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.settings.connectivity;
18 
19 import android.content.Context;
20 import android.net.wifi.WifiConfiguration;
21 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
22 import android.net.wifi.WifiConfiguration.KeyMgmt;
23 import android.net.wifi.WifiInfo;
24 import android.net.wifi.WifiManager;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import com.android.settingslib.wifi.AccessPoint;
29 import com.android.tv.settings.R;
30 import com.android.tv.settings.connectivity.util.WifiSecurityUtil;
31 
32 import java.util.List;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35 
36 /**
37  * Helper class that deals with Wi-fi configuration.
38  */
39 public final class WifiConfigHelper {
40 
41     private static final String TAG = "WifiConfigHelper";
42     private static final boolean DEBUG = false;
43 
44     // Allows underscore char to supports proxies that do not
45     // follow the spec
46     private static final String HC = "a-zA-Z0-9\\_";
47 
48     // Matches blank input, ips, and domain names
49     private static final String HOSTNAME_REGEXP =
50             "^$|^[" + HC + "]+(\\-[" + HC + "]+)*(\\.[" + HC + "]+(\\-[" + HC + "]+)*)*$";
51     private static final Pattern HOSTNAME_PATTERN;
52     private static final String EXCLUSION_REGEXP =
53             "$|^(\\*)?\\.?[" + HC + "]+(\\-[" + HC + "]+)*(\\.[" + HC + "]+(\\-[" + HC + "]+)*)*$";
54     private static final Pattern EXCLUSION_PATTERN;
55 
56     private static final String BYPASS_PROXY_EXCLUDE_REGEX =
57             "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*";
58     private static final String BYPASS_PROXY_EXCLUDE_LIST_REGEXP = "^$|^"
59             + BYPASS_PROXY_EXCLUDE_REGEX + "(," + BYPASS_PROXY_EXCLUDE_REGEX + ")*$";
60     private static final Pattern BYPASS_PROXY_EXCLUSION_PATTERN;
61 
62     static {
63         HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
64         EXCLUSION_PATTERN = Pattern.compile(EXCLUSION_REGEXP);
65         BYPASS_PROXY_EXCLUSION_PATTERN = Pattern.compile(BYPASS_PROXY_EXCLUDE_LIST_REGEXP);
66     }
67 
WifiConfigHelper()68     private WifiConfigHelper() {
69     }
70 
71     /**
72      * Set configuration ssid.
73      *
74      * @param config configuration
75      * @param ssid   network ssid
76      */
setConfigSsid(WifiConfiguration config, String ssid)77     public static void setConfigSsid(WifiConfiguration config, String ssid) {
78         config.SSID = AccessPoint.convertToQuotedString(ssid);
79     }
80 
81     /**
82      * Set configuration key managment by security.
83      */
setConfigKeyManagementBySecurity( WifiConfiguration config, int security)84     public static void setConfigKeyManagementBySecurity(
85             WifiConfiguration config, int security) {
86         config.allowedKeyManagement.clear();
87         config.allowedAuthAlgorithms.clear();
88         switch (security) {
89             case AccessPoint.SECURITY_NONE:
90                 config.allowedKeyManagement.set(KeyMgmt.NONE);
91                 break;
92             case AccessPoint.SECURITY_WEP:
93                 config.allowedKeyManagement.set(KeyMgmt.NONE);
94                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
95                 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
96                 break;
97             case AccessPoint.SECURITY_PSK:
98                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
99                 break;
100             case AccessPoint.SECURITY_EAP:
101                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
102                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
103                 break;
104         }
105     }
106 
107     /**
108      * validate syntax of hostname and port entries
109      *
110      * @param hostname host name to be used
111      * @param port port to be used
112      * @param exclList what should be accepted as input
113      * @return 0 on success, string resource ID on failure
114      */
validate(String hostname, String port, String exclList)115     public static int validate(String hostname, String port, String exclList) {
116         return validate(hostname, port, exclList, false);
117     }
118 
119     /**
120      * validate syntax of hostname and port entries
121      *
122      * @param hostname host name to be used
123      * @param port port to be used
124      * @param exclList what should be accepted as input
125      * @param forProxyCheck if extra check for bypass proxy should be done
126      * @return 0 on success, string resource ID on failure
127      */
validate(String hostname, String port, String exclList, boolean forProxyCheck)128     public static int validate(String hostname, String port, String exclList,
129                                boolean forProxyCheck) {
130         if (DEBUG) {
131             Log.i(TAG, "validate, hostname: " + hostname + ", for proxy=" + forProxyCheck);
132         }
133         Matcher match = HOSTNAME_PATTERN.matcher(hostname);
134         String[] exclListArray = exclList.split(",");
135 
136         if (!match.matches()) return R.string.proxy_error_invalid_host;
137 
138         for (String excl : exclListArray) {
139             Matcher m;
140             if (forProxyCheck) {
141                 m = BYPASS_PROXY_EXCLUSION_PATTERN.matcher(excl);
142             } else {
143                 m = EXCLUSION_PATTERN.matcher(excl);
144             }
145             if (!m.matches()) {
146                 return R.string.proxy_error_invalid_exclusion_list;
147             }
148         }
149 
150         if (hostname.length() > 0 && port.length() == 0) {
151             return R.string.proxy_error_empty_port;
152         }
153 
154         if (port.length() > 0) {
155             if (hostname.length() == 0) {
156                 return R.string.proxy_error_empty_host_set_port;
157             }
158             int portVal = -1;
159             try {
160                 portVal = Integer.parseInt(port);
161             } catch (NumberFormatException ex) {
162                 return R.string.proxy_error_invalid_port;
163             }
164             if (portVal <= 0 || portVal > 0xFFFF) {
165                 return R.string.proxy_error_invalid_port;
166             }
167         }
168         return 0;
169     }
170 
171     /**
172      * Get {@link WifiConfiguration} based upon the {@link WifiManager} and networkId.
173      *
174      * @param networkId the id of the network.
175      * @return the {@link WifiConfiguration} of the specified network.
176      */
getWifiConfiguration(WifiManager wifiManager, int networkId)177     public static WifiConfiguration getWifiConfiguration(WifiManager wifiManager, int networkId) {
178         List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
179         if (configuredNetworks != null) {
180             for (WifiConfiguration configuredNetwork : configuredNetworks) {
181                 if (configuredNetwork.networkId == networkId) {
182                     return configuredNetwork;
183                 }
184             }
185         }
186         return null;
187     }
188 
189     /**
190      * Did this config come out of the supplicant?  NOT "Is the config currently in the supplicant?"
191      */
isNetworkSaved(WifiConfiguration config)192     public static boolean isNetworkSaved(WifiConfiguration config) {
193         return config != null && config.networkId > -1;
194     }
195 
196     /**
197      * Return the configured network that matches the ssid/security pair, or create one.
198      */
getConfiguration(Context context, String ssid, int security)199     public static WifiConfiguration getConfiguration(Context context, String ssid, int security) {
200         WifiConfiguration config = getFromConfiguredNetworks(context, ssid, security);
201 
202         if (config == null) {
203             // No configured network found; populate a new one with the provided ssid / security.
204             config = new WifiConfiguration();
205             setConfigSsid(config, ssid);
206             setConfigKeyManagementBySecurity(config, security);
207         }
208         return config;
209     }
210 
211     /**
212      * Save a wifi configuration.
213      */
saveConfiguration(Context context, WifiConfiguration config)214     public static boolean saveConfiguration(Context context, WifiConfiguration config) {
215         if (config == null) {
216             return false;
217         }
218 
219         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
220         int networkId = wifiMan.addNetwork(config);
221         if (networkId == -1) {
222             if (DEBUG) Log.e(TAG, "failed to add network: " + config.toString());
223             return false;
224         }
225 
226         if (!wifiMan.enableNetwork(networkId, false)) {
227             if (DEBUG) Log.e(TAG, "enable network failed: " + networkId + "; " + config.toString());
228             return false;
229         }
230 
231         if (!wifiMan.saveConfiguration()) {
232             if (DEBUG) Log.e(TAG, "failed to save: " + config.toString());
233             return false;
234         }
235 
236         if (DEBUG) Log.d(TAG, "saved network: " + config.toString());
237         return true;
238     }
239 
240     /**
241      * @return A matching WifiConfiguration from the list of configured
242      * networks, or null if no matching network is found.
243      */
getFromConfiguredNetworks(Context context, String ssid, int security)244     private static WifiConfiguration getFromConfiguredNetworks(Context context,
245             String ssid,
246             int security) {
247         WifiManager wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
248         List<WifiConfiguration> configuredNetworks = wifiMan.getConfiguredNetworks();
249         if (configuredNetworks != null) {
250             for (WifiConfiguration configuredNetwork : configuredNetworks) {
251                 if (configuredNetwork == null || configuredNetwork.SSID == null) {
252                     continue;  // Does this ever really happen?
253                 }
254 
255                 // If the SSID and the security match, that's our network.
256                 String configuredSsid = WifiInfo.sanitizeSsid(configuredNetwork.SSID);
257 
258                 if (TextUtils.equals(configuredSsid, ssid)) {
259                     int configuredSecurity = WifiSecurityUtil.getSecurity(configuredNetwork);
260                     if (configuredSecurity == security) {
261                         return configuredNetwork;
262                     }
263                 }
264             }
265         }
266 
267         return null;
268     }
269 }
270