Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / resources / settings / internet_page / internet_detail_page.js
blob46335658fecbd4b6554899a944928cf923188194
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * @fileoverview
7  * 'cr-settings-internet-detail' is the settings subpage containing details
8  * for a network.
9  *
10  * @group Chrome Settings Elements
11  * @element cr-settings-internet-detail
12  */
13 (function() {
14 'use strict';
16 /** @const */ var CARRIER_VERIZON = 'Verizon Wireless';
18 Polymer({
19   is: 'cr-settings-internet-detail-page',
21   properties: {
22     /**
23      * ID of the page.
24      */
25     PAGE_ID: {
26       type: String,
27       value: 'internet-detail',
28       readOnly: true
29     },
31     /**
32      * Route for the page.
33      */
34     route: {
35       type: String,
36       value: ''
37     },
39     /**
40      * Whether the page is a subpage.
41      */
42     subpage: {
43       type: Boolean,
44       value: false
45     },
47     /**
48      * Title for the page header and navigation menu.
49      */
50     pageTitle: {
51       type: String,
52       value: function() {
53         return loadTimeData.getString('internetDetailPageTitle');
54       }
55     },
57     /**
58      * Reflects the selected settings page. We use this to extract guid from
59      * window.location.href when this page is navigated to. This is a
60      * workaround for a bug in the 1.0 version of more-routing where
61      * selected-params='{{params}}' is not correctly setting params in
62      * settings_main.html. TODO(stevenjb): Remove once more-routing is fixed.
63      * @type {?{PAGE_ID: string}}
64      */
65     selectedPage: {
66       type: Object,
67       value: null,
68       observer: 'selectedPageChanged_'
69     },
71     /**
72      * Name of the 'core-icon' to show. TODO(stevenjb): Update this with the
73      * icon for the active internet connection.
74      */
75     icon: {
76       type: String,
77       value: 'settings-ethernet',
78       readOnly: true
79     },
81     /**
82      * The network GUID to display details for.
83      */
84     guid: {
85       type: String,
86       value: '',
87       observer: 'guidChanged_',
88     },
90     /**
91      * The current state for the network matching |guid|. TODO(stevenjb): Use
92      * chrome.networkingProperties.NetworkPoperties once it is defined. This
93      * will be a super-set of NetworkStateProperties. Currently properties that
94      * are not defined in NetworkStateProperties are accessed through
95      * CrOnc.getActive* which uses [] to access the property, which avoids any
96      * type checking (see CrOnc.getProperty for more info).
97      * @type {?CrOnc.NetworkStateProperties}
98      */
99     networkState: {
100       type: Object,
101       value: null,
102       observer: 'networkStateChanged_'
103     },
105     /**
106      * The network AutoConnect state.
107      */
108     autoConnect: {
109       type: Boolean,
110       value: false,
111       observer: 'autoConnectChanged_'
112     },
114     /**
115      * The network preferred state.
116      */
117     preferNetwork: {
118       type: Boolean,
119       value: false,
120       observer: 'preferNetworkChanged_'
121     },
123     /**
124      * The network IP Address.
125      */
126     IPAddress: {
127       type: String,
128       value: ''
129     },
131     /**
132      * Object providing network type values for data binding.
133      * @const
134      */
135     NetworkType: {
136       type: Object,
137       value: {
138         CELLULAR: CrOnc.Type.CELLULAR,
139         ETHERNET: CrOnc.Type.ETHERNET,
140         VPN: CrOnc.Type.VPN,
141         WIFI: CrOnc.Type.WI_FI,
142         WIMAX: CrOnc.Type.WI_MAX,
143       },
144       readOnly: true
145     },
146   },
148   /**
149    * Listener function for chrome.networkingPrivate.onNetworksChanged event.
150    * @type {function(!Array<string>)}
151    * @private
152    */
153   networksChangedListener_: function() {},
155   /** @override */
156   attached: function() {
157     this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this);
158     chrome.networkingPrivate.onNetworksChanged.addListener(
159         this.networksChangedListener_);
160   },
162   /** @override */
163   detached: function() {
164     chrome.networkingPrivate.onNetworksChanged.removeListener(
165         this.networksChangedListener_);
166   },
168   /**
169    * Polymer guid changed method.
170    */
171   guidChanged_: function() {
172     if (!this.guid)
173       return;
174     this.getNetworkDetails_();
175   },
177   /**
178    * Polymer guid changed method. TODO(stevenjb): Remove, see TODO above.
179    */
180   selectedPageChanged_: function() {
181     if ((this.selectedPage && this.selectedPage.PAGE_ID) != this.PAGE_ID)
182       return;
183     var href = window.location.href;
184     var idx = href.lastIndexOf('/');
185     var guid = href.slice(idx + 1);
186     this.guid = guid;
187   },
189   /**
190    * Polymer networkState changed method.
191    */
192   networkStateChanged_: function() {
193     if (!this.networkState)
194       return;
196     // Update autoConnect if it has changed. Default value is false.
197     var autoConnect = /** @type {boolean} */(
198         CrOnc.getActiveTypeValue(this.networkState, 'AutoConnect')) || false;
199     if (autoConnect != this.autoConnect)
200       this.autoConnect = autoConnect;
202     // Update preferNetwork if it has changed. Default value is false.
203     var preferNetwork = this.networkState.Priority > 0;
204     if (preferNetwork != this.preferNetwork)
205       this.preferNetwork = preferNetwork;
207     // Set the IPAddress property to the IPV4 Address.
208     var ipv4 = CrOnc.getIPConfigForType(this.networkState, CrOnc.IPType.IPV4);
209     this.IPAddress = (ipv4 && ipv4.IPAddress) || '';
210   },
212   /**
213    * Polymer autoConnect changed method.
214    */
215   autoConnectChanged_: function() {
216     if (!this.networkState || !this.guid)
217       return;
218     var onc = this.getEmptyNetworkProperties_();
219     CrOnc.setTypeProperty(onc, 'AutoConnect', this.autoConnect);
220     this.setNetworkProperties_(onc);
221   },
223   /**
224    * Polymer preferNetwork changed method.
225    */
226   preferNetworkChanged_: function() {
227     if (!this.networkState || !this.guid)
228       return;
229     var onc = this.getEmptyNetworkProperties_();
230     onc.Priority = this.preferNetwork ? 1 : 0;
231     this.setNetworkProperties_(onc);
232   },
234   /**
235    * networkingPrivate.onNetworksChanged event callback.
236    * @param {!Array<string>} networkIds The list of changed network GUIDs.
237    * @private
238    */
239   onNetworksChangedEvent_: function(networkIds) {
240     if (networkIds.indexOf(this.guid) != -1)
241       this.getNetworkDetails_();
242   },
244   /**
245    * Calls networkingPrivate.getProperties for this.guid.
246    * @private
247    */
248   getNetworkDetails_: function() {
249     if (!this.guid)
250       return;
251     chrome.networkingPrivate.getProperties(
252         this.guid, this.getPropertiesCallback_.bind(this));
253   },
255   /**
256    * networkingPrivate.getProperties callback.
257    * @param {Object} properties The network properties.
258    * @private
259    */
260   getPropertiesCallback_: function(properties) {
261     this.networkState = /** @type {CrOnc.NetworkStateProperties}*/(properties);
262     if (!properties) {
263       // If state becomes null (i.e. the network is no longer visible), close
264       // the page.
265       this.navigateBack_();
266     }
267   },
269   /**
270    * @param {!chrome.networkingPrivate.NetworkConfigProperties} onc The ONC
271    *     network properties.
272    * @private
273    */
274   setNetworkProperties_: function(onc) {
275     if (!this.guid)
276       return;
277     chrome.networkingPrivate.setProperties(this.guid, onc, function() {
278       if (chrome.runtime.lastError) {
279         // An error typically indicates invalid input; request the properties
280         // to update any invalid fields.
281         this.getNetworkDetails_();
282       }
283     }.bind(this));
284   },
286   /**
287    * @return {!chrome.networkingPrivate.NetworkConfigProperties} An ONC
288    *     dictionary with just the Type property set. Used for passing properties
289    *     to setNetworkProperties_.
290    * @private
291    */
292   getEmptyNetworkProperties_: function() {
293     return {Type: this.networkState.Type};
294   },
296   /**
297    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
298    * @return {string} The text to display for the network name.
299    * @private
300    */
301   getStateName_: function(state) {
302     return (state && state.Name) || '';
303   },
305   /**
306    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
307    * @return {string} The text to display for the network connection state.
308    * @private
309    */
310   getStateText_: function(state) {
311     // TODO(stevenjb): Localize.
312     return (state && state.ConnectionState) || '';
313   },
315   /**
316    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
317    * @return {boolean} True if the state is connected.
318    * @private
319    */
320   isConnectedState_: function(state) {
321     return !!state && state.ConnectionState == CrOnc.ConnectionState.CONNECTED;
322   },
324   /**
325    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
326    * @return {boolean} Whether or not to show the 'Connect' button.
327    * @private
328    */
329   showConnect_: function(state) {
330     return !!state && state.Type != CrOnc.Type.ETHERNET &&
331            state.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
332   },
334   /**
335    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
336    * @return {boolean} Whether or not to show the 'Activate' button.
337    * @private
338    */
339   showActivate_: function(state) {
340     if (!state || state.Type != CrOnc.Type.CELLULAR)
341       return false;
342     var activation = state.Cellular.ActivationState;
343     return activation == CrOnc.ActivationState.NOT_ACTIVATED ||
344            activation == CrOnc.ActivationState.PARTIALLY_ACTIVATED;
345   },
347   /**
348    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
349    * @return {boolean} Whether or not to show the 'View Account' button.
350    * @private
351    */
352   showViewAccount_: function(state) {
353     // Show either the 'Activate' or the 'View Account' button.
354     if (this.showActivate_(state))
355       return false;
357     if (!state || state.Type != CrOnc.Type.CELLULAR || !state.Cellular)
358       return false;
360     // Only show if online payment URL is provided or the carrier is Verizon.
361     var carrier = CrOnc.getActiveValue(state, 'Cellular.Carrier');
362     if (carrier != CARRIER_VERIZON) {
363       var paymentPortal = /** @type {CrOnc.PaymentPortal|undefined} */(
364           CrOnc.getActiveValue(state, 'Cellular.PaymentPortal'));
365       if (!paymentPortal || !paymentPortal.Url)
366         return false;
367     }
369     // Only show for connected networks or LTE networks with a valid MDN.
370     if (!this.isConnectedState_(state)) {
371       var technology = /** @type {CrOnc.NetworkTechnology|undefined} */(
372           CrOnc.getActiveValue(state, 'Cellular.NetworkTechnology'));
373       if (technology != CrOnc.NetworkTechnology.LTE &&
374           technology != CrOnc.NetworkTechnology.LTE_ADVANCED) {
375         return false;
376       }
377       if (!CrOnc.getActiveValue(state, 'Cellular.MDN'))
378         return false;
379     }
381     return true;
382   },
384   /**
385    * @return {boolean} Whether or not to enable the network connect button.
386    * @private
387    */
388   enableConnect_: function(state) {
389     if (!state || !this.showConnect_(state))
390       return false;
391     if (state.Type == CrOnc.Type.CELLULAR && CrOnc.isSimLocked(state))
392       return false;
393     // TODO(stevenjb): For VPN, check connected state of any network.
394     return true;
395   },
397   /**
398    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
399    * @return {boolean} Whether or not to show the 'Disconnect' button.
400    * @private
401    */
402   showDisconnect_: function(state) {
403     return !!state && state.Type != CrOnc.Type.ETHERNET &&
404            state.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED;
405   },
407   /**
408    * Callback when the Connect button is clicked.
409    * @private
410    */
411   onConnectClicked_: function() {
412     chrome.networkingPrivate.startConnect(this.guid);
413   },
415   /**
416    * Callback when the Disconnect button is clicked.
417    * @private
418    */
419   onDisconnectClicked_: function() {
420     chrome.networkingPrivate.startDisconnect(this.guid);
421   },
423   /**
424    * Callback when the Activate button is clicked.
425    * @private
426    */
427   onActivateClicked_: function() {
428     chrome.networkingPrivate.startActivate(this.guid);
429   },
431   /**
432    * Callback when the View Account button is clicked.
433    * @private
434    */
435   onViewAccountClicked_: function() {
436     // startActivate() will show the account page for activated networks.
437     chrome.networkingPrivate.startActivate(this.guid);
438   },
440   /**
441    * Event triggered for elements associated with network properties.
442    * @param {!{detail: !{field: string, value: (string|!Object)}}} event
443    * @private
444    */
445   onNetworkPropertyChange_: function(event) {
446     if (!this.networkState)
447       return;
448     var field = event.detail.field;
449     var value = event.detail.value;
450     var onc = this.getEmptyNetworkProperties_();
451     if (field == 'APN') {
452       CrOnc.setTypeProperty(onc, 'APN', value);
453     } else if (field == 'SIMLockStatus') {
454       CrOnc.setTypeProperty(onc, 'SIMLockStatus', value);
455     } else {
456       console.error('Unexpected property change event: ', field);
457       return;
458     }
459     this.setNetworkProperties_(onc);
460   },
462   /**
463    * Event triggered when the IP Config or NameServers element changes.
464    * @param {!{detail: !{field: string,
465    *                     value: (string|!CrOnc.IPConfigProperties|
466    *                             !Array<string>)}}} event
467    *     The network-ip-config or network-nameservers change event.
468    * @private
469    */
470   onIPConfigChange_: function(event) {
471     if (!this.networkState)
472       return;
473     var field = event.detail.field;
474     var value = event.detail.value;
475     // Get an empty ONC dictionary and set just the IP Config properties that
476     // need to change.
477     var onc = this.getEmptyNetworkProperties_();
478     var ipConfigType =
479         /** @type {chrome.networkingPrivate.IPConfigType|undefined} */(
480             CrOnc.getActiveValue(this.networkState, 'IPAddressConfigType'));
481     if (field == 'IPAddressConfigType') {
482       var newIpConfigType =
483           /** @type {chrome.networkingPrivate.IPConfigType} */(value);
484       if (newIpConfigType == ipConfigType)
485         return;
486       onc.IPAddressConfigType = newIpConfigType;
487     } else if (field == 'NameServersConfigType') {
488       var nsConfigType =
489           /** @type {chrome.networkingPrivate.IPConfigType|undefined} */(
490               CrOnc.getActiveValue(this.networkState, 'NameServersConfigType'));
491       var newNsConfigType =
492           /** @type {chrome.networkingPrivate.IPConfigType} */(value);
493       if (newNsConfigType == nsConfigType)
494         return;
495       onc.NameServersConfigType = newNsConfigType;
496     } else if (field == 'StaticIPConfig') {
497       if (ipConfigType == CrOnc.IPConfigType.STATIC) {
498         var staticIpConfig = /** @type {CrOnc.IPConfigProperties|undefined} */(
499             CrOnc.getActiveValue(this.networkState, 'StaticIPConfig'));
500         if (staticIpConfig &&
501             this.allPropertiesMatch_(staticIpConfig,
502                                      /** @type {!Object} */(value))) {
503           return;
504         }
505       }
506       onc.IPAddressConfigType = CrOnc.IPConfigType.STATIC;
507       if (!onc.StaticIPConfig) {
508         onc.StaticIPConfig =
509             /** @type {!chrome.networkingPrivate.IPConfigProperties} */({});
510       }
511       for (let key in value)
512         onc.StaticIPConfig[key] = value[key];
513     } else if (field == 'NameServers') {
514       // If a StaticIPConfig property is specified and its NameServers value
515       // matches the new value, no need to set anything.
516       var nameServers = /** @type {!Array<string>} */(value);
517       if (onc.NameServersConfigType == CrOnc.IPConfigType.STATIC &&
518           onc.StaticIPConfig &&
519           onc.StaticIPConfig.NameServers == nameServers) {
520         return;
521       }
522       onc.NameServersConfigType = CrOnc.IPConfigType.STATIC;
523       if (!onc.StaticIPConfig) {
524         onc.StaticIPConfig =
525             /** @type {!chrome.networkingPrivate.IPConfigProperties} */({});
526       }
527       onc.StaticIPConfig.NameServers = nameServers;
528     } else {
529       console.error('Unexpected change field: ' + field);
530       return;
531     }
532     // setValidStaticIPConfig will fill in any other properties from
533     // networkState. This is necessary since we update IP Address and
534     // NameServers independently.
535     CrOnc.setValidStaticIPConfig(onc, this.networkState);
536     this.setNetworkProperties_(onc);
537   },
539   /**
540    * Event triggered when the Proxy configuration element changes.
541    * @param {!{detail: {field: string, value: !CrOnc.ProxySettings}}} event
542    *     The network-proxy change event.
543    * @private
544    */
545   onProxyChange_: function(event) {
546     if (!this.networkState)
547       return;
548     var field = event.detail.field;
549     var value = event.detail.value;
550     if (field != 'ProxySettings')
551       return;
552     var onc = this.getEmptyNetworkProperties_();
553     CrOnc.setProperty(onc, 'ProxySettings', /** @type {!Object} */(value));
554     this.setNetworkProperties_(onc);
555   },
557   /**
558    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
559    * @return {boolean} True if the shared message should be shown.
560    * @private
561    */
562   showShared_: function(state) {
563     return !!state &&
564            (state.Source == 'Device' || state.Source == 'DevicePolicy');
565   },
567   /**
568    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
569    * @return {boolean} True if the AutoConnect checkbox should be shown.
570    * @private
571    */
572   showAutoConnect_: function(state) {
573     return !!state && state.Type != CrOnc.Type.ETHERNET &&
574            state.Source != CrOnc.Source.NONE;
575   },
577   /**
578    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
579    * @return {boolean} True if the prefer network checkbox should be shown.
580    * @private
581    */
582   showPreferNetwork_: function(state) {
583     // TODO(stevenjb): Resolve whether or not we want to allow "preferred" for
584     // state.Type == CrOnc.Type.ETHERNET.
585     return !!state && state.Source != CrOnc.Source.NONE;
586   },
588   /**
589    * @param {boolean} preferNetwork
590    * @return {string} The icon to use for the preferred button.
591    * @private
592    */
593   getPreferredIcon_: function(preferNetwork) {
594     return preferNetwork ? 'star' : 'star-border';
595   },
597   /**
598    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
599    * @return {!Array<string>} The fields to display in the info section.
600    * @private
601    */
602   getInfoFields_: function(state) {
603     /** @type {!Array<string>} */ var fields = [];
604     if (!state)
605       return fields;
607     if (state.Type == CrOnc.Type.CELLULAR) {
608       fields.push('Cellular.ActivationState',
609                   'Cellular.RoamingState',
610                   'RestrictedConnectivity',
611                   'Cellular.ServingOperator.Name');
612     }
613     if (state.Type == CrOnc.Type.VPN) {
614       fields.push('VPN.Host', 'VPN.Type');
615       if (state.VPN.Type == 'OpenVPN')
616         fields.push('VPN.OpenVPN.Username');
617       else if (state.VPN.Type == 'L2TP-IPsec')
618         fields.push('VPN.L2TP.Username');
619       // TODO(stevenjb): ThirdPartyVPN
620     }
621     if (state.Type == CrOnc.Type.WI_FI)
622       fields.push('RestrictedConnectivity');
623     if (state.Type == CrOnc.Type.WI_MAX) {
624       fields.push('RestrictedConnectivity', 'WiMAX.EAP.Identity');
625     }
626     return fields;
627   },
629   /**
630    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
631    * @return {!Array<string>} The fields to display in the Advanced section.
632    * @private
633    */
634   getAdvancedFields_: function(state) {
635     /** @type {!Array<string>} */ var fields = [];
636     if (!state)
637       return fields;
638     fields.push('MacAddress');
639     if (state.Type == CrOnc.Type.CELLULAR) {
640       fields.push('Cellular.Carrier',
641                   'Cellular.Family',
642                   'Cellular.NetworkTechnology',
643                   'Cellular.ServingOperator.Code');
644     }
645     if (state.Type == CrOnc.Type.WI_FI) {
646       fields.push('WiFi.SSID',
647                   'WiFi.BSSID',
648                   'WiFi.Security',
649                   'WiFi.SignalStrength',
650                   'WiFi.Frequency');
651     }
652     if (state.Type == CrOnc.Type.WI_MAX)
653       fields.push('WiFi.SignalStrength');
654     return fields;
655   },
657   /**
658    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
659    * @return {!Array<string>} The fields to display in the device section.
660    * @private
661    */
662   getDeviceFields_: function(state) {
663     /** @type {!Array<string>} */ var fields = [];
664     if (!state)
665       return fields;
666     if (state.Type == CrOnc.Type.CELLULAR) {
667       fields.push('Cellular.HomeProvider.Name',
668                   'Cellular.HomeProvider.Country',
669                   'Cellular.HomeProvider.Code',
670                   'Cellular.Manufacturer',
671                   'Cellular.ModelID',
672                   'Cellular.FirmwareRevision',
673                   'Cellular.HardwareRevision',
674                   'Cellular.ESN',
675                   'Cellular.ICCID',
676                   'Cellular.IMEI',
677                   'Cellular.IMSI',
678                   'Cellular.MDN',
679                   'Cellular.MEID',
680                   'Cellular.MIN',
681                   'Cellular.PRLVersion');
682     }
683     return fields;
684   },
686   /**
687    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
688    * @return {boolean} True if there are any advanced fields to display.
689    * @private
690    */
691   hasAdvancedOrDeviceFields_: function(state) {
692     return this.getAdvancedFields_(state).length > 0 ||
693            this.hasDeviceFields_(state);
694   },
696   /**
697    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
698    * @return {boolean} True if there are any device fields to display.
699    * @private
700    */
701   hasDeviceFields_: function(state) {
702     var fields = this.getDeviceFields_(state);
703     return fields.length > 0;
704   },
706   /**
707    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
708    * @return {boolean} True if the network section should be shown.
709    * @private
710    */
711   hasNetworkSection_: function(state) {
712     return !!state && state.Type != CrOnc.Type.VPN;
713   },
715   /**
716    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
717    * @param {string} type The network type.
718    * @return {boolean} True if the network type matches 'type'.
719    * @private
720    */
721   isType_: function(state, type) {
722     return !!state && state.Type == type;
723   },
725   /**
726    * @param {?CrOnc.NetworkStateProperties} state The network state properties.
727    * @return {boolean} True if the Cellular SIM section should be shown.
728    * @private
729    */
730   showCellularSim_: function(state) {
731     if (!state || state.Type != 'Cellular')
732       return false;
733     return CrOnc.getActiveValue(state, 'Cellular.Family') == 'GSM';
734   },
736   /**
737    * Navigate to the previous page.
738    * @private
739    */
740   navigateBack_: function() {
741     MoreRouting.navigateTo('internet');
742   },
744   /**
745    * @param {!Object} curValue
746    * @param {!Object} newValue
747    * @return {boolean} True if all properties set in |newValue| are equal to
748    *     the corresponding properties in |curValue|. Note: Not all properties
749    *     of |curValue| need to be specified in |newValue| for this to return
750    *     true.
751    * @private
752    */
753   allPropertiesMatch_: function(curValue, newValue) {
754     for (let key in newValue) {
755       if (newValue[key] != curValue[key])
756         return false;
757     }
758     return true;
759   }
761 })();