connection.js (15276B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* import-globals-from /browser/base/content/utilityOverlay.js */ 7 /* import-globals-from /toolkit/content/preferencesBindings.js */ 8 /* import-globals-from ../extensionControlled.js */ 9 10 const proxyService = Ci.nsIProtocolProxyService; 11 12 const PROXY_TYPES_MAP_REVERSE = new Map([ 13 [proxyService.PROXYCONFIG_DIRECT, "DIRECT"], 14 [proxyService.PROXYCONFIG_MANUAL, "MANUAL"], 15 [proxyService.PROXYCONFIG_PAC, "PAC"], 16 [proxyService.PROXYCONFIG_WPAD, "WPAD"], 17 [proxyService.PROXYCONFIG_SYSTEM, "SYSTEM"], 18 ]); 19 20 Preferences.addAll([ 21 // Add network.proxy.autoconfig_url before network.proxy.type so they're 22 // both initialized when network.proxy.type initialization triggers a call to 23 // gConnectionsDialog.updateReloadButton(). 24 { id: "network.proxy.autoconfig_url", type: "string" }, 25 { id: "network.proxy.system_wpad", type: "bool" }, 26 { id: "network.proxy.type", type: "int" }, 27 { id: "network.proxy.http", type: "string" }, 28 { id: "network.proxy.http_port", type: "int" }, 29 { id: "network.proxy.ssl", type: "string" }, 30 { id: "network.proxy.ssl_port", type: "int" }, 31 { id: "network.proxy.socks", type: "string" }, 32 { id: "network.proxy.socks_port", type: "int" }, 33 { id: "network.proxy.socks_version", type: "int" }, 34 { id: "network.proxy.socks_remote_dns", type: "bool" }, 35 { id: "network.proxy.socks5_remote_dns", type: "bool" }, 36 { id: "network.proxy.no_proxies_on", type: "string" }, 37 { id: "network.proxy.share_proxy_settings", type: "bool" }, 38 { id: "signon.autologin.proxy", type: "bool" }, 39 { id: "pref.advanced.proxies.disable_button.reload", type: "bool" }, 40 { id: "network.proxy.backup.ssl", type: "string" }, 41 { id: "network.proxy.backup.ssl_port", type: "int" }, 42 ]); 43 44 window.addEventListener( 45 "DOMContentLoaded", 46 () => { 47 Preferences.get("network.proxy.type").on( 48 "change", 49 gConnectionsDialog.proxyTypeChanged.bind(gConnectionsDialog) 50 ); 51 Preferences.get("network.proxy.socks_version").on( 52 "change", 53 gConnectionsDialog.updateDNSPref.bind(gConnectionsDialog) 54 ); 55 56 document 57 .getElementById("key_close") 58 .addEventListener("command", event => Preferences.close(event)); 59 60 document 61 .getElementById("disableProxyExtension") 62 .addEventListener( 63 "command", 64 makeDisableControllingExtension(PREF_SETTING_TYPE, PROXY_KEY).bind( 65 gConnectionsDialog 66 ) 67 ); 68 document 69 .getElementById("networkProxyAutoconfigURL") 70 .addEventListener("input", () => gConnectionsDialog.updateReloadButton()); 71 document 72 .getElementById("autoReload") 73 .addEventListener("command", () => gConnectionsDialog.reloadPAC()); 74 75 gConnectionsDialog.checkForSystemProxy(); 76 gConnectionsDialog.updateProxySettingsUI(); 77 initializeProxyUI(gConnectionsDialog); 78 gConnectionsDialog.registerSyncPrefListeners(); 79 document 80 .getElementById("ConnectionsDialog") 81 .addEventListener("beforeaccept", e => 82 gConnectionsDialog.beforeAccept(e) 83 ); 84 }, 85 { once: true, capture: true } 86 ); 87 88 var gConnectionsDialog = { 89 beforeAccept(event) { 90 var proxyTypePref = Preferences.get("network.proxy.type"); 91 92 // collect "network.proxy.type" to glean metrics 93 let proxyTypePrefStr = 94 PROXY_TYPES_MAP_REVERSE.get(proxyTypePref.value) || "OTHER"; 95 Glean.networkProxySettings.proxyTypePreference.record({ 96 value: proxyTypePrefStr, 97 }); 98 99 if (proxyTypePref.value == 2) { 100 this.doAutoconfigURLFixup(); 101 return; 102 } 103 104 if (proxyTypePref.value != 1) { 105 return; 106 } 107 108 var httpProxyURLPref = Preferences.get("network.proxy.http"); 109 var httpProxyPortPref = Preferences.get("network.proxy.http_port"); 110 var shareProxiesPref = Preferences.get( 111 "network.proxy.share_proxy_settings" 112 ); 113 114 // If the proxy server (when specified) is invalid or the port is set to 0 then cancel submission. 115 for (let prefName of ["http", "ssl", "socks"]) { 116 let proxyPortPref = Preferences.get( 117 "network.proxy." + prefName + "_port" 118 ); 119 let proxyPref = Preferences.get("network.proxy." + prefName); 120 // Only worry about ports which are currently active. If the share option is on, then ignore 121 // all ports except the HTTP and SOCKS port 122 if ( 123 proxyPref.value != "" && 124 (prefName == "http" || prefName == "socks" || !shareProxiesPref.value) 125 ) { 126 if (proxyPortPref.value == 0) { 127 document 128 .getElementById("networkProxy" + prefName.toUpperCase() + "_Port") 129 .focus(); 130 event.preventDefault(); 131 return; 132 } else if (!Services.io.isValidHostname(proxyPref.value)) { 133 document 134 .getElementById("networkProxy" + prefName.toUpperCase()) 135 .focus(); 136 event.preventDefault(); 137 return; 138 } 139 } 140 } 141 142 // In the case of a shared proxy preference, backup the current values and update with the HTTP value 143 if (shareProxiesPref.value) { 144 var proxyServerURLPref = Preferences.get("network.proxy.ssl"); 145 var proxyPortPref = Preferences.get("network.proxy.ssl_port"); 146 var backupServerURLPref = Preferences.get("network.proxy.backup.ssl"); 147 var backupPortPref = Preferences.get("network.proxy.backup.ssl_port"); 148 backupServerURLPref.value = 149 backupServerURLPref.value || proxyServerURLPref.value; 150 backupPortPref.value = backupPortPref.value || proxyPortPref.value; 151 proxyServerURLPref.value = httpProxyURLPref.value; 152 proxyPortPref.value = httpProxyPortPref.value; 153 } 154 155 this.sanitizeNoProxiesPref(); 156 }, 157 158 checkForSystemProxy() { 159 if ("@mozilla.org/system-proxy-settings;1" in Cc) { 160 document.getElementById("systemPref").removeAttribute("hidden"); 161 162 var systemWpadAllowed = Services.prefs.getBoolPref( 163 "network.proxy.system_wpad.allowed", 164 false 165 ); 166 if (systemWpadAllowed && AppConstants.platform == "win") { 167 document.getElementById("systemWpad").removeAttribute("hidden"); 168 } 169 } 170 }, 171 172 proxyTypeChanged() { 173 var proxyTypePref = Preferences.get("network.proxy.type"); 174 var systemWpadPref = Preferences.get("network.proxy.system_wpad"); 175 systemWpadPref.updateControlDisabledState(proxyTypePref.value != 5); 176 177 // Update http 178 var httpProxyURLPref = Preferences.get("network.proxy.http"); 179 httpProxyURLPref.updateControlDisabledState(proxyTypePref.value != 1); 180 var httpProxyPortPref = Preferences.get("network.proxy.http_port"); 181 httpProxyPortPref.updateControlDisabledState(proxyTypePref.value != 1); 182 183 // Now update the other protocols 184 this.updateProtocolPrefs(); 185 186 var shareProxiesPref = Preferences.get( 187 "network.proxy.share_proxy_settings" 188 ); 189 shareProxiesPref.updateControlDisabledState(proxyTypePref.value != 1); 190 var autologinProxyPref = Preferences.get("signon.autologin.proxy"); 191 autologinProxyPref.updateControlDisabledState(proxyTypePref.value == 0); 192 var noProxiesPref = Preferences.get("network.proxy.no_proxies_on"); 193 noProxiesPref.updateControlDisabledState(proxyTypePref.value == 0); 194 195 var autoconfigURLPref = Preferences.get("network.proxy.autoconfig_url"); 196 autoconfigURLPref.updateControlDisabledState(proxyTypePref.value != 2); 197 198 this.updateReloadButton(); 199 200 document.getElementById("networkProxyNoneLocalhost").hidden = 201 Services.prefs.getBoolPref( 202 "network.proxy.allow_hijacking_localhost", 203 false 204 ); 205 }, 206 207 updateDNSPref() { 208 var socksVersionPref = Preferences.get("network.proxy.socks_version"); 209 var socks4DNSPref = Preferences.get("network.proxy.socks_remote_dns"); 210 var socks5DNSPref = Preferences.get("network.proxy.socks5_remote_dns"); 211 var proxyTypePref = Preferences.get("network.proxy.type"); 212 var isDefinitelySocks4 = 213 proxyTypePref.value == 1 && socksVersionPref.value == 4; 214 socks5DNSPref.updateControlDisabledState( 215 isDefinitelySocks4 || proxyTypePref.value == 0 216 ); 217 var isDefinitelySocks5 = 218 proxyTypePref.value == 1 && socksVersionPref.value == 5; 219 socks4DNSPref.updateControlDisabledState( 220 isDefinitelySocks5 || proxyTypePref.value == 0 221 ); 222 return undefined; 223 }, 224 225 updateReloadButton() { 226 // Disable the "Reload PAC" button if the selected proxy type is not PAC or 227 // if the current value of the PAC input does not match the value stored 228 // in prefs. Likewise, disable the reload button if PAC is not configured 229 // in prefs. 230 231 var typedURL = document.getElementById("networkProxyAutoconfigURL").value; 232 var proxyTypeCur = Preferences.get("network.proxy.type").value; 233 234 var pacURL = Services.prefs.getCharPref("network.proxy.autoconfig_url"); 235 var proxyType = Services.prefs.getIntPref("network.proxy.type"); 236 237 var disableReloadPref = Preferences.get( 238 "pref.advanced.proxies.disable_button.reload" 239 ); 240 disableReloadPref.updateControlDisabledState( 241 proxyTypeCur != 2 || proxyType != 2 || typedURL != pacURL 242 ); 243 }, 244 245 readProxyType() { 246 this.proxyTypeChanged(); 247 return undefined; 248 }, 249 250 updateProtocolPrefs() { 251 var proxyTypePref = Preferences.get("network.proxy.type"); 252 var shareProxiesPref = Preferences.get( 253 "network.proxy.share_proxy_settings" 254 ); 255 var proxyPrefs = ["ssl", "socks"]; 256 for (var i = 0; i < proxyPrefs.length; ++i) { 257 var proxyServerURLPref = Preferences.get( 258 "network.proxy." + proxyPrefs[i] 259 ); 260 var proxyPortPref = Preferences.get( 261 "network.proxy." + proxyPrefs[i] + "_port" 262 ); 263 264 // Restore previous per-proxy custom settings, if present. 265 if (proxyPrefs[i] != "socks" && !shareProxiesPref.value) { 266 var backupServerURLPref = Preferences.get( 267 "network.proxy.backup." + proxyPrefs[i] 268 ); 269 var backupPortPref = Preferences.get( 270 "network.proxy.backup." + proxyPrefs[i] + "_port" 271 ); 272 if (backupServerURLPref.hasUserValue) { 273 proxyServerURLPref.value = backupServerURLPref.value; 274 backupServerURLPref.reset(); 275 } 276 if (backupPortPref.hasUserValue) { 277 proxyPortPref.value = backupPortPref.value; 278 backupPortPref.reset(); 279 } 280 } 281 282 proxyServerURLPref.updateElements(); 283 proxyPortPref.updateElements(); 284 let prefIsShared = proxyPrefs[i] != "socks" && shareProxiesPref.value; 285 proxyServerURLPref.updateControlDisabledState( 286 proxyTypePref.value != 1 || prefIsShared 287 ); 288 proxyPortPref.updateControlDisabledState( 289 proxyTypePref.value != 1 || prefIsShared 290 ); 291 } 292 var socksVersionPref = Preferences.get("network.proxy.socks_version"); 293 socksVersionPref.updateControlDisabledState(proxyTypePref.value != 1); 294 this.updateDNSPref(); 295 return undefined; 296 }, 297 298 readProxyProtocolPref(aProtocol, aIsPort) { 299 if (aProtocol != "socks") { 300 var shareProxiesPref = Preferences.get( 301 "network.proxy.share_proxy_settings" 302 ); 303 if (shareProxiesPref.value) { 304 var pref = Preferences.get( 305 "network.proxy.http" + (aIsPort ? "_port" : "") 306 ); 307 return pref.value; 308 } 309 310 var backupPref = Preferences.get( 311 "network.proxy.backup." + aProtocol + (aIsPort ? "_port" : "") 312 ); 313 return backupPref.hasUserValue ? backupPref.value : undefined; 314 } 315 return undefined; 316 }, 317 318 reloadPAC() { 319 Cc["@mozilla.org/network/protocol-proxy-service;1"] 320 .getService() 321 .reloadPAC(); 322 }, 323 324 doAutoconfigURLFixup() { 325 var autoURL = document.getElementById("networkProxyAutoconfigURL"); 326 var autoURLPref = Preferences.get("network.proxy.autoconfig_url"); 327 try { 328 autoURLPref.value = autoURL.value = Services.uriFixup.getFixupURIInfo( 329 autoURL.value 330 ).preferredURI.spec; 331 } catch (ex) {} 332 }, 333 334 sanitizeNoProxiesPref() { 335 var noProxiesPref = Preferences.get("network.proxy.no_proxies_on"); 336 // replace substrings of ; and \n with commas if they're neither immediately 337 // preceded nor followed by a valid separator character 338 noProxiesPref.value = noProxiesPref.value.replace( 339 /([^, \n;])[;\n]+(?![,\n;])/g, 340 "$1," 341 ); 342 // replace any remaining ; and \n since some may follow commas, etc. 343 noProxiesPref.value = noProxiesPref.value.replace(/[;\n]/g, ""); 344 }, 345 346 readHTTPProxyServer() { 347 var shareProxiesPref = Preferences.get( 348 "network.proxy.share_proxy_settings" 349 ); 350 if (shareProxiesPref.value) { 351 this.updateProtocolPrefs(); 352 } 353 return undefined; 354 }, 355 356 readHTTPProxyPort() { 357 var shareProxiesPref = Preferences.get( 358 "network.proxy.share_proxy_settings" 359 ); 360 if (shareProxiesPref.value) { 361 this.updateProtocolPrefs(); 362 } 363 return undefined; 364 }, 365 366 getProxyControls() { 367 let controlGroup = document.getElementById("networkProxyType"); 368 return [ 369 ...controlGroup.querySelectorAll(":scope > radio"), 370 ...controlGroup.querySelectorAll("label"), 371 ...controlGroup.querySelectorAll("input"), 372 ...controlGroup.querySelectorAll("checkbox"), 373 ...document.querySelectorAll("#networkProxySOCKSVersion > radio"), 374 ...document.querySelectorAll("#ConnectionsDialogPane > checkbox"), 375 ]; 376 }, 377 378 // Update the UI to show/hide the extension controlled message for 379 // proxy settings. 380 async updateProxySettingsUI() { 381 let isLocked = API_PROXY_PREFS.some(pref => 382 Services.prefs.prefIsLocked(pref) 383 ); 384 385 function setInputsDisabledState(isControlled) { 386 for (let element of gConnectionsDialog.getProxyControls()) { 387 element.disabled = isControlled; 388 } 389 gConnectionsDialog.proxyTypeChanged(); 390 } 391 392 if (isLocked) { 393 // An extension can't control this setting if any pref is locked. 394 hideControllingExtension(PROXY_KEY); 395 } else { 396 handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY).then( 397 setInputsDisabledState 398 ); 399 } 400 }, 401 402 registerSyncPrefListeners() { 403 function setSyncFromPrefListener(element_id, callback) { 404 Preferences.addSyncFromPrefListener( 405 document.getElementById(element_id), 406 callback 407 ); 408 } 409 setSyncFromPrefListener("networkProxyType", () => this.readProxyType()); 410 setSyncFromPrefListener("networkProxyHTTP", () => 411 this.readHTTPProxyServer() 412 ); 413 setSyncFromPrefListener("networkProxyHTTP_Port", () => 414 this.readHTTPProxyPort() 415 ); 416 setSyncFromPrefListener("shareAllProxies", () => 417 this.updateProtocolPrefs() 418 ); 419 setSyncFromPrefListener("networkProxySSL", () => 420 this.readProxyProtocolPref("ssl", false) 421 ); 422 setSyncFromPrefListener("networkProxySSL_Port", () => 423 this.readProxyProtocolPref("ssl", true) 424 ); 425 setSyncFromPrefListener("networkProxySOCKS", () => 426 this.readProxyProtocolPref("socks", false) 427 ); 428 setSyncFromPrefListener("networkProxySOCKS_Port", () => 429 this.readProxyProtocolPref("socks", true) 430 ); 431 }, 432 };