 Chromium Code Reviews
 Chromium Code Reviews Issue 1017443002:
  Allow users to add third-party VPNs from the settings page  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@f_3_460428_update_details_dialog
    
  
    Issue 1017443002:
  Allow users to add third-party VPNs from the settings page  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@f_3_460428_update_details_dialog| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 /** | 5 /** | 
| 6 * This partially describes the network list entries passed to | 6 * This partially describes the network list entries passed to | 
| 7 * refreshNetworkData. The contents of those lists actually match | 7 * refreshNetworkData. The contents of those lists actually match | 
| 8 * CrOnc.NetworkConfigType with the addition of the policyManaged property. | 8 * CrOnc.NetworkConfigType with the addition of the policyManaged property. | 
| 9 * TODO(stevenjb): Use networkingPrivate.getNetworks. | 9 * TODO(stevenjb): Use networkingPrivate.getNetworks. | 
| 10 * @typedef {{ | 10 * @typedef {{ | 
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 Menu.decorate(menu); | 368 Menu.decorate(menu); | 
| 369 for (var i = 0; i < this.data.menu.length; i++) { | 369 for (var i = 0; i < this.data.menu.length; i++) { | 
| 370 var entry = this.data.menu[i]; | 370 var entry = this.data.menu[i]; | 
| 371 createCallback_(menu, null, entry.label, entry.command); | 371 createCallback_(menu, null, entry.label, entry.command); | 
| 372 } | 372 } | 
| 373 return menu; | 373 return menu; | 
| 374 } | 374 } | 
| 375 return null; | 375 return null; | 
| 376 }, | 376 }, | 
| 377 | 377 | 
| 378 /** | |
| 379 * Determines if a menu can be updated on the fly. Menus that cannot be | |
| 380 * updated are fully regenerated using createMenu. The advantage of | |
| 381 * updating a menu is that it can preserve ordering of networks avoiding | |
| 382 * entries from jumping around after an update. | |
| 383 * @return {boolean} Whether the menu can be updated on the fly. | |
| 384 */ | |
| 378 canUpdateMenu: function() { | 385 canUpdateMenu: function() { | 
| 379 return false; | 386 return false; | 
| 380 }, | 387 }, | 
| 381 | 388 | 
| 382 /** | 389 /** | 
| 390 * Removes the current menu contents, causing it to be regenerated when the | |
| 391 * menu is shown the next time. If the menu is showing right now, its | |
| 392 * contents are regenerated immediately and the menu remains visible. | |
| 393 */ | |
| 394 refreshMenu: function() { | |
| 395 this.menu_ = null; | |
| 396 if (activeMenu_ == this.getMenuName()) | |
| 397 this.showMenu(); | |
| 398 }, | |
| 399 | |
| 400 /** | |
| 383 * Displays a popup menu. | 401 * Displays a popup menu. | 
| 384 */ | 402 */ | 
| 385 showMenu: function() { | 403 showMenu: function() { | 
| 386 var rebuild = false; | 404 var rebuild = false; | 
| 387 // Force a rescan if opening the menu for WiFi networks to ensure the | 405 // Force a rescan if opening the menu for WiFi networks to ensure the | 
| 388 // list is up to date. Networks are periodically rescanned, but depending | 406 // list is up to date. Networks are periodically rescanned, but depending | 
| 389 // on timing, there could be an excessive delay before the first rescan | 407 // on timing, there could be an excessive delay before the first rescan | 
| 390 // unless forced. | 408 // unless forced. | 
| 391 var rescan = !activeMenu_ && this.data_.key == 'WiFi'; | 409 var rescan = !activeMenu_ && this.data_.key == 'WiFi'; | 
| 392 if (!this.menu_) { | 410 if (!this.menu_) { | 
| 393 rebuild = true; | 411 rebuild = true; | 
| 394 var existing = $(this.getMenuName()); | 412 var existing = $(this.getMenuName()); | 
| 395 if (existing) { | 413 if (existing) { | 
| 396 if (this.updateMenu()) | 414 if (this.canUpdateMenu() && this.updateMenu()) | 
| 397 return; | 415 return; | 
| 398 closeMenu_(); | 416 closeMenu_(); | 
| 399 } | 417 } | 
| 400 this.menu_ = this.createMenu(); | 418 this.menu_ = this.createMenu(); | 
| 401 this.menu_.addEventListener('mousedown', function(e) { | 419 this.menu_.addEventListener('mousedown', function(e) { | 
| 402 // Prevent blurring of list, which would close the menu. | 420 // Prevent blurring of list, which would close the menu. | 
| 403 e.preventDefault(); | 421 e.preventDefault(); | 
| 404 }); | 422 }); | 
| 405 var parent = $('network-menus'); | 423 var parent = $('network-menus'); | 
| 406 if (existing) | 424 if (existing) | 
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 490 createMenu: function() { | 508 createMenu: function() { | 
| 491 var menu = this.ownerDocument.createElement('div'); | 509 var menu = this.ownerDocument.createElement('div'); | 
| 492 menu.id = this.getMenuName(); | 510 menu.id = this.getMenuName(); | 
| 493 menu.className = 'network-menu'; | 511 menu.className = 'network-menu'; | 
| 494 menu.hidden = true; | 512 menu.hidden = true; | 
| 495 Menu.decorate(menu); | 513 Menu.decorate(menu); | 
| 496 var addendum = []; | 514 var addendum = []; | 
| 497 if (this.data_.key == 'WiFi') { | 515 if (this.data_.key == 'WiFi') { | 
| 498 addendum.push({ | 516 addendum.push({ | 
| 499 label: loadTimeData.getString('joinOtherNetwork'), | 517 label: loadTimeData.getString('joinOtherNetwork'), | 
| 500 command: createAddConnectionCallback_('WiFi'), | 518 command: createAddNonVPNConnectionCallback_('WiFi'), | 
| 501 data: {} | 519 data: {} | 
| 502 }); | 520 }); | 
| 503 } else if (this.data_.key == 'Cellular') { | 521 } else if (this.data_.key == 'Cellular') { | 
| 504 if (cellularEnabled_ && cellularSupportsScan_) { | 522 if (cellularEnabled_ && cellularSupportsScan_) { | 
| 505 addendum.push({ | 523 addendum.push({ | 
| 506 label: loadTimeData.getString('otherCellularNetworks'), | 524 label: loadTimeData.getString('otherCellularNetworks'), | 
| 507 command: createAddConnectionCallback_('Cellular'), | 525 command: createAddNonVPNConnectionCallback_('Cellular'), | 
| 508 addClass: ['other-cellulars'], | 526 addClass: ['other-cellulars'], | 
| 509 data: {} | 527 data: {} | 
| 510 }); | 528 }); | 
| 511 } | 529 } | 
| 512 | 530 | 
| 513 var label = enableDataRoaming_ ? 'disableDataRoaming' : | 531 var label = enableDataRoaming_ ? 'disableDataRoaming' : | 
| 514 'enableDataRoaming'; | 532 'enableDataRoaming'; | 
| 515 var disabled = !loadTimeData.getValue('loggedInAsOwner'); | 533 var disabled = !loadTimeData.getValue('loggedInAsOwner'); | 
| 516 var entry = {label: loadTimeData.getString(label), | 534 var entry = {label: loadTimeData.getString(label), | 
| 517 data: {}}; | 535 data: {}}; | 
| 518 if (disabled) { | 536 if (disabled) { | 
| 519 entry.command = null; | 537 entry.command = null; | 
| 520 entry.tooltip = | 538 entry.tooltip = | 
| 521 loadTimeData.getString('dataRoamingDisableToggleTooltip'); | 539 loadTimeData.getString('dataRoamingDisableToggleTooltip'); | 
| 522 } else { | 540 } else { | 
| 523 var self = this; | 541 var self = this; | 
| 524 entry.command = function() { | 542 entry.command = function() { | 
| 525 options.Preferences.setBooleanPref( | 543 options.Preferences.setBooleanPref( | 
| 526 'cros.signed.data_roaming_enabled', | 544 'cros.signed.data_roaming_enabled', | 
| 527 !enableDataRoaming_, true); | 545 !enableDataRoaming_, true); | 
| 528 // Force revalidation of the menu the next time it is displayed. | 546 // Force revalidation of the menu the next time it is displayed. | 
| 529 self.menu_ = null; | 547 self.menu_ = null; | 
| 530 }; | 548 }; | 
| 531 } | 549 } | 
| 532 addendum.push(entry); | 550 addendum.push(entry); | 
| 533 } else if (this.data_.key == 'VPN') { | 551 } else if (this.data_.key == 'VPN') { | 
| 534 addendum.push({ | 552 addendum = addendum.concat(createAddVPNConnectionEntries_()); | 
| 535 label: loadTimeData.getString('joinOtherNetwork'), | |
| 536 command: createAddConnectionCallback_('VPN'), | |
| 537 data: {} | |
| 538 }); | |
| 539 } | 553 } | 
| 540 | 554 | 
| 541 var list = this.data.rememberedNetworks; | 555 var list = this.data.rememberedNetworks; | 
| 542 if (list && list.length > 0) { | 556 if (list && list.length > 0) { | 
| 543 var callback = function(list) { | 557 var callback = function(list) { | 
| 544 $('remembered-network-list').clear(); | 558 $('remembered-network-list').clear(); | 
| 545 var dialog = options.PreferredNetworks.getInstance(); | 559 var dialog = options.PreferredNetworks.getInstance(); | 
| 546 PageManager.showPageByName('preferredNetworksPage', false); | 560 PageManager.showPageByName('preferredNetworksPage', false); | 
| 547 dialog.update(list); | 561 dialog.update(list); | 
| 548 sendChromeMetricsAction('Options_NetworkShowPreferred'); | 562 sendChromeMetricsAction('Options_NetworkShowPreferred'); | 
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 627 separator = false; | 641 separator = false; | 
| 628 } else if (!separator) { | 642 } else if (!separator) { | 
| 629 menu.appendChild(MenuItem.createSeparator()); | 643 menu.appendChild(MenuItem.createSeparator()); | 
| 630 separator = true; | 644 separator = true; | 
| 631 } | 645 } | 
| 632 } | 646 } | 
| 633 } | 647 } | 
| 634 return menu; | 648 return menu; | 
| 635 }, | 649 }, | 
| 636 | 650 | 
| 637 /** | 651 /** @override */ | 
| 638 * Determines if a menu can be updated on the fly. Menus that cannot be | |
| 639 * updated are fully regenerated using createMenu. The advantage of | |
| 640 * updating a menu is that it can preserve ordering of networks avoiding | |
| 641 * entries from jumping around after an update. | |
| 642 */ | |
| 643 canUpdateMenu: function() { | 652 canUpdateMenu: function() { | 
| 644 return this.data_.key == 'WiFi' && activeMenu_ == this.getMenuName(); | 653 return this.data_.key == 'WiFi' && activeMenu_ == this.getMenuName(); | 
| 645 }, | 654 }, | 
| 646 | 655 | 
| 647 /** | 656 /** | 
| 648 * Updates an existing menu. Updated menus preserve ordering of prior | 657 * Updates an existing menu. Updated menus preserve ordering of prior | 
| 649 * entries. During the update process, the ordering may differ from the | 658 * entries. During the update process, the ordering may differ from the | 
| 650 * preferred ordering as determined by the network library. If the | 659 * preferred ordering as determined by the network library. If the | 
| 651 * ordering becomes potentially out of sync, then the updated menu is | 660 * ordering becomes potentially out of sync, then the updated menu is | 
| 652 * marked for disposal on close. Reopening the menu will force a | 661 * marked for disposal on close. Reopening the menu will force a | 
| 653 * regeneration, which will in turn fix the ordering. | 662 * regeneration, which will in turn fix the ordering. This method must only | 
| 663 * be called if canUpdateMenu() returned |true|. | |
| 654 * @return {boolean} True if successfully updated. | 664 * @return {boolean} True if successfully updated. | 
| 655 */ | 665 */ | 
| 656 updateMenu: function() { | 666 updateMenu: function() { | 
| 657 if (!this.canUpdateMenu()) | |
| 658 return false; | |
| 659 var oldMenu = $(this.getMenuName()); | 667 var oldMenu = $(this.getMenuName()); | 
| 660 var group = oldMenu.getElementsByClassName('network-menu-group')[0]; | 668 var group = oldMenu.getElementsByClassName('network-menu-group')[0]; | 
| 661 if (!group) | 669 if (!group) | 
| 662 return false; | 670 return false; | 
| 663 var newMenu = this.createMenu(); | 671 var newMenu = this.createMenu(); | 
| 664 var discardOnClose = false; | 672 var discardOnClose = false; | 
| 665 var oldNetworkButtons = this.extractNetworkConnectButtons_(oldMenu); | 673 var oldNetworkButtons = this.extractNetworkConnectButtons_(oldMenu); | 
| 666 var newNetworkButtons = this.extractNetworkConnectButtons_(newMenu); | 674 var newNetworkButtons = this.extractNetworkConnectButtons_(newMenu); | 
| 667 for (var key in oldNetworkButtons) { | 675 for (var key in oldNetworkButtons) { | 
| 668 if (newNetworkButtons[key]) { | 676 if (newNetworkButtons[key]) { | 
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 835 this.autoExpands = true; | 843 this.autoExpands = true; | 
| 836 this.dataModel = new ArrayDataModel([]); | 844 this.dataModel = new ArrayDataModel([]); | 
| 837 this.selectionModel = new ListSingleSelectionModel(); | 845 this.selectionModel = new ListSingleSelectionModel(); | 
| 838 this.addEventListener('blur', this.onBlur_.bind(this)); | 846 this.addEventListener('blur', this.onBlur_.bind(this)); | 
| 839 this.selectionModel.addEventListener('change', | 847 this.selectionModel.addEventListener('change', | 
| 840 this.onSelectionChange_.bind(this)); | 848 this.onSelectionChange_.bind(this)); | 
| 841 | 849 | 
| 842 // Wi-Fi control is always visible. | 850 // Wi-Fi control is always visible. | 
| 843 this.update({key: 'WiFi', networkList: []}); | 851 this.update({key: 'WiFi', networkList: []}); | 
| 844 | 852 | 
| 845 var entryAddWifi = { | 853 this.updateAddConnectionMenuEntries_(); | 
| 846 label: loadTimeData.getString('addConnectionWifi'), | |
| 847 command: createAddConnectionCallback_('WiFi') | |
| 848 }; | |
| 849 var entryAddVPN = { | |
| 850 label: loadTimeData.getString('addConnectionVPN'), | |
| 851 command: createAddConnectionCallback_('VPN') | |
| 852 }; | |
| 853 this.update({key: 'addConnection', | |
| 854 iconType: 'add-connection', | |
| 855 menu: [entryAddWifi, entryAddVPN] | |
| 856 }); | |
| 857 | 854 | 
| 858 var prefs = options.Preferences.getInstance(); | 855 var prefs = options.Preferences.getInstance(); | 
| 859 prefs.addEventListener('cros.signed.data_roaming_enabled', | 856 prefs.addEventListener('cros.signed.data_roaming_enabled', | 
| 860 function(event) { | 857 function(event) { | 
| 861 enableDataRoaming_ = event.value.value; | 858 enableDataRoaming_ = event.value.value; | 
| 862 }); | 859 }); | 
| 863 this.endBatchUpdates(); | 860 this.endBatchUpdates(); | 
| 861 | |
| 862 options.VPNProviders.addObserver(this.onVPNProvidersChanged_.bind(this)); | |
| 864 }, | 863 }, | 
| 865 | 864 | 
| 866 /** | 865 /** | 
| 866 * Called when the list of VPN providers changes. Refreshes the contents of | |
| 867 * menus that list VPN providers. | |
| 868 * @private | |
| 869 */ | |
| 870 onVPNProvidersChanged_() { | |
| 
Dan Beam
2015/03/19 19:01:52
please try your code before you land it
 
bartfab (slow)
2015/03/20 00:10:25
This is valid JavaScript and works just fine. I di
 
Dan Beam
2015/03/20 01:27:58
ah, bummer, my bad (I've just never seen it before
 | |
| 871 // Refresh the contents of the VPN menu. | |
| 872 var index = this.indexOf('VPN'); | |
| 873 if (index != undefined) | |
| 874 this.getListItemByIndex(index).refreshMenu(); | |
| 875 | |
| 876 // Refresh the contents of the "add connection" menu. | |
| 877 this.updateAddConnectionMenuEntries_(); | |
| 878 index = this.indexOf('addConnection'); | |
| 879 if (index != undefined) | |
| 880 this.getListItemByIndex(index).refreshMenu(); | |
| 881 }, | |
| 882 | |
| 883 /** | |
| 884 * Updates the entries in the "add connection" menu, based on the VPN | |
| 885 * providers currently enabled in the primary user's profile. | |
| 886 * @private | |
| 887 */ | |
| 888 updateAddConnectionMenuEntries_() { | |
| 889 var entries = [{ | |
| 890 label: loadTimeData.getString('addConnectionWifi'), | |
| 891 command: createAddNonVPNConnectionCallback_('WiFi') | |
| 892 }]; | |
| 893 entries = entries.concat(createAddVPNConnectionEntries_()); | |
| 894 this.update({key: 'addConnection', | |
| 895 iconType: 'add-connection', | |
| 896 menu: entries | |
| 897 }); | |
| 898 }, | |
| 899 | |
| 900 /** | |
| 867 * When the list loses focus, unselect all items in the list and close the | 901 * When the list loses focus, unselect all items in the list and close the | 
| 868 * active menu. | 902 * active menu. | 
| 869 * @private | 903 * @private | 
| 870 */ | 904 */ | 
| 871 onBlur_: function() { | 905 onBlur_: function() { | 
| 872 this.selectionModel.unselectAll(); | 906 this.selectionModel.unselectAll(); | 
| 873 closeMenu_(); | 907 closeMenu_(); | 
| 874 }, | 908 }, | 
| 875 | 909 | 
| 876 /** | 910 /** | 
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1211 for (var i = 0; i < networkList.length; i++) { | 1245 for (var i = 0; i < networkList.length; i++) { | 
| 1212 var entry = networkList[i]; | 1246 var entry = networkList[i]; | 
| 1213 if (entry.ConnectionState == 'Connected' || | 1247 if (entry.ConnectionState == 'Connected' || | 
| 1214 entry.ConnectionState == 'Connecting') | 1248 entry.ConnectionState == 'Connecting') | 
| 1215 return entry; | 1249 return entry; | 
| 1216 } | 1250 } | 
| 1217 return null; | 1251 return null; | 
| 1218 } | 1252 } | 
| 1219 | 1253 | 
| 1220 /** | 1254 /** | 
| 1221 * Create a callback function that adds a new connection of the given type. | 1255 * Creates a callback function that adds a new connection of the given type. | 
| 1256 * This method may be used for all network types except VPN. | |
| 1222 * @param {string} type An ONC network type | 1257 * @param {string} type An ONC network type | 
| 1223 * @return {function()} The created callback. | 1258 * @return {function()} The created callback. | 
| 1224 * @private | 1259 * @private | 
| 1225 */ | 1260 */ | 
| 1226 function createAddConnectionCallback_(type) { | 1261 function createAddNonVPNConnectionCallback_(type) { | 
| 1227 return function() { | 1262 return function() { | 
| 1228 if (type == 'WiFi') | 1263 if (type == 'WiFi') | 
| 1229 sendChromeMetricsAction('Options_NetworkJoinOtherWifi'); | 1264 sendChromeMetricsAction('Options_NetworkJoinOtherWifi'); | 
| 1230 else if (type == 'VPN') | 1265 chrome.send('addNonVPNConnection', [type]); | 
| 1231 sendChromeMetricsAction('Options_NetworkJoinOtherVPN'); | |
| 1232 chrome.send('addConnection', [type]); | |
| 1233 }; | 1266 }; | 
| 1234 } | 1267 } | 
| 1235 | 1268 | 
| 1236 /** | 1269 /** | 
| 1270 * Creates a callback function that shows the "add network" dialog for the | |
| 1271 * built-in OpenVPN/L2TP VPN provider. | |
| 1272 * @return {function()} The created callback. | |
| 1273 * @private | |
| 1274 */ | |
| 1275 function createVPNConnectionWithAddBuiltInProviderCallback_() { | |
| 
michaelpg
2015/03/19 19:48:28
Could these be simplified into one function? e.g.,
 
bartfab (slow)
2015/03/20 00:10:25
Done.
 
michaelpg
2015/03/20 00:27:28
Thanks!
 | |
| 1276 return function() { | |
| 1277 sendChromeMetricsAction('Options_NetworkAddVPNBuiltIn'); | |
| 1278 chrome.send('addVPNConnection'); | |
| 1279 }; | |
| 1280 } | |
| 1281 | |
| 1282 /** | |
| 1283 * Creates a callback function that asks the third-party VPN provider | |
| 1284 * identified by |extensionID| to show its "add network" dialog. | |
| 1285 * @param {string} providerID The VPN provider's extension ID. | |
| 1286 * @return {function()} The created callback. | |
| 1287 * @private | |
| 1288 */ | |
| 1289 function createAddVPNConnectionWithThirdPartyProviderCallback_(extensionID) { | |
| 1290 return function() { | |
| 1291 sendChromeMetricsAction('Options_NetworkAddVPNThirdParty'); | |
| 1292 chrome.send('addVPNConnection', [extensionID]); | |
| 1293 }; | |
| 1294 } | |
| 1295 | |
| 1296 /** | |
| 1297 * Generates an "add network" entry for each VPN provider currently enabled in | |
| 1298 * the primary user's profile. | |
| 1299 * @return {!Array<{label: string, command: function(), data: !Object}>} The | |
| 1300 * list of entries. | |
| 1301 * @private | |
| 1302 */ | |
| 1303 function createAddVPNConnectionEntries_() { | |
| 1304 var entries = []; | |
| 1305 var providers = options.VPNProviders.getProviders(); | |
| 1306 for (var i = 0; i < providers.length; ++i) { | |
| 1307 entries.push({ | |
| 1308 label: loadTimeData.getStringF('addConnectionVPNTemplate', | |
| 1309 providers[i].name), | |
| 1310 command: providers[i].extensionID ? | |
| 
michaelpg
2015/03/19 19:48:28
Then this would just be createVPNConnectionCallbac
 
bartfab (slow)
2015/03/20 00:10:25
Done.
 | |
| 1311 createAddVPNConnectionWithThirdPartyProviderCallback_( | |
| 1312 providers[i].extensionID) : | |
| 1313 createVPNConnectionWithAddBuiltInProviderCallback_(), | |
| 1314 data: {} | |
| 1315 }); | |
| 1316 } | |
| 1317 return entries; | |
| 1318 } | |
| 1319 | |
| 1320 /** | |
| 1237 * Whether the Network list is disabled. Only used for display purpose. | 1321 * Whether the Network list is disabled. Only used for display purpose. | 
| 1238 */ | 1322 */ | 
| 1239 cr.defineProperty(NetworkList, 'disabled', cr.PropertyKind.BOOL_ATTR); | 1323 cr.defineProperty(NetworkList, 'disabled', cr.PropertyKind.BOOL_ATTR); | 
| 1240 | 1324 | 
| 1241 // Export | 1325 // Export | 
| 1242 return { | 1326 return { | 
| 1243 NetworkList: NetworkList | 1327 NetworkList: NetworkList | 
| 1244 }; | 1328 }; | 
| 1245 }); | 1329 }); | 
| OLD | NEW |