// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'network-config' provides configuration of authentication properties for new
* and existing networks.
*/
import '//resources/ash/common/cr_elements/action_link.css.js';
import '//resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
import '//resources/ash/common/cr_elements/cr_toggle/cr_toggle.js';
import '//resources/ash/common/cr_elements/policy/cr_policy_indicator.js';
import '//resources/js/action_link.js';
import '//resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
import '//resources/polymer/v3_0/iron-icon/iron-icon.js';
import '//resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
import './network_config_input.js';
import './network_config_select.js';
import './network_config_toggle.js';
import './network_password_input.js';
import './network_shared.css.js';
import {assert, assertNotReached} from '//resources/ash/common/assert.js';
import {I18nBehavior} from '//resources/ash/common/i18n_behavior.js';
import {loadTimeData} from '//resources/ash/common/load_time_data.m.js';
import {CertificateType, ConfigProperties, CrosNetworkConfigInterface, EAPConfigProperties, GlobalPolicy, HiddenSsidMode, IPSecConfigProperties, L2TPConfigProperties, ManagedBoolean, ManagedEAPProperties, ManagedInt32, ManagedIPSecProperties, ManagedL2TPProperties, ManagedOpenVPNProperties, ManagedProperties, ManagedString, ManagedStringList, ManagedWireGuardProperties, NetworkCertificate, OpenVPNConfigProperties, SecurityType, StartConnectResult, SubjectAltName, VpnType, WireGuardConfigProperties} from '//resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ConnectionStateType, IPConfigType, NetworkType, OncSource, PolicySource} from '//resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {flush, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {MojoInterfaceProvider, MojoInterfaceProviderImpl} from './mojo_interface_provider.js';
import {getTemplate} from './network_config.html.js';
import {NetworkListenerBehavior} from './network_listener_behavior.js';
import {OncMojo} from './onc_mojo.js';
/**
* Note: closure does not always recognize this if inside function() {}.
* @enum {string}
*/
const VPNConfigType = {
IKEV2: 'IKEv2',
L2TP_IPSEC: 'L2TP_IPsec',
OPEN_VPN: 'OpenVPN',
WIREGUARD: 'WireGuard',
};
/**
* Authentication types for IPsec-based VPNs.
* @enum {string}
*/
const IpsecAuthType = {
PSK: 'PSK',
CERT: 'Cert',
EAP: 'EAP',
};
/**
* Method to configure WireGuard local key pair.
* @enum {string}
*/
const WireGuardKeyConfigType = {
USE_CURRENT: 'UseCurrent',
GENERATE_NEW: 'GenerateNew',
USER_INPUT: 'UserInput',
};
/** @type {string} */ const DEFAULT_HASH = 'default';
/** @type {string} */ const DO_NOT_CHECK_HASH = 'do-not-check';
/** @type {string} */ const NO_CERTS_HASH = 'no-certs';
/** @type {string} */ const NO_USER_CERT_HASH = 'no-user-cert';
/** @type {string} */ const DEFAULT_EAP_OUTER_PROTOCOL = 'PEAP';
/** @type {string} */ const PLACEHOLDER_CREDENTIAL = '(credential)';
/**
* A light-weight regular expression for testing an IPv4 address string. Note
* that this is not a complete check and thus some invalid input can also be
* accepted.
* @type {RegExp}
* @private
*/
const IPV4_ADDR_REGEX = /^([0-9]+\.){3}[0-9]+$/i;
/**
* A light-weight regular expression for testing an IPv6 address string. Note
* that this is not a complete check and thus some invalid input can also be
* accepted.
* @type {RegExp}
* @private
*/
const IPV6_ADDR_REGEX = /^(\:?[0-9a-f]{0,4}){2,8}$/i;
/**
* A light-weight regular expression for testing an IP CIDR string (e.g.,
* 192.168.1.0/24). Both IPv4 and IPv6 are accepted. Note that this is not a
* complete check and thus some invalid input can also be accepted.
* @type {RegExp}
* @private
*/
const IP_CIDR_REGEX = /^[0-9a-f\.\:]+\/[0-9]+?$/i;
Polymer({
_template: getTemplate(),
is: 'network-config',
behaviors: [
NetworkListenerBehavior,
I18nBehavior,
],
properties: {
/** @type {!GlobalPolicy|undefined} */
globalPolicy_: Object,
/**
* The GUID when an existing network is being configured. This will be
* empty when configuring a new network.
*/
guid: String,
/** The type of network being configured as a string. */
type: String,
/**
* The type of network being configured as an enum.
* @private {NetworkType|undefined}
*/
mojoType_: Number,
/** True if the user configuring the network can toggle the shared state. */
shareAllowEnable: Boolean,
/** The default shared state. */
shareDefault: Boolean,
enableConnect: {
type: Boolean,
notify: true,
value: false,
},
enableSave: {
type: Boolean,
notify: true,
value: false,
},
/**
* Whether pressing the "Enter" key within the password field should start a
* connection attempt. If this field is false, pressing "Enter" saves the
* current configuration but does not connect.
*/
connectOnEnter: {
type: Boolean,
value: false,
},
/** Set to any error from the last configuration result. */
error: {
type: String,
notify: true,
},
/**
* The prefilled network configuration. This can be empty if nothing to
* prefill or the configuration will be synced according to `this.guid`.
* @type {?ConfigProperties}
*/
prefilledProperties: Object,
/** @private {?ManagedProperties} */
managedProperties_: {
type: Object,
value: null,
},
/**
* Managed EAP properties used for determination of managed EAP fields.
* @private {?ManagedEAPProperties}
*/
managedEapProperties_: {
type: Object,
value: null,
},
/** Set once managedProperties_ have been sent; prevents multiple saves. */
propertiesSent_: Boolean,
/**
* The configuration properties for the network.
* @private {!ConfigProperties|undefined}
*/
configProperties_: Object,
/**
* Reference to the EAP properties for the current type or null if all EAP
* properties should be hidden (e.g. WiFi networks with non EAP Security).
* Note: even though this references an entry in configProperties_, we
* need to send a separate notification when it changes for data binding
* (e.g. by using 'set').
* @private {?EAPConfigProperties}
*/
eapProperties_: {
type: Object,
value: null,
},
/**
* The cached result of installed server CA certificates.
* @private {
* undefined|Array<!NetworkCertificate>}
*/
cachedServerCaCerts_: Array,
/**
* The cached result of installed user certificates.
* @private {
* undefined|Array<!NetworkCertificate>}
*/
cachedUserCerts_: Array,
/**
* Used to populate the 'Server CA certificate' dropdown.
* @private {!Array<!NetworkCertificate>}
*/
serverCaCerts_: {
type: Array,
value() {
return [];
},
},
/** @private {string|undefined} */
selectedServerCaHash_: String,
/**
* Used to populate the 'User certificate' dropdown.
* @private {!Array<!NetworkCertificate>}
*/
userCerts_: {
type: Array,
value() {
return [];
},
},
/** @private {string|undefined} */
selectedUserCertHash_: {
type: String,
observer: 'updateIsConfigured_',
},
/**
* Whether all required properties have been set.
* @private
*/
isConfigured_: {
type: Boolean,
value: false,
},
/**
* Whether this network should be shared with other users of the device.
* @private
*/
shareNetwork_: {
type: Boolean,
value: true,
},
/**
* This is a ManagedBoolean that represents a device-policy-enforced false
* value. It is used to present a policy-disabled toggle for "Share network"
* when user-created networks are ephemeral. It is never mutated.
* @private {!ManagedBoolean}
*/
shareNetworkEphemeralDisabled_: {
type: Object,
value: {
activeValue: false,
policySource: PolicySource.kDevicePolicyEnforced,
policyValue: false,
},
},
/**
* Whether the device should automatically connect to the network.
* @private
*/
autoConnect_: {
type: Boolean,
observer: 'updateHiddenNetworkWarning_',
},
/**
* Whether or not to show the hidden network warning.
* @private
*/
hiddenNetworkWarning_: Boolean,
/**
* Security value, used for Ethernet and Wifi and to detect when Security
* changes. NOTE: the <select> element might set this to a string, see
* crbug.com/1046149.
* @private {!SecurityType|string|undefined}
*/
securityType_: Number,
/**
* 'SaveCredentials' value used for VPN (OpenVPN, IPsec, and L2TP).
* @private
*/
vpnSaveCredentials_: {
type: Boolean,
value: false,
},
/**
* VPN Type from vpnTypeItems_.
* @private {VPNConfigType|undefined}
*/
vpnType_: {
type: String,
observer: 'updateVpnIPsecAuthTypeItems_',
},
/**
* Ipsec auth type from ipsecAuthTypeItems_.
* @private {IpsecAuthType}
*/
ipsecAuthType_: {
type: String,
value: IpsecAuthType.PSK,
},
/** @private {WireGuardKeyConfigType|undefined} */
wireguardKeyType_: String,
/** @private {string|undefined} */
ipAddressInput_: {
type: String,
observer: 'updateIsConfigured_',
},
/** @private {string|undefined} */
nameServersInput_: String,
/**
* Dictionary of boolean values determining which EAP properties to show,
* or null to hide all EAP settings.
* @private {?{
* Outer: (boolean|undefined),
* Inner: (boolean|undefined),
* ServerCA: (boolean|undefined),
* EapServerCertMatch: (boolean|undefined),
* UserCert: (boolean|undefined),
* Identity: (boolean|undefined),
* Password: (boolean|undefined),
* AnonymousIdentity: (boolean|undefined),
* }}
*/
showEap_: {
type: Object,
value: null,
},
/**
* Dictionary of boolean values determining which VPN properties to show,
* or null to hide all VPN settings.
* @private {?{
* IPsec: (boolean|undefined),
* IPsecPSK: (boolean|undefined),
* IPsecEAP: (boolean|undefined),
* IKEv2: (boolean|undefined),
* OpenVPN: (boolean|undefined),
* WireGuard: (boolean|undefined),
* ServerCA: (boolean|undefined),
* UserCert: (boolean|undefined),
* }}
*/
showVpn_: {
type: Object,
value: null,
},
/**
* Whether the WireGuard private key input box should be shown.
* @private
*/
isWireGuardUserPrivateKeyInputActive_: {
type: Boolean,
computed: 'updateWireGuardKeyType_(wireguardKeyType_)',
},
/**
* Array of values for the EAP Method (Outer) dropdown.
* They will be presented in a dropdown in this order.
* @private {!Array<string>}
*/
eapOuterItems_: {
type: Array,
readOnly: true,
value: ['PEAP', 'EAP-TLS', 'EAP-TTLS', 'LEAP'],
},
/**
* Array of values for the EAP EAP Phase 2 authentication (Inner) dropdown
* when the Outer type is PEAP.
* @private {!Array<string>}
* @const
*/
eapInnerItemsPeap_: {
type: Array,
readOnly: true,
value: () => {
const values = ['Automatic', 'MD5', 'MSCHAPv2'];
if (loadTimeData.getBoolean('eapGtcWifiAuthentication')) {
values.push('GTC');
}
return values;
},
},
/**
* Array of values for the EAP EAP Phase 2 authentication (Inner) dropdown
* when the Outer type is EAP-TTLS.
* @private {!Array<string>}
* @const
*/
eapInnerItemsTtls_: {
type: Array,
readOnly: true,
value: ['Automatic', 'MD5', 'MSCHAP', 'MSCHAPv2', 'PAP', 'CHAP', 'GTC'],
},
/**
* Array of values for the VPN Type dropdown.
* Note: closure does not recognize Array<VPNConfigType> here.
* @private {!Array<string>}
*/
vpnTypeItems_: {
type: Array,
value: [
VPNConfigType.L2TP_IPSEC,
VPNConfigType.OPEN_VPN,
],
},
/**
* Array of values for the Authentication Type dropdown for IPsec-based
* VPNs.
* @private {!Array<string>}
*/
ipsecAuthTypeItems_: {
type: Array,
value: [],
},
/**
* Array of values for the WireGuard key configuration method dropdown.
* The actual value is set in initWireGuardKeyConfigType_() since the
* value differs for new network and existing networks.
* @private {!Array<string>}
*/
wireguardKeyTypeItems_: {
type: Array,
value: [],
},
/**
* Whether the current network configuration allows only device-wide
* certificates (e.g. shared EAP TLS networks).
* @private
*/
deviceCertsOnly_: {
type: Boolean,
value: false,
},
/** @private */
configRequiresPassphrase_: {
type: Boolean,
computed: 'computeConfigRequiresPassphrase_(mojoType_, securityType_)',
},
/** @private */
serializedDomainSuffixMatch_: {
type: String,
value: '',
},
/** @private */
serializedSubjectAltNameMatch_: {
type: String,
value: '',
},
},
observers: [
'setEnableConnect_(isConfigured_, propertiesSent_)',
'setEnableSave_(isConfigured_, managedProperties_)',
'setShareNetwork_(mojoType_, managedProperties_, securityType_,' +
'shareDefault, shareAllowEnable)',
'updateConfigProperties_(mojoType_, managedProperties_)',
'updateSecurity_(configProperties_, securityType_)',
'updateCertItems_(cachedServerCaCerts_, cachedUserCerts_, vpnType_, ' +
'securityType_, eapProperties_.outer)',
'updateEapOuter_(eapProperties_.outer)',
'updateEapCerts_(eapProperties_.*, serverCaCerts_, userCerts_)',
'updateShowEap_(configProperties_.*, eapProperties_.*, securityType_)',
'updateVpnType_(configProperties_, vpnType_, ipsecAuthType_)',
'updateVpnIPsecCerts_(vpnType_, ipsecAuthType_,' +
'configProperties_.typeConfig.vpn.ipSec.*, serverCaCerts_, userCerts_)',
'updateOpenVPNCerts_(vpnType_,' +
'configProperties_.typeConfig.vpn.openVpn.*,' +
'serverCaCerts_, userCerts_)',
// Multiple updateIsConfigured observers for different configurations.
'updateIsConfigured_(configProperties_.*, securityType_)',
'updateIsConfigured_(configProperties_, eapProperties_.*)',
'updateIsConfigured_(configProperties_.typeConfig.wifi.*)',
'updateIsConfigured_(configProperties_.typeConfig.vpn.*, vpnType_,' +
'ipsecAuthType_)',
],
listeners: {'enter': 'onEnterEvent_'},
/** @const */
MIN_PASSPHRASE_LENGTH: 5,
/** @private {?CrosNetworkConfigInterface} */
networkConfig_: null,
/** @override */
created() {
this.networkConfig_ =
MojoInterfaceProviderImpl.getInstance().getMojoServiceRemote();
},
/** @override */
attached() {
this.networkConfig_.getGlobalPolicy().then(response => {
this.globalPolicy_ = response.result;
});
},
init() {
this.mojoType_ = undefined;
this.vpnType_ = undefined;
this.managedProperties_ = null;
this.configProperties_ = undefined;
this.propertiesSent_ = false;
this.cachedServerCaCerts_ = undefined;
this.cachedUserCerts_ = undefined;
this.selectedServerCaHash_ = undefined;
this.selectedUserCertHash_ = undefined;
this.networkConfig_.getSupportedVpnTypes().then(response => {
this.updateVpnTypeItems_(response.vpnTypes);
});
this.initWireGuardKeyConfigType_();
if (this.guid) {
this.networkConfig_.getManagedProperties(this.guid).then(response => {
this.getManagedPropertiesCallback_(response.result);
});
} else {
const mojoType = OncMojo.getNetworkTypeFromString(this.type);
const managedProperties =
OncMojo.getDefaultManagedProperties(mojoType, this.guid, this.name);
// Allow securityType_ to be set externally (e.g. in tests).
if (mojoType === NetworkType.kWiFi && this.securityType_ !== undefined) {
managedProperties.typeProperties.wifi.security =
/**@type {!SecurityType}*/ (this.securityType_);
}
this.managedProperties_ = managedProperties;
this.mojoType_ = mojoType;
setTimeout(() => {
this.focusFirstInput_();
});
}
if (this.mojoType_ === NetworkType.kVPN ||
(this.globalPolicy_ &&
this.globalPolicy_.allowOnlyPolicyWifiNetworksToConnect)) {
this.autoConnect_ = false;
} else {
this.autoConnect_ = true;
}
this.hiddenNetworkWarning_ = this.showHiddenNetworkWarning_();
this.updateIsConfigured_();
},
save() {
this.saveAndConnect_(false /* connect */);
},
connect() {
this.saveAndConnect_(true /* connect */);
},
/** @private */
focusPassphrase_() {
const passphraseInput = this.$$('#wifi-passphrase');
if (passphraseInput) {
passphraseInput.focus();
}
},
/**
* @param {boolean} connect If true, connect after save.
* @private
*/
saveAndConnect_(connect) {
if (!this.managedProperties_ || this.propertiesSent_) {
return;
}
this.propertiesSent_ = true;
this.error = '';
if (this.eapProperties_) {
const dsm = OncMojo.deserializeDomainSuffixMatch(
this.serializedDomainSuffixMatch_);
if (!dsm) {
this.setError_('invalidDomainSuffixMatchEntry');
this.propertiesSent_ = false;
return;
}
this.eapProperties_.domainSuffixMatch = dsm;
const sanm = OncMojo.deserializeSubjectAltNameMatch(
this.serializedSubjectAltNameMatch_);
if (!sanm) {
this.setError_('invalidSubjectAlternativeNameMatchEntry');
this.propertiesSent_ = false;
return;
}
this.eapProperties_.subjectAltNameMatch = sanm;
if (!this.eapConfigServerCaCertAllowed_()) {
this.setError_('missingEapDefaultServerCaSubjectVerification');
this.propertiesSent_ = false;
return;
}
}
const propertiesToSet = this.getPropertiesToSet_();
if (this.managedProperties_.source === OncSource.kNone) {
// Explicitly set the hidden SSID mode of new WiFi networks disabled to
// avoid networks being unintentionally marked as hidden in some
// situations, e.g., when the network SSID is misspelled or the network is
// not within range.
if (this.mojoType_ === NetworkType.kWiFi) {
propertiesToSet.typeConfig.wifi.hiddenSsid = HiddenSsidMode.kDisabled;
}
if (!this.autoConnect_) {
// Note: Do not set autoConnect to true, the connection manager will do
// that on a successful connection (unless set to false here).
propertiesToSet.autoConnect = {value: false};
}
this.networkConfig_.configureNetwork(propertiesToSet, this.shareNetwork_)
.then(response => {
this.createNetworkCallback_(
response.guid, response.errorMessage, connect);
});
} else {
this.networkConfig_.setProperties(this.guid, propertiesToSet)
.then(response => {
this.setPropertiesCallback_(
response.success, response.errorMessage, connect);
});
}
this.fire('properties-set');
},
/** @private */
focusFirstInput_() {
flush();
const e = this.$$(
'network-config-input:not([readonly]),' +
'network-password-input:not([disabled]),' +
'network-config-select:not([disabled])');
if (e) {
e.focus();
}
},
/**
* @param {!Event} event
* @private
*/
onEnterEvent_(event) {
if (event.composedPath()[0].localName === 'network-config-input' ||
event.composedPath()[0].localName === 'network-password-input') {
this.onEnterPressedInInput_();
event.stopPropagation();
}
},
/** @private */
onEnterPressedInInput_() {
if (!this.isConfigured_) {
return;
}
if (this.connectOnEnter) {
this.connect();
} else {
this.save();
}
},
/** @private */
close_() {
this.guid = '';
this.type = '';
this.securityType_ = undefined;
this.fire('close');
},
/**
* @return {boolean}
* @private
*/
hasGuid_() {
return !!this.guid;
},
/**
* @return {boolean}
* @private
*/
isIkev2Supported_() {
return this.vpnTypeItems_.includes(VPNConfigType.IKEV2);
},
/**
* @return {boolean}
* @private
*/
isWireGuardSupported_() {
return this.vpnTypeItems_.includes(VPNConfigType.WIREGUARD);
},
/**
* @param {!Array<string>|undefined} responseTypes
* @private
*/
updateVpnTypeItems_(responseTypes) {
this.vpnTypeItems_ = [
VPNConfigType.L2TP_IPSEC,
VPNConfigType.OPEN_VPN,
];
if (responseTypes.includes('ikev2')) {
this.vpnTypeItems_.unshift(VPNConfigType.IKEV2);
}
if (responseTypes.includes('wireguard')) {
this.vpnTypeItems_.push(VPNConfigType.WIREGUARD);
}
},
/** @private */
initWireGuardKeyConfigType_() {
let items = [
WireGuardKeyConfigType.GENERATE_NEW,
WireGuardKeyConfigType.USER_INPUT,
];
if (this.hasGuid_()) {
items = [...items, WireGuardKeyConfigType.USE_CURRENT];
this.wireguardKeyType_ = WireGuardKeyConfigType.USE_CURRENT;
} else {
this.wireguardKeyType_ = WireGuardKeyConfigType.GENERATE_NEW;
}
this.wireguardKeyTypeItems_ = items;
},
/** NetworkListenerBehavior override */
onNetworkCertificatesChanged() {
this.networkConfig_.getNetworkCertificates().then(response => {
this.set('cachedServerCaCerts_', response.serverCas.slice());
this.set('cachedUserCerts_', response.userCerts.slice());
});
},
/**
* @param {CertificateType} type
* @param {string} desc
* @param {string} hash
* @return {!NetworkCertificate}
* @private
*/
getDefaultCert_(type, desc, hash) {
return {
type: type,
hash: hash,
issuedBy: desc,
issuedTo: '',
pemOrId: '',
availableForNetworkAuth: false,
hardwareBacked: false,
// Default cert entries should always be shown, even in the login UI,
// so treat thiem as device-wide.
deviceWide: true,
};
},
/**
* @param {?ManagedBoolean|undefined} property
* @return {boolean}
* @private
*/
getActiveBoolean_(property) {
if (!property) {
return false;
}
return property.activeValue;
},
/**
* @param {?ManagedInt32|undefined} property
* @return {number}
* @private
*/
getActiveInt32_(property) {
if (!property) {
return 0;
}
return property.activeValue;
},
/**
* @param {?ManagedStringList|undefined} property
* @return {!Array<string>|undefined}
* @private
*/
getActiveStringList_(property) {
if (!property) {
return undefined;
}
return property.activeValue;
},
/**
* @param {?ManagedProperties} managedProperties
* @private
*/
getManagedPropertiesCallback_(managedProperties) {
if (!managedProperties) {
// The network no longer exists; close the page.
console.warn('Network no longer exists: ' + this.guid);
this.close_();
return;
}
this.managedProperties_ = managedProperties;
this.managedEapProperties_ = this.getManagedEap_(managedProperties);
this.mojoType_ = managedProperties.type;
if (this.mojoType_ === NetworkType.kVPN) {
let saveCredentials = false;
const vpn = managedProperties.typeProperties.vpn;
if (vpn.type === VpnType.kOpenVPN) {
saveCredentials = this.getActiveBoolean_(vpn.openVpn.saveCredentials);
} else if (vpn.type === VpnType.kIKEv2) {
saveCredentials = this.getActiveBoolean_(vpn.ipSec.saveCredentials);
} else if (vpn.type === VpnType.kL2TPIPsec) {
saveCredentials = this.getActiveBoolean_(vpn.ipSec.saveCredentials) ||
this.getActiveBoolean_(vpn.l2tp.saveCredentials);
} else if (vpn.type === VpnType.kWireGuard) {
saveCredentials = true;
}
this.vpnSaveCredentials_ = saveCredentials;
}
this.setError_(managedProperties.errorState);
this.updateCertError_();
this.focusFirstInput_();
},
/**
* @return {!Array<SecurityType>}
* @private
*/
getSecurityItems_() {
if (this.mojoType_ === NetworkType.kWiFi) {
return [
SecurityType.kNone,
SecurityType.kWepPsk,
SecurityType.kWpaPsk,
SecurityType.kWpaEap,
];
}
return [
SecurityType.kNone,
SecurityType.kWpaEap,
];
},
/** @private */
setShareNetwork_() {
if (this.mojoType_ === undefined || !this.managedProperties_ ||
!this.securityType_ === undefined) {
return;
}
const source = this.managedProperties_.source;
if (source !== OncSource.kNone) {
// Configured networks can not change whether they are shared.
this.shareNetwork_ =
source === OncSource.kDevice || source === OncSource.kDevicePolicy;
return;
}
if (!this.shareIsVisible_()) {
this.shareNetwork_ = this.shareDefault;
return;
}
if (this.shareAllowEnable && !this.shareDefault) {
// By default, Wi-Fi networks which require passwords are not shared,
// but "insecure" networks with no passwords are shared. In either case,
// the user can change the sharing setting by updating the toggle in the
// UI.
if (this.mojoType_ === NetworkType.kWiFi) {
this.shareNetwork_ = this.securityType_ === SecurityType.kNone;
return;
}
}
this.shareNetwork_ = this.shareDefault;
},
/** @private */
onShareChanged_(event) {
this.updateSelectedCerts_();
},
/**
* @param {!ManagedEAPProperties} eap
* @return {!EAPConfigProperties}
* @private
*/
getEAPConfigProperties_(eap) {
return {
anonymousIdentity: OncMojo.getActiveString(eap.anonymousIdentity),
clientCertType: OncMojo.getActiveString(eap.clientCertType),
clientCertPkcs11Id: OncMojo.getActiveString(eap.clientCertPkcs11Id),
domainSuffixMatch: this.getActiveStringList_(eap.domainSuffixMatch) || [],
identity: OncMojo.getActiveString(eap.identity),
inner: OncMojo.getActiveString(eap.inner),
outer: OncMojo.getActiveString(eap.outer) || DEFAULT_EAP_OUTER_PROTOCOL,
password: OncMojo.getActiveString(eap.password),
saveCredentials: this.getActiveBoolean_(eap.saveCredentials),
serverCaPems: this.getActiveStringList_(eap.serverCaPems),
subjectAltNameMatch:
/** @type {!Array<!SubjectAltName>} */
(OncMojo.getActiveValue(eap.subjectAltNameMatch) || []),
subjectMatch: OncMojo.getActiveString(eap.subjectMatch),
useSystemCas: this.getActiveBoolean_(eap.useSystemCas),
};
},
/**
* @param {!ManagedIPSecProperties} ipSec
* @return {!IPSecConfigProperties}
* @private
*/
getIPSecConfigProperties_(ipSec) {
return {
authenticationType:
OncMojo.getActiveString(ipSec.authenticationType) || 'PSK',
clientCertPkcs11Id: OncMojo.getActiveString(ipSec.clientCertPkcs11Id),
clientCertType: OncMojo.getActiveString(ipSec.clientCertType),
eap: ipSec.eap ? this.getEAPConfigProperties_(ipSec.eap) : null,
group: OncMojo.getActiveString(ipSec.group),
ikeVersion: this.getActiveInt32_(ipSec.ikeVersion),
localIdentity: OncMojo.getActiveString(ipSec.localIdentity),
psk: OncMojo.getActiveString(ipSec.psk),
remoteIdentity: OncMojo.getActiveString(ipSec.remoteIdentity),
saveCredentials: this.getActiveBoolean_(ipSec.saveCredentials),
serverCaPems: this.getActiveStringList_(ipSec.serverCaPems),
serverCaRefs: this.getActiveStringList_(ipSec.serverCaRefs),
};
},
/**
* @param {!ManagedL2TPProperties} l2tp
* @return {!L2TPConfigProperties}
* @private
*/
getL2TPConfigProperties_(l2tp) {
return {
lcpEchoDisabled: this.getActiveBoolean_(l2tp.lcpEchoDisabled),
password: OncMojo.getActiveString(l2tp.password),
saveCredentials: this.getActiveBoolean_(l2tp.saveCredentials),
username: OncMojo.getActiveString(l2tp.username),
};
},
/**
* @param {!ManagedOpenVPNProperties} openVpn
* @return {!OpenVPNConfigProperties}
* @private
*/
getOpenVPNConfigProperties_(openVpn) {
return {
clientCertPkcs11Id: OncMojo.getActiveString(openVpn.clientCertPkcs11Id),
clientCertType: OncMojo.getActiveString(openVpn.clientCertType),
extraHosts: this.getActiveStringList_(openVpn.extraHosts),
otp: '',
password: OncMojo.getActiveString(openVpn.password),
saveCredentials: this.getActiveBoolean_(openVpn.saveCredentials),
serverCaPems: this.getActiveStringList_(openVpn.serverCaPems),
serverCaRefs: this.getActiveStringList_(openVpn.serverCaRefs),
userAuthenticationType:
OncMojo.getActiveString(openVpn.userAuthenticationType),
username: OncMojo.getActiveString(openVpn.username),
};
},
/**
* @param {!ManagedWireGuardProperties} wireguard
* @return {!WireGuardConfigProperties}
* @private
*/
getWireGuardConfigProperties_(wireguard) {
const config = {
ipAddresses: this.getActiveStringList_(wireguard.ipAddresses) ?? [],
privateKey: OncMojo.getActiveString(wireguard.privateKey),
peers: [],
};
if (wireguard.peers && wireguard.peers.activeValue) {
for (const peer of wireguard.peers.activeValue) {
const peerCopied = Object.assign({}, peer);
if (this.hasGuid_()) {
// Shill does not return exact value for credential fields, showing
// a placeholder here.
peerCopied.presharedKey = PLACEHOLDER_CREDENTIAL;
}
config.peers.push(peerCopied);
}
}
return config;
},
/**
* Updates the config properties when |this.managedProperties| changes.
* This gets called once when navigating to the page when default properties
* are set, and again for existing networks when the properties are received.
* @private
*/
updateConfigProperties_() {
if (this.mojoType_ === undefined || !this.managedProperties_) {
return;
}
this.showEap_ = null;
this.showVpn_ = null;
this.vpnType_ = undefined;
const managedProperties = this.managedProperties_;
const configProperties =
OncMojo.getDefaultConfigProperties(managedProperties.type);
configProperties.name = OncMojo.getActiveString(managedProperties.name);
let autoConnect;
let security = SecurityType.kNone;
switch (managedProperties.type) {
case NetworkType.kWiFi:
const wifi = managedProperties.typeProperties.wifi;
const configWifi = configProperties.typeConfig.wifi;
autoConnect = this.getActiveBoolean_(wifi.autoConnect);
configWifi.passphrase = OncMojo.getActiveString(wifi.passphrase);
configWifi.ssid = OncMojo.getActiveString(wifi.ssid);
if (wifi.eap) {
configWifi.eap = this.getEAPConfigProperties_(wifi.eap);
}
// updateSecurity_ will ensure that EAP properties are set correctly.
security = wifi.security;
configWifi.security = security;
break;
case NetworkType.kEthernet:
const eap = managedProperties.typeProperties.ethernet.eap ?
this.getEAPConfigProperties_(
managedProperties.typeProperties.ethernet.eap) :
undefined;
security = eap ? SecurityType.kWpaEap : SecurityType.kNone;
const auth = security === SecurityType.kWpaEap ? '8021X' : 'None';
configProperties.typeConfig.ethernet.authentication = auth;
configProperties.typeConfig.ethernet.eap = eap;
break;
case NetworkType.kVPN:
const vpn = managedProperties.typeProperties.vpn;
const vpnType = vpn.type;
const configVpn = configProperties.typeConfig.vpn;
configVpn.host = OncMojo.getActiveString(vpn.host);
configVpn.type = {value: vpnType};
if (vpnType === VpnType.kIKEv2) {
if (!this.isIkev2Supported_()) {
break;
}
assert(vpn.ipSec);
configVpn.ipSec = this.getIPSecConfigProperties_(vpn.ipSec);
} else if (vpnType === VpnType.kL2TPIPsec) {
assert(vpn.ipSec);
configVpn.ipSec = this.getIPSecConfigProperties_(vpn.ipSec);
assert(vpn.l2tp);
configVpn.l2tp = this.getL2TPConfigProperties_(vpn.l2tp);
} else if (vpnType === VpnType.kOpenVPN) {
assert(vpn.openVpn);
configVpn.openVpn = this.getOpenVPNConfigProperties_(vpn.openVpn);
} else if (vpnType === VpnType.kWireGuard) {
if (!this.isWireGuardSupported_()) {
break;
}
assert(vpn.wireguard);
configVpn.wireguard =
this.getWireGuardConfigProperties_(vpn.wireguard);
this.ipAddressInput_ = configVpn.wireguard.ipAddresses.join(',');
const staticIpConfig = managedProperties.staticIpConfig;
if (staticIpConfig && staticIpConfig.nameServers) {
this.nameServersInput_ =
staticIpConfig.nameServers.activeValue.join(',');
}
} else {
assertNotReached();
}
security = SecurityType.kNone;
break;
}
if (autoConnect !== undefined) {
configProperties.autoConnect = {value: autoConnect};
}
// Request certificates the first time |configProperties_| is set.
const requestCertificates = this.configProperties_ === undefined;
this.configProperties_ = configProperties;
this.securityType_ = security;
this.set('eapProperties_', this.getEap_(this.configProperties_));
if (!this.eapProperties_) {
this.showEap_ = null;
} else {
this.serializedDomainSuffixMatch_ = OncMojo.serializeDomainSuffixMatch(
this.eapProperties_.domainSuffixMatch);
this.serializedSubjectAltNameMatch_ =
OncMojo.serializeSubjectAltNameMatch(
this.eapProperties_.subjectAltNameMatch);
}
if (managedProperties.type === NetworkType.kVPN) {
this.vpnType_ = this.getVpnTypeFromProperties_(this.configProperties_);
this.ipsecAuthType_ =
this.getIpsecAuthTypeFromProperties_(this.configProperties_);
}
if (requestCertificates) {
this.onNetworkCertificatesChanged();
}
},
/**
* Ensures that the appropriate properties are set or deleted when
* |securityType_| changes.
* @private
*/
updateSecurity_() {
if (this.securityType_ === undefined || !this.configProperties_) {
return;
}
const type = this.mojoType_;
// Force |securityType_| to an enum value when the <select> element sets it
// to a string. See crbug.com/1046149 for details.
if (typeof (this.securityType_) === 'string') {
this.securityType_ =
/** @type {!SecurityType}*/ (
Number.parseInt(/** @type {string}*/ (this.securityType_), 10));
}
const security = this.securityType_;
if (type === NetworkType.kWiFi) {
this.configProperties_.typeConfig.wifi.security = security;
} else if (type === NetworkType.kEthernet) {
const auth = security === SecurityType.kWpaEap ? '8021X' : 'None';
this.configProperties_.typeConfig.ethernet.authentication = auth;
}
let eap;
if (security === SecurityType.kWpaEap) {
eap = this.getEap_(this.configProperties_, true);
eap.outer = eap.outer || DEFAULT_EAP_OUTER_PROTOCOL;
}
this.setEap_(eap);
},
/**
* Ensures that the appropriate EAP properties are created (or deleted when
* the eap.outer property changes.
* @private
*/
updateEapOuter_() {
const eap = this.eapProperties_;
if (!eap || !eap.outer) {
return;
}
const innerItems = this.getEapInnerItems_(eap.outer);
if (innerItems.length > 0) {
if (!eap.inner || innerItems.indexOf(eap.inner) < 0) {
this.set('eapProperties_.inner', innerItems[0]);
}
} else {
this.set('eapProperties_.inner', undefined);
}
if (eap.outer !== 'EAP-TLS') {
this.set('eapProperties_.clientCertType', 'None');
this.set('eapProperties_.clientCertPkcs11Id', '');
this.selectedUserCertHash_ = NO_USER_CERT_HASH;
}
},
/** @private */
updateEapCerts_() {
// EAP is used for all configurable types except VPN.
if (this.mojoType_ === NetworkType.kVPN) {
return;
}
const eap = this.eapProperties_;
const pem = eap && eap.serverCaPems ? eap.serverCaPems[0] : '';
const certId =
eap && eap.clientCertType === 'PKCS11Id' ? eap.clientCertPkcs11Id : '';
this.setSelectedCerts_(pem, certId);
},
/** @private */
updateShowEap_() {
if (!this.eapProperties_ || this.securityType_ === SecurityType.kNone) {
this.showEap_ = null;
this.updateCertError_();
return;
}
const outer = this.eapProperties_.outer;
switch (this.mojoType_) {
case NetworkType.kWiFi:
case NetworkType.kEthernet:
this.showEap_ = {
Outer: true,
Inner: outer === 'PEAP' || outer === 'EAP-TTLS',
ServerCA: outer !== 'LEAP',
EapServerCertMatch:
outer === 'EAP-TLS' || outer === 'EAP-TTLS' || outer === 'PEAP',
UserCert: outer === 'EAP-TLS',
Identity: true,
Password: outer !== 'EAP-TLS',
AnonymousIdentity: outer === 'PEAP' || outer === 'EAP-TTLS',
};
break;
}
this.updateCertError_();
},
/**
* @param {!ConfigProperties} properties
* @param {boolean=} opt_create
* @return {?EAPConfigProperties}
* @private
*/
getEap_(properties, opt_create) {
let eap;
if (properties.typeConfig.wifi) {
eap = properties.typeConfig.wifi.eap;
} else if (properties.typeConfig.ethernet) {
eap = properties.typeConfig.ethernet.eap;
} else if (properties.typeConfig.vpn && properties.typeConfig.vpn.ipSec) {
eap = properties.typeConfig.vpn.ipSec.eap;
}
if (opt_create) {
return eap || {
saveCredentials: false,
useSystemCas: false,
domainSuffixMatch: [],
subjectAltNameMatch: [],
};
}
return eap || null;
},
/**
* @param {!EAPConfigProperties|undefined} eapProperties
* @private
*/
setEap_(eapProperties) {
switch (this.mojoType_) {
case NetworkType.kWiFi:
this.configProperties_.typeConfig.wifi.eap = eapProperties;
break;
case NetworkType.kEthernet:
this.configProperties_.typeConfig.ethernet.eap = eapProperties;
break;
}
this.set('eapProperties_', eapProperties);
},
/**
* @param {!ManagedProperties} managedProperties
* @return {?ManagedEAPProperties}
* @private
*/
getManagedEap_(managedProperties) {
let managedEap;
switch (managedProperties.type) {
case NetworkType.kWiFi:
managedEap = managedProperties.typeProperties.wifi.eap;
break;
case NetworkType.kEthernet:
managedEap = managedProperties.typeProperties.ethernet.eap;
break;
case NetworkType.kVPN:
if (managedProperties.typeProperties.vpn.ipSec) {
managedEap = managedProperties.typeProperties.vpn.ipSec.eap;
}
break;
}
return managedEap || null;
},
/**
* @param {!ConfigProperties} properties
* @return {!VPNConfigType}
* @private
*/
getVpnTypeFromProperties_(properties) {
const vpn = properties.typeConfig.vpn;
assert(vpn);
if (!!vpn.type && vpn.type.value === VpnType.kIKEv2) {
return VPNConfigType.IKEV2;
} else if (!!vpn.type && vpn.type.value === VpnType.kL2TPIPsec) {
return VPNConfigType.L2TP_IPSEC;
} else if (!!vpn.type && vpn.type.value === VpnType.kWireGuard) {
return VPNConfigType.WIREGUARD;
}
return VPNConfigType.OPEN_VPN;
},
/**
* @param {!ConfigProperties} properties
* @return {!IpsecAuthType}
* @private
*/
getIpsecAuthTypeFromProperties_(properties) {
const vpn = properties.typeConfig.vpn;
assert(vpn);
if (!vpn.type ||
!(vpn.type.value === VpnType.kL2TPIPsec ||
vpn.type.value === VpnType.kIKEv2)) {
// This field will not be used by services other than IPsec-based VPN.
// Initiate it to "PSK" for simplicity.
return IpsecAuthType.PSK;
}
if (vpn.ipSec.authenticationType === IpsecAuthType.PSK) {
return IpsecAuthType.PSK;
} else if (vpn.ipSec.authenticationType === IpsecAuthType.CERT) {
return IpsecAuthType.CERT;
} else if (vpn.ipSec.authenticationType === IpsecAuthType.EAP) {
return IpsecAuthType.EAP;
}
assertNotReached();
},
/** @private */
updateWireGuardKeyType_() {
return this.wireguardKeyType_ === WireGuardKeyConfigType.USER_INPUT;
},
/** @private */
updateCertItems_() {
if (this.configProperties_ === undefined ||
this.cachedServerCaCerts_ === undefined ||
this.cachedUserCerts_ === undefined) {
return;
}
const isOpenVpn = this.vpnType_ === VPNConfigType.OPEN_VPN;
const isIpsec = this.vpnType_ === VPNConfigType.L2TP_IPSEC ||
this.vpnType_ === VPNConfigType.IKEV2;
let caCerts = this.cachedServerCaCerts_.slice();
if (!isOpenVpn && !isIpsec) {
// 'Default' is the same as 'Do not check' except that 'Default' sets
// eap.useSystemCas (which does not apply to OpenVPN and IPsec-based
// VPNs).
caCerts.unshift(this.getDefaultCert_(
CertificateType.kServerCA, this.i18n('networkCAUseDefault'),
DEFAULT_HASH));
}
if (!isIpsec) {
// For IPsec-based VPNs, it is mandatory to verify the server.
caCerts.push(this.getDefaultCert_(
CertificateType.kServerCA, this.i18n('networkCADoNotCheck'),
DO_NOT_CHECK_HASH));
}
if (!caCerts.length) {
caCerts = [this.getDefaultCert_(
CertificateType.kServerCA,
this.i18n('networkCertificateNoneInstalled'), NO_CERTS_HASH)];
}
this.set('serverCaCerts_', caCerts);
let userCerts = this.cachedUserCerts_.slice();
// Only certs available for network authentication can be used.
userCerts.forEach(function(cert) {
if (!cert.availableForNetworkAuth) {
cert.hash = '';
} // Clear the hash to invalidate the certificate.
});
const isEap = this.securityType_ === SecurityType.kWpaEap;
const isEapTls = isEap && this.eapProperties_.outer === 'EAP-TLS';
// User certificate is allowed but not required for OpenVPN and
// EAP protocols except EAP-TLS (required for EAP-TLS)
const isUserCertOptional = isOpenVpn || (isEap && !isEapTls);
if (isUserCertOptional) {
userCerts.unshift(this.getDefaultCert_(
CertificateType.kUserCert, this.i18n('networkNoUserCert'),
NO_USER_CERT_HASH));
}
if (!userCerts.length) {
userCerts = [this.getDefaultCert_(
CertificateType.kUserCert,
this.i18n('networkCertificateNoneInstalled'), NO_CERTS_HASH)];
}
this.set('userCerts_', userCerts);
this.updateSelectedCerts_();
this.updateCertError_();
},
/** @private */
updateVpnType_() {
if (this.configProperties_ === undefined || this.vpnType_ === undefined) {
return;
}
const vpn = this.configProperties_.typeConfig.vpn;
if (!vpn) {
this.showVpn_ = null;
this.updateCertError_();
return;
}
switch (this.vpnType_) {
case VPNConfigType.IKEV2:
vpn.type = {value: VpnType.kIKEv2};
if (!vpn.ipSec) {
this.ipsecAuthType_ = IpsecAuthType.EAP;
vpn.ipSec = {
authenticationType: this.ipsecAuthType_,
ikeVersion: 2,
saveCredentials: false,
};
}
if (this.ipsecAuthType_ === IpsecAuthType.EAP && !vpn.ipSec.eap) {
vpn.ipSec.eap = {
domainSuffixMatch: [],
outer: 'MSCHAPv2',
saveCredentials: false,
subjectAltNameMatch: [],
useSystemCas: false,
};
this.eapProperties_ = vpn.ipSec.eap;
}
break;
case VPNConfigType.L2TP_IPSEC:
vpn.type = {value: VpnType.kL2TPIPsec};
if (this.ipsecAuthType_ !== IpsecAuthType.PSK &&
this.ipsecAuthType_ !== IpsecAuthType.CERT) {
// This will happen if user changes the VPN type to IKEv2 where the
// default value of auth type is EAP, and then changes the VPN type to
// L2TP/IPsec.
this.ipsecAuthType_ = IpsecAuthType.PSK;
}
if (!vpn.ipSec) {
vpn.ipSec = {
authenticationType: this.ipsecAuthType_,
ikeVersion: 1,
saveCredentials: false,
};
}
break;
case VPNConfigType.OPEN_VPN:
vpn.type = {value: VpnType.kOpenVPN};
vpn.openVpn = vpn.openVpn || {saveCredentials: false};
break;
case VPNConfigType.WIREGUARD:
vpn.type = {value: VpnType.kWireGuard};
vpn.wireguard = vpn.wireguard || {peers: [{}]};
break;
default:
assertNotReached();
}
const isIpsec = this.vpnType_ === VPNConfigType.L2TP_IPSEC ||
this.vpnType_ === VPNConfigType.IKEV2;
const ipsecAuthIsPsk = this.ipsecAuthType_ === IpsecAuthType.PSK;
const ipsecAuthIsEap = this.ipsecAuthType_ === IpsecAuthType.EAP;
const ipsecAuthIsCert = this.ipsecAuthType_ === IpsecAuthType.CERT;
const isOpenvpn = this.vpnType_ === VPNConfigType.OPEN_VPN;
this.showVpn_ = {
IPsec: isIpsec,
IPsecPSK: isIpsec && ipsecAuthIsPsk,
IPsecEAP: isIpsec && ipsecAuthIsEap,
IKEv2: this.vpnType_ === VPNConfigType.IKEV2,
OpenVPN: isOpenvpn,
WireGuard: this.vpnType_ === VPNConfigType.WIREGUARD,
ServerCA: (isIpsec && !ipsecAuthIsPsk) || isOpenvpn,
UserCert: (isIpsec && ipsecAuthIsCert) || isOpenvpn,
};
if (vpn.type.value === VpnType.kL2TPIPsec && !vpn.l2tp) {
vpn.l2tp = {
lcpEchoDisabled: false,
password: '',
saveCredentials: false,
username: '',
};
}
if (vpn.type.value !== VpnType.kL2TPIPsec &&
vpn.type.value !== VpnType.kIKEv2) {
delete vpn.ipSec;
}
if (vpn.type.value !== VpnType.kL2TPIPsec) {
delete vpn.l2tp;
}
if (vpn.type.value !== VpnType.kOpenVPN) {
delete vpn.openVpn;
}
if (vpn.type.value !== VpnType.kWireGuard) {
delete vpn.wireguard;
}
this.updateCertError_();
},
/** @private */
updateVpnIPsecAuthTypeItems_() {
this.ipsecAuthTypeItems_ = [
IpsecAuthType.PSK,
IpsecAuthType.CERT,
];
if (this.vpnType_ === VPNConfigType.IKEV2) {
this.ipsecAuthTypeItems_.push(IpsecAuthType.EAP);
}
},
/** @private */
updateVpnIPsecCerts_() {
if (this.vpnType_ !== VPNConfigType.L2TP_IPSEC &&
this.vpnType_ !== VPNConfigType.IKEV2) {
return;
}
if (this.ipsecAuthType_ === IpsecAuthType.PSK) {
return;
}
const ipSec = this.configProperties_.typeConfig.vpn.ipSec;
if (!ipSec) {
return;
}
const pem = ipSec.serverCaPems ? ipSec.serverCaPems[0] : undefined;
const certId =
ipSec.clientCertType === 'PKCS11Id' ? ipSec.clientCertPkcs11Id : '';
this.setSelectedCerts_(pem, certId);
},
/** @private */
updateOpenVPNCerts_() {
if (this.vpnType_ !== VPNConfigType.OPEN_VPN) {
return;
}
const openVpn = this.configProperties_.typeConfig.vpn.openVpn;
if (!openVpn) {
return;
}
const pem = openVpn.serverCaPems ? openVpn.serverCaPems[0] : undefined;
const certId =
openVpn.clientCertType === 'PKCS11Id' ? openVpn.clientCertPkcs11Id : '';
this.setSelectedCerts_(pem, certId);
},
/** @private */
updateCertError_() {
// If |this.error| was set to something other than a cert error, do not
// change it.
/** @const */ const noCertsError = 'networkErrorNoUserCertificate';
/** @const */ const noValidCertsError =
'networkErrorNotAvailableForNetworkAuth';
if (this.error && this.error !== noCertsError &&
this.error !== noValidCertsError) {
return;
}
const requireCerts = (this.showEap_ && this.showEap_.UserCert) ||
(this.showVpn_ && this.showVpn_.UserCert);
if (!requireCerts) {
this.setError_('');
return;
}
if (!this.userCerts_.length || this.userCerts_[0].hash === NO_CERTS_HASH) {
this.setError_(noCertsError);
return;
}
const validUserCert = this.userCerts_.find(function(cert) {
return !!cert.hash;
});
if (!validUserCert) {
this.setError_(noValidCertsError);
return;
}
this.setError_('');
return;
},
/**
* Sets the selected cert if |pem| (serverCa) or |certId| (user) is specified.
* Otherwise sets a default value if no certificate is selected.
* @param {string|undefined} pem
* @param {string|undefined} certId
* @private
*/
setSelectedCerts_(pem, certId) {
if (pem) {
const serverCa = this.serverCaCerts_.find(function(cert) {
return cert.pemOrId === pem;
});
if (serverCa) {
this.selectedServerCaHash_ = serverCa.hash;
}
}
if (certId) {
// |certId| is in the format |slot:id| for EAP and IPSec and |id| for
// OpenVPN certs.
// |userCerts_[i].pemOrId| is always in the format |slot:id|.
// Use a substring comparison to support both |certId| formats.
const userCert = this.userCerts_.find(function(cert) {
return cert.pemOrId.indexOf(/** @type {string} */ (certId)) >= 0;
});
if (userCert) {
this.selectedUserCertHash_ = userCert.hash;
}
}
this.updateSelectedCerts_();
this.updateIsConfigured_();
},
/**
* @param {!Array<!NetworkCertificate>} certs
* @param {string|undefined} hash
* @private
* @return {!NetworkCertificate|undefined}
*/
findCert_(certs, hash) {
if (!hash) {
return undefined;
}
return certs.find((cert) => {
return cert.hash === hash;
});
},
/**
* Called when the certificate list or a selected certificate changes.
* Ensures that each selected certificate exists in its list, or selects the
* correct default value.
* @private
*/
updateSelectedCerts_() {
if (!this.serverCaCerts_.length || !this.userCerts_.length) {
return;
}
const eap = this.eapProperties_;
// Only device-wide certificates can be used for shared networks that
// require a certificate.
this.deviceCertsOnly_ =
this.shareNetwork_ && !!eap && eap.outer === 'EAP-TLS';
// Validate selected Server CA.
const caCert =
this.findCert_(this.serverCaCerts_, this.selectedServerCaHash_);
if (!caCert || (this.deviceCertsOnly_ && !caCert.deviceWide)) {
this.selectedServerCaHash_ = undefined;
}
if (!this.selectedServerCaHash_) {
if (eap && eap.useSystemCas) {
this.selectedServerCaHash_ = DEFAULT_HASH;
} else if (!this.guid && this.serverCaCerts_[0]) {
// For unconfigured networks, default to the first available
// certificate and fallback to DEFAULT_HASH. See
// onNetworkCertificatesChanged() for how certificates are added.
let cert = this.serverCaCerts_[0];
if (cert.hash === DEFAULT_HASH &&
this.isRealCertUsableForNetworkAuth_(this.serverCaCerts_[1])) {
cert = this.serverCaCerts_[1];
}
this.selectedServerCaHash_ = cert.hash;
} else {
this.selectedServerCaHash_ = DO_NOT_CHECK_HASH;
}
}
// Validate selected User cert.
const userCert =
this.findCert_(this.userCerts_, this.selectedUserCertHash_);
if (!userCert || (this.deviceCertsOnly_ && !userCert.deviceWide)) {
this.selectedUserCertHash_ = undefined;
}
if (!this.selectedUserCertHash_) {
for (let i = 0; i < this.userCerts_.length; ++i) {
const userCert = this.userCerts_[i];
if (userCert && (!this.deviceCertsOnly_ || userCert.deviceWide)) {
this.selectedUserCertHash_ = userCert.hash;
break;
}
}
}
},
/**
* Checks that the hash of the certificate is set and not one of the default
* special strings.
* @param {NetworkCertificate|undefined} cert
* @return {boolean}
* @private
*/
isRealCertUsableForNetworkAuth_(cert) {
return !!cert && cert.hash !== DO_NOT_CHECK_HASH &&
cert.hash !== DEFAULT_HASH;
},
/**
* @return {boolean}
* @private
*/
getIsConfigured_() {
if (this.securityType_ === undefined || !this.configProperties_) {
return false;
}
const typeConfig = this.configProperties_.typeConfig;
if (typeConfig.vpn) {
if (this.vpnType_ === VPNConfigType.IKEV2 && !this.isIkev2Supported_()) {
return false;
}
return this.vpnIsConfigured_();
}
if (typeConfig.wifi) {
if (!typeConfig.wifi.ssid) {
return false;
}
if (this.configRequiresPassphrase_) {
const passphrase = typeConfig.wifi.passphrase;
if (!passphrase || passphrase.length < this.MIN_PASSPHRASE_LENGTH) {
return false;
}
}
}
if (this.securityType_ === SecurityType.kWpaEap) {
return this.eapIsConfigured_();
}
return true;
},
/** @private */
updateIsConfigured_() {
this.isConfigured_ = this.getIsConfigured_();
},
/**
* @param {NetworkType} networkType
* @return {boolean}
* @private
*/
isWiFi_(networkType) {
return networkType === NetworkType.kWiFi;
},
/** @private */
setEnableSave_() {
this.enableSave = this.isConfigured_ && !!this.managedProperties_;
},
/** @private */
setEnableConnect_() {
this.enableConnect = this.isConfigured_ && !this.propertiesSent_;
},
/**
* @param {NetworkType} networkType
* @return {boolean}
* @private
*/
securityIsVisible_(networkType) {
return networkType === NetworkType.kWiFi ||
networkType === NetworkType.kEthernet;
},
/**
* @return {boolean}
* @private
*/
securityIsEnabled_() {
// WiFi Security type cannot be changed once configured.
return !this.guid || this.mojoType_ === NetworkType.kEthernet;
},
/**
* @return {boolean}
* @private
*/
shareIsVisible_() {
if (!this.managedProperties_) {
return false;
}
return this.managedProperties_.source === OncSource.kNone &&
this.managedProperties_.type === NetworkType.kWiFi;
},
/**
* @return {boolean}
* @private
*/
shareIsEnabled_() {
if (!this.managedProperties_) {
return false;
}
if (!this.shareAllowEnable ||
this.managedProperties_.source !== OncSource.kNone) {
return false;
}
return true;
},
/**
* Returns true if the network configured by this UI element is ephemeral
* according to enterprise policy.
* @return {boolean}
* @private
*/
networkIsEphemeral_() {
if (!loadTimeData.getBoolean('ephemeralNetworkPoliciesEnabled')) {
return false;
}
if (!this.globalPolicy_ ||
!this.globalPolicy_.userCreatedNetworkConfigurationsAreEphemeral) {
return false;
}
if (!this.managedProperties_) {
return false;
}
// Only user-created networks are ephemeral with this policy.
return this.managedProperties_.source === OncSource.kNone;
},
/**
* @return {boolean}
* @private
*/
configCanAutoConnect_() {
// Only WiFi can choose whether or not to autoConnect.
return loadTimeData.getBoolean('showHiddenNetworkWarning') &&
this.mojoType_ === NetworkType.kWiFi;
},
/**
* @return {boolean}
* @private
*/
autoConnectDisabled_() {
return this.isAutoConnectEnforcedByPolicy_();
},
/**
* @return {boolean}
* @private
*/
isAutoConnectEnforcedByPolicy_() {
return !!this.globalPolicy_ &&
!!this.globalPolicy_.allowOnlyPolicyNetworksToAutoconnect;
},
/**
* @return {boolean}
* @private
*/
showHiddenNetworkWarning_() {
flush();
return loadTimeData.getBoolean('showHiddenNetworkWarning') &&
this.autoConnect_ && !this.hasGuid_();
},
/**
* @private
*/
updateHiddenNetworkWarning_() {
this.hiddenNetworkWarning_ = this.showHiddenNetworkWarning_();
},
/**
* @return {boolean}
* @private
*/
selectedServerCaHashIsValid_() {
return !!this.selectedServerCaHash_ &&
this.selectedServerCaHash_ !== NO_CERTS_HASH;
},
/**
* @return {boolean}
* @private
*/
selectedUserCertHashIsValid_() {
return !!this.selectedUserCertHash_ &&
this.selectedUserCertHash_ !== NO_CERTS_HASH;
},
/**
* @return {boolean}
* @private
*/
eapIsConfigured_() {
if (!this.configProperties_) {
return false;
}
const eap = this.getEap_(this.configProperties_);
if (!eap) {
return false;
}
if (eap.outer !== 'EAP-TLS') {
return true;
}
// EAP TLS networks can be shared only for device-wide certificates.
if (this.deviceCertsOnly_) { // network is shared
let cert = this.findCert_(this.userCerts_, this.selectedUserCertHash_);
if (!cert || !cert.deviceWide) {
return false;
}
cert = this.findCert_(this.serverCaCerts_, this.selectedServerCaHash_);
if (!cert.deviceWide) {
return false;
}
}
return this.selectedUserCertHashIsValid_();
},
/**
* @return {boolean}
* @private
*/
ikev2IsConfigured_() {
const vpn = this.configProperties_.typeConfig.vpn;
switch (this.ipsecAuthType_) {
case IpsecAuthType.PSK:
return !!vpn.ipSec.psk;
case IpsecAuthType.CERT:
// TODO(b/206722135): Show proper error message in the UI if server CA
// is invalid.
return this.selectedServerCaHashIsValid_() &&
this.selectedUserCertHashIsValid_();
case IpsecAuthType.EAP:
return this.selectedServerCaHashIsValid_() &&
!!this.eapProperties_.identity;
default:
assertNotReached();
}
},
/**
* @return {boolean}
* @private
*/
l2tpIpsecIsConfigured_() {
const vpn = this.configProperties_.typeConfig.vpn;
switch (this.ipsecAuthType_) {
case IpsecAuthType.PSK:
return !!vpn.l2tp.username && !!vpn.ipSec.psk;
case IpsecAuthType.CERT:
// TODO(b/206722135): Show proper error message in the UI if server CA
// is invalid.
return !!vpn.l2tp.username && this.selectedServerCaHashIsValid_() &&
this.selectedUserCertHashIsValid_();
default:
assertNotReached();
}
},
/**
* @param {string|null|undefined} input
* @return {boolean}
* @private
*/
isValidWireGuardKey_(input) {
// A base64 translation of a 32 byte string is 44 bytes with '=' ending
return !!input && input.length === 44 && input.charAt(43) === '=' &&
!!input.match(/^[a-z0-9+/=]+$/i);
},
/**
* Checks if the input ipAddresses is a comma-delimited string which contains
* IP addresses (v4, v6, or both).
* @param {string|undefined} ipAddresses
* @return {boolean}
* @private
*/
isValidWireGuardIpAddresses_(ipAddresses) {
if (!ipAddresses) {
return false;
}
// Currently shill only supports at most 1 IPv4 + 1 IPv6 address.
let v4Count = 0;
let v6Count = 0;
for (const ipAddress of ipAddresses.split(',')) {
if (ipAddress.match(IPV4_ADDR_REGEX)) {
v4Count++;
} else if (ipAddress.match(IPV6_ADDR_REGEX)) {
v6Count++;
} else {
return false;
}
}
if (v4Count > 1 || v6Count > 1) {
return false;
}
return v4Count + v6Count > 0;
},
/**
* @param {WireGuardConfigProperties|null|undefined} wireguard
* @param {string|undefined} ipAddresses
* @return {boolean}
* @private
*/
isWireGuardConfigurationValid_(wireguard, ipAddresses) {
if (!wireguard) {
return false;
}
if (!this.isValidWireGuardIpAddresses_(ipAddresses)) {
return false;
}
if (this.isWireGuardUserPrivateKeyInputActive_ &&
!this.isValidWireGuardKey_(wireguard.privateKey)) {
return false;
}
// TODO: Current UI only supports configuring a single peer.
const peer = wireguard.peers[0];
if (!this.isValidWireGuardKey_(peer.publicKey)) {
return false;
}
if (!!peer.presharedKey && peer.presharedKey !== PLACEHOLDER_CREDENTIAL &&
!this.isValidWireGuardKey_(peer.presharedKey)) {
return false;
}
// endpoint should be the form of IP:port or hostname:port
if (!peer.endpoint ||
!peer.endpoint.match(/^\[?[a-zA-Z0-9\-\.:]+\]?:[0-9]+$/i)) {
return false;
}
// allowedIps should be comma-separated list of IP/cidr.
if (!peer.allowedIps ||
!peer.allowedIps.split(',').every(s => s.match(IP_CIDR_REGEX))) {
return false;
}
return true;
},
/**
* @return {boolean}
* @private
*/
vpnIsConfigured_() {
const vpn = this.configProperties_.typeConfig.vpn;
if (!this.configProperties_.name || !vpn ||
(!vpn.host && this.vpnType_ !== VPNConfigType.WIREGUARD)) {
return false;
}
switch (this.vpnType_) {
case VPNConfigType.IKEV2:
return this.ikev2IsConfigured_();
case VPNConfigType.L2TP_IPSEC:
return this.l2tpIpsecIsConfigured_();
case VPNConfigType.OPEN_VPN:
// OpenVPN should require username + password OR a user cert. However,
// there may be servers with different requirements so err on the side
// of permissiveness.
return true;
case VPNConfigType.WIREGUARD:
return this.isWireGuardConfigurationValid_(
vpn.wireguard, this.ipAddressInput_);
}
return false;
},
/** @private */
getPropertiesToSet_() {
const propertiesToSet =
/** @type {!ConfigProperties}*/ (
Object.assign({}, this.configProperties_));
// Do not set AutoConnect by default, the connection manager will set
// it to true on a successful connection.
delete propertiesToSet.autoConnect;
if (this.guid) {
propertiesToSet.guid = this.guid;
}
const eap = this.getEap_(propertiesToSet);
if (eap) {
this.setEapProperties_(eap);
}
if (this.mojoType_ === NetworkType.kVPN) {
const vpnConfig = propertiesToSet.typeConfig.vpn;
// VPN.Host can be an IP address but will not be recognized as such if
// there is initial whitespace, so trim it.
if (vpnConfig.host !== undefined) {
vpnConfig.host = vpnConfig.host.trim();
}
const vpnType = vpnConfig.type.value;
if (vpnType === VpnType.kOpenVPN) {
this.setOpenVPNProperties_(propertiesToSet);
} else {
delete propertiesToSet.typeConfig.vpn.openVpn;
}
if (vpnType === VpnType.kIKEv2) {
this.setVpnIkev2Properties_(propertiesToSet);
} else if (vpnType === VpnType.kL2TPIPsec) {
this.setVpnL2tpIpsecProperties_(propertiesToSet);
} else {
delete propertiesToSet.typeConfig.vpn.ipSec;
delete propertiesToSet.typeConfig.vpn.l2tp;
}
if (vpnType === VpnType.kWireGuard) {
this.setWireGuardProperties_(propertiesToSet);
} else {
delete propertiesToSet.typeConfig.vpn.wireguard;
}
}
return propertiesToSet;
},
/**
* @return {!Array<string>}
* @private
*/
getServerCaPems_() {
const caHash = this.selectedServerCaHash_ || '';
if (!caHash || caHash === DO_NOT_CHECK_HASH || caHash === DEFAULT_HASH) {
return [];
}
const serverCa = this.findCert_(this.serverCaCerts_, caHash);
return serverCa && serverCa.pemOrId ? [serverCa.pemOrId] : [];
},
/**
* @return {string}
* @private
*/
getUserCertPkcs11Id_() {
const userCertHash = this.selectedUserCertHash_ || '';
if (!this.selectedUserCertHashIsValid_() ||
userCertHash === NO_USER_CERT_HASH) {
return '';
}
const userCert = this.findCert_(this.userCerts_, userCertHash);
return (userCert && userCert.pemOrId) || '';
},
/**
* @param {!EAPConfigProperties} eap
* @private
*/
setEapProperties_(eap) {
eap.useSystemCas = this.selectedServerCaHash_ === DEFAULT_HASH;
eap.serverCaPems = this.getServerCaPems_();
const pkcs11Id = this.getUserCertPkcs11Id_();
eap.clientCertType = pkcs11Id ? 'PKCS11Id' : 'None';
eap.clientCertPkcs11Id = pkcs11Id || '';
},
/**
* @param {!ConfigProperties} propertiesToSet
* @private
*/
setVpnIkev2Properties_(propertiesToSet) {
const ipsec = propertiesToSet.typeConfig.vpn.ipSec;
assert(!!ipsec);
ipsec.authenticationType = this.ipsecAuthType_;
if (ipsec.authenticationType !== IpsecAuthType.PSK) {
// Set psk to empty string to make sure the value is cleared.
ipsec.psk = '';
// For non-PSK auth method, server CA is mandatory.
ipsec.serverCaPems = this.getServerCaPems_();
}
if (ipsec.authenticationType === IpsecAuthType.CERT) {
ipsec.clientCertType = 'PKCS11Id';
ipsec.clientCertPkcs11Id = this.getUserCertPkcs11Id_();
} else {
delete ipsec.clientCertType;
delete ipsec.clientCertPkcs11Id;
}
if (ipsec.authenticationType === IpsecAuthType.EAP) {
// Not all fields in eap are used by IKEv2, so create a new object here.
const eap = ipsec.eap;
ipsec.eap = {
domainSuffixMatch: [],
identity: eap.identity,
outer: 'MSCHAPv2',
password: eap.password,
saveCredentials: this.vpnSaveCredentials_,
subjectAltNameMatch: [],
useSystemCas: false,
};
} else {
delete ipsec.eap;
}
ipsec.ikeVersion = 2;
ipsec.saveCredentials = this.vpnSaveCredentials_;
},
/**
* @param {!ConfigProperties} propertiesToSet
* @private
*/
setOpenVPNProperties_(propertiesToSet) {
const openVpn = propertiesToSet.typeConfig.vpn.openVpn;
assert(!!openVpn);
openVpn.serverCaPems = this.getServerCaPems_();
const pkcs11Id = this.getUserCertPkcs11Id_();
openVpn.clientCertType = pkcs11Id ? 'PKCS11Id' : 'None';
openVpn.clientCertPkcs11Id = pkcs11Id || '';
if (openVpn.password) {
openVpn.userAuthenticationType =
openVpn.otp ? 'PasswordAndOTP' : 'Password';
} else if (openVpn.otp) {
openVpn.userAuthenticationType = 'OTP';
} else {
openVpn.userAuthenticationType = 'None';
}
openVpn.saveCredentials = this.vpnSaveCredentials_;
propertiesToSet.typeConfig.vpn.openVpn = openVpn;
},
/**
* @param {!ConfigProperties} propertiesToSet
* @private
*/
setWireGuardProperties_(propertiesToSet) {
const wireguard = propertiesToSet.typeConfig.vpn.wireguard;
assert(!!wireguard);
propertiesToSet.typeConfig.vpn.host = 'wireguard';
propertiesToSet.ipAddressConfigType = 'Static';
wireguard.ipAddresses = this.ipAddressInput_.split(',');
propertiesToSet.staticIpConfig = {
gateway: this.ipAddressInput_,
routingPrefix: 32,
type: IPConfigType.kIPv4,
};
if (this.nameServersInput_) {
propertiesToSet.nameServersConfigType = 'Static';
propertiesToSet.staticIpConfig.nameServers =
this.nameServersInput_.split(',');
}
if (this.wireguardKeyType_ === WireGuardKeyConfigType.USE_CURRENT) {
delete wireguard.privateKey;
} else if (this.wireguardKeyType_ === WireGuardKeyConfigType.GENERATE_NEW) {
wireguard.privateKey = '';
}
assert(!!wireguard.peers);
for (const peer of wireguard.peers) {
if (peer.presharedKey === PLACEHOLDER_CREDENTIAL) {
delete peer.presharedKey; // No modification
} else if (peer.presharedKey === undefined) {
peer.presharedKey = ''; // Explicitly removed
}
}
},
/**
* @param {!ConfigProperties} propertiesToSet
* @private
*/
setVpnL2tpIpsecProperties_(propertiesToSet) {
const vpn = propertiesToSet.typeConfig.vpn;
assert(vpn.ipSec);
assert(vpn.l2tp);
vpn.ipSec.authenticationType = this.ipsecAuthType_;
if (vpn.ipSec.authenticationType === IpsecAuthType.CERT) {
vpn.ipSec.clientCertType = 'PKCS11Id';
vpn.ipSec.clientCertPkcs11Id = this.getUserCertPkcs11Id_();
vpn.ipSec.serverCaPems = this.getServerCaPems_();
}
vpn.ipSec.ikeVersion = 1;
vpn.ipSec.saveCredentials = this.vpnSaveCredentials_;
vpn.l2tp.saveCredentials = this.vpnSaveCredentials_;
// Clear IPsec fields which are only for IKEv2.
delete vpn.ipSec.eap;
delete vpn.ipSec.localIdentity;
delete vpn.ipSec.remoteIdentity;
},
/**
* @param {boolean} success
* @param {string} errorMessage
* @param {boolean} connect If true, connect after save.
* @private
*/
setPropertiesCallback_(success, errorMessage, connect) {
if (!success) {
console.warn(
'Unable to set properties for: ' + this.guid +
' Error: ' + errorMessage);
this.propertiesSent_ = false;
this.setError_(errorMessage);
this.focusPassphrase_();
return;
}
// Only attempt a connection if the network is not yet connected.
if (connect &&
this.managedProperties_.connectionState ===
ConnectionStateType.kNotConnected) {
this.startConnect_(this.guid);
} else {
this.close_();
}
},
/**
* @param {?string} guid
* @param {string} errorMessage
* @param {boolean} connect If true, connect after save.
* @private
*/
createNetworkCallback_(guid, errorMessage, connect) {
if (!guid) {
console.warn(
'Unable to configure network: ' + guid + ' Error: ' + errorMessage);
this.propertiesSent_ = false;
this.setError_(errorMessage);
this.focusPassphrase_();
return;
}
if (connect) {
this.startConnect_(guid);
} else {
this.close_();
}
},
/**
* @param {string} guid
* @private
*/
startConnect_(guid) {
this.networkConfig_.startConnect(guid).then(response => {
const result = response.result;
if (result === StartConnectResult.kSuccess ||
result === StartConnectResult.kInvalidGuid ||
result === StartConnectResult.kInvalidState ||
result === StartConnectResult.kCanceled) {
// Connect succeeded, or is in progress completed or canceled.
// Close the dialog.
this.close_();
return;
}
this.setError_(response.message);
console.warn(
'Error connecting to network: ' + guid + ': ' + result.toString() +
' Message: ' + response.message);
this.propertiesSent_ = false;
});
},
/**
* @param {NetworkType|undefined} mojoType
* @param {SecurityType|undefined} securityType
* @return {boolean}
* @private
*/
computeConfigRequiresPassphrase_(mojoType, securityType) {
// Note: 'Passphrase' is only used by WiFi; Ethernet uses EAP.Password.
return mojoType === NetworkType.kWiFi &&
(securityType === SecurityType.kWepPsk ||
securityType === SecurityType.kWpaPsk);
},
/**
* @param {string} outer
* @return {!Array<string>}
* @private
*/
getEapInnerItems_(outer) {
if (outer === 'PEAP') {
return this.eapInnerItemsPeap_;
}
if (outer === 'EAP-TTLS') {
return this.eapInnerItemsTtls_;
}
return [];
},
/**
* @param {string|undefined} error
* @private
*/
setError_(error) {
this.error = error || '';
},
/**
* Returns a managed property for policy controlled networks.
* @param {!ManagedProperties} managedProperties
* @return {ManagedString|undefined}
* @private
*/
getManagedSecurity_(managedProperties) {
const policySource =
OncMojo.getEnforcedPolicySourceFromOncSource(managedProperties.source);
if (policySource === PolicySource.kNone) {
return undefined;
}
switch (managedProperties.type) {
case NetworkType.kWiFi:
return {
activeValue: OncMojo.getSecurityTypeString(
managedProperties.typeProperties.wifi.security),
policySource: policySource,
};
break;
case NetworkType.kEthernet:
return {
activeValue: OncMojo.getActiveString(
managedProperties.typeProperties.ethernet.authentication),
policySource: policySource,
};
break;
}
return undefined;
},
/**
* @param {!ManagedProperties} managedProperties
* @return {!ManagedBoolean|undefined}
* @private
*/
getManagedVpnSaveCredentials_(managedProperties) {
const vpn = managedProperties.typeProperties.vpn;
switch (vpn.type) {
case VpnType.kIKEv2:
return vpn.ipSec.saveCredentials || OncMojo.createManagedBool(false);
case VpnType.kOpenVPN:
return vpn.openVpn.saveCredentials || OncMojo.createManagedBool(false);
case VpnType.kL2TPIPsec:
return vpn.ipSec.saveCredentials || vpn.l2tp.saveCredentials ||
OncMojo.createManagedBool(false);
case VpnType.kWireGuard:
return OncMojo.createManagedBool(true);
}
assertNotReached();
return undefined;
},
/**
* @param {!ManagedProperties} managedProperties
* @return {?ManagedStringList|undefined}
* @private
*/
getManagedVpnServerCaRefs_(managedProperties) {
const vpn = managedProperties.typeProperties.vpn;
switch (vpn.type) {
case VpnType.kOpenVPN:
return vpn.openVpn.serverCaRefs;
case VpnType.kIKEv2:
case VpnType.kL2TPIPsec:
return vpn.ipSec.serverCaRefs;
}
assertNotReached();
return undefined;
},
/**
* @param {!ManagedProperties} managedProperties
* @return {!ManagedString|undefined}
* @private
*/
getManagedVpnClientCertType_(managedProperties) {
const vpn = managedProperties.typeProperties.vpn;
switch (vpn.type) {
case VpnType.kOpenVPN:
return vpn.openVpn.clientCertType || OncMojo.createManagedString('');
case VpnType.kIKEv2:
case VpnType.kL2TPIPsec:
return vpn.ipSec.clientCertType || OncMojo.createManagedString('');
}
assertNotReached();
return undefined;
},
/** @private */
onWifiPasswordInputKeypress_() {
// bad-passphrase corresponds to kErrorBadPassphrase in shill
if (this.error === 'bad-passphrase') {
// Reset error if user starts typing new password.
this.setError_('');
}
},
/**
* Verifies if the selected server CA certificate can be used for the selected
* EAP method. This method returns false is the selected EAP method requires a
* server CA certificate and the user selected the default certificate without
* configuring the domain suffix match or subject alternative match and
* without explicitly allowing insecure connections via Chrome flags.
* Otherwise returns true.
* @return {boolean}
* @private
*/
eapConfigServerCaCertAllowed_() {
const outer = this.eapProperties_.outer;
if (!(outer === 'EAP-TLS' || outer === 'EAP-TTLS' || outer === 'PEAP')) {
return true;
}
if (this.selectedServerCaHash_ !== DEFAULT_HASH) {
// Does not use default CA server certs.
return true;
}
const isPropertyManaged = !!this.managedEapProperties_ &&
!!this.managedEapProperties_.useSystemCas &&
(this.managedEapProperties_.useSystemCas.policySource !==
PolicySource.kNone);
// Bypass `domainSuffixMatch` and `subjectAltNameMatch` checks for managed
// networks if the user doesn't control the CA setting.
if (isPropertyManaged) {
return true;
}
if (this.eapProperties_.domainSuffixMatch.length != 0 ||
this.eapProperties_.subjectAltNameMatch.length != 0) {
return true;
}
return false;
},
});