blob: 3ef1fd6af5caa69bf8c65160a0d266f9bf658d64 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'settings-internet-detail' is the settings subpage containing details
* for a network.
*/
(function() {
'use strict';
const CARRIER_VERIZON = 'Verizon Wireless';
Polymer({
is: 'settings-internet-detail-page',
behaviors:
[CrPolicyNetworkBehavior, settings.RouteObserverBehavior, I18nBehavior],
properties: {
/** The network GUID to display details for. */
guid: String,
/**
* The current properties for the network matching |guid|.
* @type {!CrOnc.NetworkProperties|undefined}
*/
networkProperties: {
type: Object,
observer: 'networkPropertiesChanged_',
},
/** Preferences state. */
prefs: {
type: Object,
notify: true,
},
/**
* Whether the user is a secondary user.
* @private
*/
isSecondaryUser_: {
type: Boolean,
value: function() {
return loadTimeData.getBoolean('isSecondaryUser');
},
readOnly: true,
},
/**
* Email address for the primary user.
* @private
*/
primaryUserEmail_: {
type: String,
value: function() {
return loadTimeData.getBoolean('isSecondaryUser') ?
loadTimeData.getString('primaryUserEmail') :
'';
},
readOnly: true,
},
/**
* Whether the network has been lost (e.g., has gone out of range). A
* network is considered to be lost when a 'network-list-changed' event
* occurs, and the new network list does not contain the GUID of the current
* network.
* @private
*/
outOfRange_: {
type: Boolean,
value: false,
},
/**
* Highest priority connected network or null.
* @type {?CrOnc.NetworkStateProperties}
*/
defaultNetwork: {
type: Object,
value: null,
},
/** @type {!chrome.networkingPrivate.GlobalPolicy|undefined} */
globalPolicy: {
type: Object,
value: null,
},
/**
* Whether a managed network is available in the visible network list.
* @private {boolean}
*/
managedNetworkAvailable: {
type: Boolean,
value: false,
},
/**
* Interface for networkingPrivate calls, passed from internet_page.
* @type {NetworkingPrivate}
*/
networkingPrivate: Object,
/**
* The network AutoConnect state.
* @private
*/
autoConnect_: {
type: Boolean,
value: false,
observer: 'autoConnectChanged_',
},
/**
* State of the Always-on VPN toggle.
* @private
*/
alwaysOnVpn_: {
type: Boolean,
value: false,
},
/**
* The network preferred state.
* @private
*/
preferNetwork_: {
type: Boolean,
value: false,
observer: 'preferNetworkChanged_',
},
/**
* The network IP Address.
* @private
*/
ipAddress_: {
type: String,
value: '',
},
/** @private */
advancedExpanded_: Boolean,
/** @private */
networkExpanded_: Boolean,
/** @private */
proxyExpanded_: Boolean,
},
observers: [
'onAlwaysOnPrefChanged_(prefs.arc.vpn.always_on.*)',
],
listeners: {
'network-list-changed': 'checkNetworkExists_',
'networks-changed': 'updateNetworkDetails_'
},
/** @private {boolean} */
didSetFocus_: false,
/**
* Set to true to once the initial properties have been received. This
* prevents setProperties from being called when setting default properties.
* @private {boolean}
*/
networkPropertiesReceived_: false,
/**
* Set in currentRouteChanged() if the showConfigure URL query
* parameter is set to true. The dialog cannot be shown until the
* network properties have been fetched in networkPropertiesChanged_().
* @private {boolean}
*/
shouldShowConfigureWhenNetworkLoaded_: false,
/** @private {settings.InternetPageBrowserProxy} */
browserProxy_: null,
/** @override */
created: function() {
this.browserProxy_ = settings.InternetPageBrowserProxyImpl.getInstance();
},
/**
* settings.RouteObserverBehavior
* @param {!settings.Route} route
* @param {!settings.Route} oldRoute
* @protected
*/
currentRouteChanged: function(route, oldRoute) {
if (route != settings.routes.NETWORK_DETAIL) {
return;
}
const queryParams = settings.getQueryParameters();
const guid = queryParams.get('guid') || '';
if (!guid) {
console.error('No guid specified for page:' + route);
this.close_();
}
this.shouldShowConfigureWhenNetworkLoaded_ =
queryParams.get('showConfigure') == 'true';
const type = /** @type {!chrome.networkingPrivate.NetworkType} */ (
queryParams.get('type')) ||
CrOnc.Type.WI_FI;
const name = queryParams.get('name') || type;
this.init(guid, type, name);
},
/**
* @param {string} guid
* @param {!chrome.networkingPrivate.NetworkType} type
* @param {string} name
* @private
*/
init: function(guid, type, name) {
this.guid = guid;
// Set basic networkProperties until they are loaded.
this.networkPropertiesReceived_ = false;
this.networkProperties = {
GUID: this.guid,
Type: type,
ConnectionState: CrOnc.ConnectionState.NOT_CONNECTED,
Name: {Active: name},
};
this.didSetFocus_ = false;
this.getNetworkDetails_();
},
/** @private */
close_: function() {
this.guid = '';
// Delay navigating to allow other subpages to load first.
requestAnimationFrame(() => settings.navigateToPreviousRoute());
},
/** @private */
networkPropertiesChanged_: function() {
if (!this.networkProperties) {
return;
}
// Update autoConnect if it has changed. Default value is false.
const autoConnect = CrOnc.getAutoConnect(this.networkProperties);
if (autoConnect != this.autoConnect_) {
this.autoConnect_ = autoConnect;
}
// Update preferNetwork if it has changed. Default value is false.
const priority = /** @type {number} */ (
CrOnc.getActiveValue(this.networkProperties.Priority) || 0);
const preferNetwork = priority > 0;
if (preferNetwork != this.preferNetwork_) {
this.preferNetwork_ = preferNetwork;
}
// Set the IPAddress property to the IPV4 Address.
const ipv4 =
CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4);
this.ipAddress_ = (ipv4 && ipv4.IPAddress) || '';
// Update the detail page title.
this.parentNode.pageTitle = CrOnc.getNetworkName(this.networkProperties);
Polymer.dom.flush();
if (!this.didSetFocus_) {
// Focus a button once the initial state is set.
this.didSetFocus_ = true;
const button = this.$$('#titleDiv .action-button:not([hidden])') ||
this.$$('#titleDiv paper-button:not([hidden])');
if (button) {
setTimeout(() => button.focus());
}
}
if (this.shouldShowConfigureWhenNetworkLoaded_ &&
this.networkProperties.Tether) {
// Set |this.shouldShowConfigureWhenNetworkLoaded_| back to false to
// ensure that the Tether dialog is only shown once.
this.shouldShowConfigureWhenNetworkLoaded_ = false;
this.showTetherDialog_();
}
},
/** @private */
autoConnectChanged_: function() {
if (!this.networkProperties || !this.guid) {
return;
}
const onc = this.getEmptyNetworkProperties_();
CrOnc.setTypeProperty(onc, 'AutoConnect', this.autoConnect_);
this.setNetworkProperties_(onc);
},
/** @private */
preferNetworkChanged_: function() {
if (!this.networkProperties || !this.guid) {
return;
}
const onc = this.getEmptyNetworkProperties_();
onc.Priority = this.preferNetwork_ ? 1 : 0;
this.setNetworkProperties_(onc);
},
/**
* @param {!CustomEvent<!Array<string>>} event
* @private
*/
checkNetworkExists_: function(event) {
const networkIds = event.detail;
this.outOfRange_ = networkIds.indexOf(this.guid) == -1;
},
/**
* @param {!CustomEvent<!Array<string>>} event
* @private
*/
updateNetworkDetails_: function(event) {
const networkIds = event.detail;
if (networkIds.indexOf(this.guid) != -1) {
this.getNetworkDetails_();
}
},
/**
* Calls networkingPrivate.getProperties for this.guid.
* @private
*/
getNetworkDetails_: function() {
assert(!!this.guid);
if (this.isSecondaryUser_) {
this.networkingPrivate.getState(
this.guid, this.getStateCallback_.bind(this));
} else {
this.networkingPrivate.getManagedProperties(
this.guid, this.getPropertiesCallback_.bind(this));
}
},
/**
* networkingPrivate.getProperties callback.
* @param {!CrOnc.NetworkProperties} properties The network properties.
* @private
*/
getPropertiesCallback_: function(properties) {
if (chrome.runtime.lastError) {
const message = chrome.runtime.lastError.message;
if (message == 'Error.InvalidNetworkGuid') {
console.error('Details page: GUID no longer exists: ' + this.guid);
} else {
console.error(
'Unexpected networkingPrivate.getManagedProperties error: ' +
message + ' For: ' + this.guid);
}
this.close_();
return;
}
// Details page was closed while request was in progress, ignore the result.
if (!this.guid) {
return;
}
if (!properties) {
console.error('No properties for: ' + this.guid);
this.close_();
return;
}
// Detail page should not be shown when Arc VPN is not connected.
if (this.isArcVpn_(properties) && !this.isConnectedState_(properties)) {
this.guid = '';
this.close_();
}
this.networkProperties = properties;
this.networkPropertiesReceived_ = true;
this.outOfRange_ = false;
},
/**
* networkingPrivate.getState callback.
* @param {CrOnc.NetworkStateProperties} state The network state properties.
* @private
*/
getStateCallback_: function(state) {
if (!state) {
// If |state| is null, the network is no longer visible, close this.
console.error('Network no longer exists: ' + this.guid);
this.networkProperties = undefined;
this.close_();
}
this.networkProperties = {
GUID: state.GUID,
Type: state.Type,
Connectable: state.Connectable,
ConnectionState: state.ConnectionState,
};
this.networkPropertiesReceived_ = true;
this.outOfRange_ = false;
},
/**
* @param {!chrome.networkingPrivate.NetworkConfigProperties} onc The ONC
* network properties.
* @private
*/
setNetworkProperties_: function(onc) {
if (!this.networkPropertiesReceived_) {
return;
}
assert(!!this.guid);
this.networkingPrivate.setProperties(this.guid, onc, () => {
if (chrome.runtime.lastError) {
// An error typically indicates invalid input; request the properties
// to update any invalid fields.
this.getNetworkDetails_();
}
});
},
/**
* @return {!chrome.networkingPrivate.NetworkConfigProperties} An ONC
* dictionary with just the Type property set. Used for passing properties
* to setNetworkProperties_.
* @private
*/
getEmptyNetworkProperties_: function() {
const type =
this.networkProperties ? this.networkProperties.Type : CrOnc.Type.WI_FI;
return {Type: type};
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {boolean} outOfRange
* @return {string} The text to display for the network connection state.
* @private
*/
getStateText_: function(networkProperties, outOfRange) {
if (networkProperties === undefined || !networkProperties.ConnectionState) {
return '';
}
if (outOfRange) {
return networkProperties.Type == CrOnc.Type.TETHER ?
this.i18n('tetherPhoneOutOfRange') :
this.i18n('networkOutOfRange');
}
return this.i18n('Onc' + networkProperties.ConnectionState);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean} True if the network is connected.
* @private
*/
isConnectedState_: function(networkProperties) {
return networkProperties.ConnectionState == CrOnc.ConnectionState.CONNECTED;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
isRemembered_: function(networkProperties) {
const source = networkProperties ? networkProperties.Source : null;
return !!source && source != CrOnc.Source.NONE;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
isRememberedOrConnected_: function(networkProperties) {
return this.isRemembered_(networkProperties) ||
this.isConnectedState_(networkProperties);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
isCellular_: function(networkProperties) {
return networkProperties !== undefined &&
networkProperties.Type == CrOnc.Type.CELLULAR &&
!!networkProperties.Cellular;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean}
* @private
*/
isBlockedByPolicy_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
if (networkProperties === undefined ||
networkProperties.Type != CrOnc.Type.WI_FI ||
this.isPolicySource(networkProperties.Source) || !globalPolicy) {
return false;
}
return !!globalPolicy.AllowOnlyPolicyNetworksToConnect ||
(!!globalPolicy.AllowOnlyPolicyNetworksToConnectIfAvailable &&
!!managedNetworkAvailable) ||
(!!networkProperties.WiFi && !!networkProperties.WiFi.HexSSID &&
!!globalPolicy.BlacklistedHexSSIDs &&
globalPolicy.BlacklistedHexSSIDs.includes(
CrOnc.getStateOrActiveString(networkProperties.WiFi.HexSSID)));
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean}
* @private
*/
showConnect_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
if (networkProperties === undefined) {
return false;
}
if (this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable)) {
return false;
}
// TODO(lgcheng@) support connect Arc VPN from UI once Android support API
// to initiate a VPN session.
if (this.isArcVpn_(networkProperties)) {
return false;
}
return networkProperties.Type != CrOnc.Type.ETHERNET &&
networkProperties.ConnectionState ==
CrOnc.ConnectionState.NOT_CONNECTED;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showDisconnect_: function(networkProperties) {
return networkProperties !== undefined &&
networkProperties.Type != CrOnc.Type.ETHERNET &&
networkProperties.ConnectionState !=
CrOnc.ConnectionState.NOT_CONNECTED;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showForget_: function(networkProperties) {
if (this.isSecondaryUser_ || networkProperties === undefined) {
return false;
}
const type = networkProperties.Type;
if (type != CrOnc.Type.WI_FI && type != CrOnc.Type.VPN) {
return false;
}
if (this.isArcVpn_(networkProperties)) {
return false;
}
return !this.isPolicySource(networkProperties.Source) &&
this.isRemembered_(networkProperties);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showActivate_: function(networkProperties) {
if (this.isSecondaryUser_) {
return false;
}
if (!this.isCellular_(networkProperties)) {
return false;
}
const activation = networkProperties.Cellular.ActivationState;
return activation == CrOnc.ActivationState.NOT_ACTIVATED ||
activation == CrOnc.ActivationState.PARTIALLY_ACTIVATED;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean}
* @private
*/
showConfigure_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
if (this.isSecondaryUser_ || networkProperties === undefined) {
return false;
}
if (this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable)) {
return false;
}
const type = networkProperties.Type;
if (type == CrOnc.Type.CELLULAR || type == CrOnc.Type.TETHER) {
return false;
}
if (type == CrOnc.Type.WI_FI) {
const security = networkProperties.WiFi &&
CrOnc.getActiveValue(networkProperties.WiFi.Security);
if (!security || security == CrOnc.Security.NONE) {
return false;
}
}
if ((type == CrOnc.Type.WI_FI || type == CrOnc.Type.WI_MAX) &&
networkProperties.ConnectionState !=
CrOnc.ConnectionState.NOT_CONNECTED) {
return false;
}
if (this.isArcVpn_(networkProperties) &&
!this.isConnectedState_(networkProperties)) {
return false;
}
return true;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.settingsPrivate.PrefObject} vpn_config_allowed
* @return {boolean}
* @private
*/
disableForget_: function(networkProperties, vpn_config_allowed) {
return this.isVpn_(networkProperties) && vpn_config_allowed &&
!vpn_config_allowed.value;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.settingsPrivate.PrefObject} vpn_config_allowed
* @return {boolean}
* @private
*/
disableConfigure_: function(networkProperties, vpn_config_allowed) {
if (this.isVpn_(networkProperties) && vpn_config_allowed &&
!vpn_config_allowed.value) {
return true;
}
return this.isPolicySource(networkProperties.Source) &&
!this.hasRecommendedFields_(networkProperties);
},
/**
* @param {!Object} networkProperties
* @return {boolean}
*/
hasRecommendedFields_: function(networkProperties) {
for (const property in networkProperties) {
const propertyValue = networkProperties[property];
if (this.isNetworkPolicyRecommended(propertyValue) ||
(typeof propertyValue == 'object' &&
this.hasRecommendedFields_(propertyValue))) {
return true;
}
}
return false;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showViewAccount_: function(networkProperties) {
if (this.isSecondaryUser_) {
return false;
}
// Show either the 'Activate' or the 'View Account' button (Cellular only).
if (!this.isCellular_(networkProperties) ||
this.showActivate_(networkProperties)) {
return false;
}
// Only show if online payment URL is provided or the carrier is Verizon.
const carrier = CrOnc.getActiveValue(networkProperties.Cellular.Carrier);
if (carrier != CARRIER_VERIZON) {
const paymentPortal = networkProperties.Cellular.PaymentPortal;
if (!paymentPortal || !paymentPortal.Url) {
return false;
}
}
// Only show for connected networks or LTE networks with a valid MDN.
if (!this.isConnectedState_(networkProperties)) {
const technology = networkProperties.Cellular.NetworkTechnology;
if (technology != CrOnc.NetworkTechnology.LTE &&
technology != CrOnc.NetworkTechnology.LTE_ADVANCED) {
return false;
}
if (!networkProperties.Cellular.MDN) {
return false;
}
}
return true;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {?CrOnc.NetworkStateProperties} defaultNetwork
* @param {boolean} networkPropertiesReceived
* @param {boolean} outOfRange
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean} Whether or not to enable the network connect button.
* @private
*/
enableConnect_: function(
networkProperties, defaultNetwork, networkPropertiesReceived, outOfRange,
globalPolicy, managedNetworkAvailable) {
if (!this.showConnect_(
networkProperties, globalPolicy, managedNetworkAvailable)) {
return false;
}
if (!networkPropertiesReceived || outOfRange) {
return false;
}
if (this.isSecondaryUser_ && this.networkProperties.Connectable === false) {
return false;
}
if ((networkProperties.Type == CrOnc.Type.CELLULAR) &&
(CrOnc.isSimLocked(networkProperties) ||
this.get('Cellular.Scanning', networkProperties))) {
return false;
}
if (networkProperties.Type == CrOnc.Type.VPN && !defaultNetwork) {
return false;
}
return true;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean} Whether or not we are looking at VPN configuration.
* @private
*/
isVpn_: function(networkProperties) {
return networkProperties.Type == CrOnc.Type.VPN;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.settingsPrivate.PrefObject} prefButtonAllowed
* @return {Object} Fake pref that is enforced
* whenever the original pref is true
* @private
*/
getVpnConfigPrefFromValue_: function(networkProperties, prefButtonAllowed) {
if (!this.isVpn_(networkProperties) || !prefButtonAllowed) {
return null;
}
const fakePref = Object.assign({}, prefButtonAllowed);
if (prefButtonAllowed.value) {
delete fakePref.enforcement;
delete fakePref.controlledBy;
} else {
fakePref.enforcement = chrome.settingsPrivate.Enforcement.ENFORCED;
}
return fakePref;
},
/**
* @return {!TetherConnectionDialogElement}
* @private
*/
getTetherDialog_: function() {
return /** @type {!TetherConnectionDialogElement} */ (this.$.tetherDialog);
},
/** @private */
onConnectTap_: function() {
if (CrOnc.shouldShowTetherDialogBeforeConnection(this.networkProperties)) {
this.showTetherDialog_();
return;
}
this.fire('network-connect', {networkProperties: this.networkProperties});
},
/** @private */
onTetherConnect_: function() {
this.getTetherDialog_().close();
this.fire('network-connect', {
networkProperties: this.networkProperties,
bypassConnectionDialog: true
});
},
/** @private */
onDisconnectTap_: function() {
this.networkingPrivate.startDisconnect(this.guid);
},
/** @private */
onForgetTap_: function() {
this.networkingPrivate.forgetNetwork(this.guid);
// A forgotten network no longer has a valid GUID, close the subpage.
this.close_();
},
/** @private */
onActivateTap_: function() {
this.networkingPrivate.startActivate(this.guid);
},
/** @private */
onConfigureTap_: function() {
if (this.networkProperties &&
(this.isThirdPartyVpn_(this.networkProperties) ||
this.isArcVpn_(this.networkProperties))) {
this.browserProxy_.configureThirdPartyVpn(this.guid);
return;
}
this.fire('show-config', this.networkProperties);
},
/** @private */
onViewAccountTap_: function() {
// startActivate() will show the account page for activated networks.
this.networkingPrivate.startActivate(this.guid);
},
/** @type {string} */
CR_EXPAND_BUTTON_TAG: 'CR-EXPAND-BUTTON',
/** @private */
showTetherDialog_: function() {
this.getTetherDialog_().open();
},
/**
* Event triggered for elements associated with network properties.
* @param {!CustomEvent<!{
* field: string,
* value: !CrOnc.NetworkPropertyType
* }>} e
* @private
*/
onNetworkPropertyChange_: function(e) {
if (!this.networkProperties) {
return;
}
const field = e.detail.field;
const value = e.detail.value;
const onc = this.getEmptyNetworkProperties_();
if (field == 'APN') {
CrOnc.setTypeProperty(onc, 'APN', value);
} else if (field == 'SIMLockStatus') {
CrOnc.setTypeProperty(onc, 'SIMLockStatus', value);
} else {
const valueType = typeof value;
if (valueType == 'string' || valueType == 'number' ||
valueType == 'boolean' || Array.isArray(value)) {
CrOnc.setProperty(onc, field, value);
// Ensure any required configuration properties are also set.
if (field.match(/^VPN/)) {
const vpnType = CrOnc.getActiveValue(this.networkProperties.VPN.Type);
assert(vpnType);
CrOnc.setProperty(onc, 'VPN.Type', vpnType);
}
} else {
console.error(
'Unexpected property change event, Key: ' + field +
' Value: ' + JSON.stringify(value));
return;
}
}
this.setNetworkProperties_(onc);
},
/**
* Event triggered when the IP Config or NameServers element changes.
* @param {!CustomEvent<!{
* field: string,
* value: (string|!CrOnc.IPConfigProperties| !Array<string>)
* }>} event The network-ip-config or network-nameservers change event.
* @private
*/
onIPConfigChange_: function(event) {
if (!this.networkProperties) {
return;
}
const field = event.detail.field;
const value = event.detail.value;
// Get an empty ONC dictionary and set just the IP Config properties that
// need to change.
const onc = this.getEmptyNetworkProperties_();
const ipConfigType =
/** @type {chrome.networkingPrivate.IPConfigType|undefined} */ (
CrOnc.getActiveValue(this.networkProperties.IPAddressConfigType));
if (field == 'IPAddressConfigType') {
const newIpConfigType =
/** @type {chrome.networkingPrivate.IPConfigType} */ (value);
if (newIpConfigType == ipConfigType) {
return;
}
onc.IPAddressConfigType = newIpConfigType;
} else if (field == 'NameServersConfigType') {
const nsConfigType =
/** @type {chrome.networkingPrivate.IPConfigType|undefined} */ (
CrOnc.getActiveValue(
this.networkProperties.NameServersConfigType));
const newNsConfigType =
/** @type {chrome.networkingPrivate.IPConfigType} */ (value);
if (newNsConfigType == nsConfigType) {
return;
}
onc.NameServersConfigType = newNsConfigType;
} else if (field == 'StaticIPConfig') {
if (ipConfigType == CrOnc.IPConfigType.STATIC) {
const staticIpConfig = this.networkProperties.StaticIPConfig;
const ipConfigValue = /** @type {!Object} */ (value);
if (staticIpConfig &&
this.allPropertiesMatch_(staticIpConfig, ipConfigValue)) {
return;
}
}
onc.IPAddressConfigType = CrOnc.IPConfigType.STATIC;
if (!onc.StaticIPConfig) {
onc.StaticIPConfig =
/** @type {!chrome.networkingPrivate.IPConfigProperties} */ ({});
}
// Only copy Static IP properties.
const keysToCopy = ['Type', 'IPAddress', 'RoutingPrefix', 'Gateway'];
for (let i = 0; i < keysToCopy.length; ++i) {
const key = keysToCopy[i];
if (key in value) {
onc.StaticIPConfig[key] = value[key];
}
}
} else if (field == 'NameServers') {
// If a StaticIPConfig property is specified and its NameServers value
// matches the new value, no need to set anything.
const nameServers = /** @type {!Array<string>} */ (value);
if (onc.NameServersConfigType == CrOnc.IPConfigType.STATIC &&
onc.StaticIPConfig && onc.StaticIPConfig.NameServers == nameServers) {
return;
}
onc.NameServersConfigType = CrOnc.IPConfigType.STATIC;
if (!onc.StaticIPConfig) {
onc.StaticIPConfig =
/** @type {!chrome.networkingPrivate.IPConfigProperties} */ ({});
}
onc.StaticIPConfig.NameServers = nameServers;
} else {
console.error('Unexpected change field: ' + field);
return;
}
// setValidStaticIPConfig will fill in any other properties from
// networkProperties. This is necessary since we update IP Address and
// NameServers independently.
CrOnc.setValidStaticIPConfig(onc, this.networkProperties);
this.setNetworkProperties_(onc);
},
/**
* Event triggered when the Proxy configuration element changes.
* @param {!CustomEvent<!{field: string, value: !CrOnc.ProxySettings}>} event
* The network-proxy change event.
* @private
*/
onProxyChange_: function(event) {
if (!this.networkProperties) {
return;
}
const field = event.detail.field;
const value = event.detail.value;
if (field != 'ProxySettings') {
return;
}
const onc = this.getEmptyNetworkProperties_();
CrOnc.setProperty(onc, 'ProxySettings', /** @type {!Object} */ (value));
this.setNetworkProperties_(onc);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean} True if the shared message should be shown.
* @private
*/
showShared_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
return networkProperties !== undefined &&
(networkProperties.Source == 'Device' ||
networkProperties.Source == 'DevicePolicy') &&
!this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean} True if the AutoConnect checkbox should be shown.
* @private
*/
showAutoConnect_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
return networkProperties !== undefined &&
networkProperties.Type != CrOnc.Type.ETHERNET &&
this.isRemembered_(networkProperties) &&
!this.isArcVpn_(networkProperties) &&
!this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @return {boolean}
* @private
*/
isAutoConnectEnforcedByPolicy: function(networkProperties, globalPolicy) {
if (networkProperties === undefined ||
networkProperties.Type != CrOnc.Type.WI_FI) {
return false;
}
if (this.isPolicySource(networkProperties.Source)) {
return !this.isEditable(CrOnc.getManagedAutoConnect(networkProperties));
}
return globalPolicy && !!globalPolicy.AllowOnlyPolicyNetworksToAutoconnect;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean} Whether the toggle for the Always-on VPN feature is
* displayed.
* @private
*/
showAlwaysOnVpn_: function(networkProperties) {
return this.isArcVpn_(networkProperties) && this.prefs.arc &&
this.prefs.arc.vpn && this.prefs.arc.vpn.always_on &&
this.prefs.arc.vpn.always_on.vpn_package &&
networkProperties.VPN.Host.Active ===
this.prefs.arc.vpn.always_on.vpn_package.value;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.settingsPrivate.PrefObject} vpnConfigAllowed
* @return {boolean} Whether the toggle for the Always-on VPN feature is
* enabled.
* @private
*/
enableAlwaysOnVpn_: function(networkProperties, vpnConfigAllowed) {
return this.isArcVpn_(networkProperties) && vpnConfigAllowed &&
!!vpnConfigAllowed.value;
},
/** @private */
onAlwaysOnPrefChanged_: function() {
if (this.prefs.arc && this.prefs.arc.vpn && this.prefs.arc.vpn.always_on &&
this.prefs.arc.vpn.always_on.lockdown) {
this.alwaysOnVpn_ = this.prefs.arc.vpn.always_on.lockdown.value;
}
},
/** @private */
onAlwaysOnVpnChange_: function() {
if (this.prefs.arc && this.prefs.arc.vpn && this.prefs.arc.vpn.always_on &&
this.prefs.arc.vpn.always_on.lockdown) {
this.set('prefs.arc.vpn.always_on.lockdown.value', this.alwaysOnVpn_);
}
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean} True if the prefer network checkbox should be shown.
* @private
*/
showPreferNetwork_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
if (!networkProperties) {
return false;
}
const type = networkProperties.Type;
if (type == CrOnc.Type.ETHERNET || type == CrOnc.Type.CELLULAR ||
this.isArcVpn_(networkProperties)) {
return false;
}
return this.isRemembered_(networkProperties) &&
!this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable);
},
/**
* @param {!Array<string>} fields
* @return {boolean}
* @private
*/
hasVisibleFields_: function(fields) {
for (let i = 0; i < fields.length; ++i) {
const value = this.get(fields[i], this.networkProperties);
if (value !== undefined && value !== '') {
return true;
}
}
return false;
},
/**
* @return {boolean}
* @private
*/
hasInfoFields_: function() {
return this.getInfoEditFieldTypes_().length > 0 ||
this.hasVisibleFields_(this.getInfoFields_());
},
/**
* @return {!Array<string>} The fields to display in the info section.
* @private
*/
getInfoFields_: function() {
if (this.networkProperties === undefined) {
return [];
}
/** @type {!Array<string>} */ const fields = [];
const type = this.networkProperties.Type;
if (type == CrOnc.Type.CELLULAR && !!this.networkProperties.Cellular) {
fields.push(
'Cellular.ActivationState', 'Cellular.RoamingState',
'RestrictedConnectivity', 'Cellular.ServingOperator.Name');
} else if (type == CrOnc.Type.TETHER && !!this.networkProperties.Tether) {
fields.push(
'Tether.BatteryPercentage', 'Tether.SignalStrength',
'Tether.Carrier');
} else if (type == CrOnc.Type.VPN && !!this.networkProperties.VPN) {
const vpnType = CrOnc.getActiveValue(this.networkProperties.VPN.Type);
switch (vpnType) {
case CrOnc.VPNType.THIRD_PARTY_VPN:
fields.push('VPN.ThirdPartyVPN.ProviderName');
break;
case CrOnc.VPNType.ARCVPN:
fields.push('VPN.Type');
break;
case CrOnc.VPNType.OPEN_VPN:
fields.push(
'VPN.Type', 'VPN.Host', 'VPN.OpenVPN.Username',
'VPN.OpenVPN.ExtraHosts');
break;
case CrOnc.VPNType.L2TP_IPSEC:
fields.push('VPN.Type', 'VPN.Host', 'VPN.L2TP.Username');
break;
}
} else if (type == CrOnc.Type.WI_FI) {
fields.push('RestrictedConnectivity');
} else if (type == CrOnc.Type.WI_MAX) {
fields.push('RestrictedConnectivity', 'WiMAX.EAP.Identity');
}
return fields;
},
/**
* @return {!Object} A dictionary of editable fields in the info section.
* @private
*/
getInfoEditFieldTypes_: function() {
if (this.networkProperties === undefined) {
return [];
}
/** @dict */ const editFields = {};
const type = this.networkProperties.Type;
if (type == CrOnc.Type.VPN && !!this.networkProperties.VPN) {
const vpnType = CrOnc.getActiveValue(this.networkProperties.VPN.Type);
if (vpnType != CrOnc.VPNType.THIRD_PARTY_VPN) {
editFields['VPN.Host'] = 'String';
}
if (vpnType == CrOnc.VPNType.OPEN_VPN) {
editFields['VPN.OpenVPN.Username'] = 'String';
editFields['VPN.OpenVPN.ExtraHosts'] = 'StringArray';
}
}
return editFields;
},
/**
* @return {!Array<string>} The fields to display in the Advanced section.
* @private
*/
getAdvancedFields_: function() {
if (this.networkProperties === undefined) {
return [];
}
/** @type {!Array<string>} */ const fields = [];
const type = this.networkProperties.Type;
if (type != CrOnc.Type.TETHER) {
fields.push('MacAddress');
}
if (type == CrOnc.Type.CELLULAR && !!this.networkProperties.Cellular) {
fields.push(
'Cellular.Carrier', 'Cellular.Family', 'Cellular.NetworkTechnology',
'Cellular.ServingOperator.Code');
} else if (type == CrOnc.Type.WI_FI) {
fields.push(
'WiFi.SSID', 'WiFi.BSSID', 'WiFi.SignalStrength', 'WiFi.Security',
'WiFi.EAP.Outer', 'WiFi.EAP.Inner', 'WiFi.EAP.SubjectMatch',
'WiFi.EAP.Identity', 'WiFi.EAP.AnonymousIdentity', 'WiFi.Frequency');
} else if (type == CrOnc.Type.WI_MAX) {
fields.push('WiFi.SignalStrength');
}
return fields;
},
/**
* @return {!Array<string>} The fields to display in the device section.
* @private
*/
getDeviceFields_: function() {
if (this.networkProperties === undefined ||
this.networkProperties.Type !== CrOnc.Type.CELLULAR) {
return [];
}
return [
'Cellular.HomeProvider.Name', 'Cellular.HomeProvider.Country',
'Cellular.HomeProvider.Code', 'Cellular.Manufacturer', 'Cellular.ModelID',
'Cellular.FirmwareRevision', 'Cellular.HardwareRevision', 'Cellular.ESN',
'Cellular.ICCID', 'Cellular.IMEI', 'Cellular.IMSI', 'Cellular.MDN',
'Cellular.MEID', 'Cellular.MIN', 'Cellular.PRLVersion'
];
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showAdvanced_: function(networkProperties) {
if (networkProperties === undefined ||
networkProperties.Type == CrOnc.Type.TETHER) {
// These settings apply to the underlying WiFi network, not the Tether
// network.
return false;
}
return this.hasAdvancedFields_() || this.hasDeviceFields_() ||
(networkProperties.Type != CrOnc.Type.VPN &&
this.isRememberedOrConnected_(networkProperties));
},
/**
* @return {boolean}
* @private
*/
hasAdvancedFields_: function() {
return this.hasVisibleFields_(this.getAdvancedFields_());
},
/**
* @return {boolean}
* @private
*/
hasDeviceFields_: function() {
return this.hasVisibleFields_(this.getDeviceFields_());
},
/**
* @return {boolean}
* @private
*/
hasAdvancedOrDeviceFields_: function() {
return this.hasAdvancedFields_() || this.hasDeviceFields_();
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean}
* @private
*/
hasNetworkSection_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
if (networkProperties === undefined ||
networkProperties.Type == CrOnc.Type.TETHER) {
// These settings apply to the underlying WiFi network, not the Tether
// network.
return false;
}
if (this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable)) {
return false;
}
if (networkProperties.Type == CrOnc.Type.CELLULAR) {
return true;
}
return this.isRememberedOrConnected_(networkProperties);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
* @param {boolean} managedNetworkAvailable
* @return {boolean}
* @private
*/
hasProxySection_: function(
networkProperties, globalPolicy, managedNetworkAvailable) {
if (networkProperties === undefined ||
networkProperties.Type == CrOnc.Type.TETHER) {
// Proxy settings apply to the underlying WiFi network, not the Tether
// network.
return false;
}
if (this.isBlockedByPolicy_(
networkProperties, globalPolicy, managedNetworkAvailable)) {
return false;
}
return this.isRememberedOrConnected_(networkProperties);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showCellularChooseNetwork_: function(networkProperties) {
return networkProperties !== undefined &&
networkProperties.Type == CrOnc.Type.CELLULAR &&
!!this.get('Cellular.SupportNetworkScan', this.networkProperties);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showScanningSpinner_: function(networkProperties) {
return !!this.get('Cellular.Scanning', networkProperties);
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showCellularSim_: function(networkProperties) {
return networkProperties !== undefined &&
networkProperties.Type == CrOnc.Type.CELLULAR &&
!!networkProperties.Cellular &&
networkProperties.Cellular.Family != 'CDMA';
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
isArcVpn_: function(networkProperties) {
return networkProperties !== undefined && !!networkProperties.VPN &&
CrOnc.getActiveValue(networkProperties.VPN.Type) ==
CrOnc.VPNType.ARCVPN;
},
/**
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
isThirdPartyVpn_: function(networkProperties) {
return networkProperties !== undefined && !!networkProperties.VPN &&
CrOnc.getActiveValue(networkProperties.VPN.Type) ==
CrOnc.VPNType.THIRD_PARTY_VPN;
},
/**
* @param {string} ipAddress
* @param {!CrOnc.NetworkProperties} networkProperties
* @return {boolean}
* @private
*/
showIpAddress_: function(ipAddress, networkProperties) {
// Arc Vpn does not currently pass IP configuration to ChromeOS. IP address
// property holds an internal IP address Android uses to talk to ChromeOS.
// TODO(lgcheng@) Show correct IP address when we implement IP configuration
// correctly.
if (this.isArcVpn_(networkProperties)) {
return false;
}
return !!ipAddress && this.isConnectedState_(networkProperties);
},
/**
* @param {!Object} curValue
* @param {!Object} newValue
* @return {boolean} True if all properties set in |newValue| are equal to
* the corresponding properties in |curValue|. Note: Not all properties
* of |curValue| need to be specified in |newValue| for this to return
* true.
* @private
*/
allPropertiesMatch_: function(curValue, newValue) {
for (const key in newValue) {
if (newValue[key] != curValue[key]) {
return false;
}
}
return true;
},
});
})();