7 var callGetCertificateFiles
= rpc
.declare({
8 object
: 'luci.openconnect',
9 method
: 'getCertificates',
10 params
: [ 'interface' ],
14 var callSetCertificateFiles
= rpc
.declare({
15 object
: 'luci.openconnect',
16 method
: 'setCertificates',
17 params
: [ 'interface', 'user_certificate', 'user_privatekey', 'ca_certificate' ],
21 network
.registerPatternVirtual(/^vpn-.+$/);
23 function sanitizeCert(s
) {
24 if (typeof(s
) != 'string')
32 s
= s
.replace(/\r\n?/g, '\n');
40 function validateCert(priv
, section_id
, value
) {
41 var beg
= priv
? /^-----BEGIN (RSA )?PRIVATE KEY-----$/ : /^-----BEGIN CERTIFICATE-----$/,
42 end
= priv
? /^-----END (RSA )?PRIVATE KEY-----$/ : /^-----END CERTIFICATE-----$/,
43 lines
= value
.trim().split(/[\r\n]/),
47 if (value
=== null || value
=== '')
50 for (i
= 0; i
< lines
.length
; i
++) {
51 if (lines
[i
].match(beg
))
53 else if (start
&& !lines
[i
].match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/))
57 if (!start
|| i
< lines
.length
- 1 || !lines
[i
].match(end
))
58 return _('This does not look like a valid PEM file');
63 return network
.registerProtocol('openconnect', {
65 return _('OpenConnect');
68 getIfname: function() {
69 return this._ubus('l3_device') || 'vpn-%s'.format(this.sid
);
72 getOpkgPackage: function() {
76 isFloating: function() {
80 isVirtual: function() {
84 getDevices: function() {
88 containsDevice: function(ifname
) {
89 return (network
.getIfnameOf(ifname
) == this.getIfname());
92 renderFormOptions: function(s
) {
93 var dev
= this.getDevice().getName(),
94 certLoadPromise
= null,
97 o
= s
.taboption('general', form
.ListValue
, 'vpn_protocol', _('VPN Protocol'));
98 o
.value('anyconnect', 'OpenConnect or Cisco AnyConnect SSL VPN');
99 o
.value('nc', 'Juniper Network Connect');
100 o
.value('gp', 'Palo Alto Networks GlobalProtect');
101 o
.value('pulse', 'Pulse Connect Secure SSL VPN');
102 o
.value('f5', 'F5 BIG-IP SSL VPN');
103 o
.value('fortinet', 'Fortinet SSL VPN');
104 o
.value('array', 'Array Networks SSL VPN');
106 o
= s
.taboption('general', form
.Value
, 'uri', _('VPN Server'));
107 o
.placeholder
= 'https://example.com:443/usergroup';
108 o
.validate = function(section_id
, value
) {
109 var m
= String(value
).match(/^(?:(\w+):\/\/|)(?:\[([0-9a-f:.]{2,45})\]|([^\/:]+))(?::([0-9]{1,5}))?(?:\/.*)?$/i);
112 return _('Invalid server URL');
115 if (!m
[1].match(/^(?:https|socks|socks4|socks5)$/i))
116 return _('Unsupported protocol');
120 if (!validation
.parseIPv6(m
[2]))
121 return _('Invalid IPv6 address');
125 if (!validation
.parseIPv4(m
[3])) {
126 if (!(m
[3].length
<= 253 &&
127 (m
[3].match(/^[a-zA-Z0-9_]+$/) != null ||
128 (m
[3].match(/^[a-zA-Z0-9_][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$/) &&
129 m
[3].match(/[^0-9.]/)))))
130 return _('Invalid hostname or IPv4 address');
137 if (p
< 0 || p
> 65535)
138 return _('Invalid port');
144 s
.taboption('general', form
.Value
, 'serverhash', _("VPN Server's certificate SHA1 hash"));
145 s
.taboption('general', form
.Value
, 'authgroup', _('Auth Group'));
146 s
.taboption("general", form
.Value
, "username", _("Username"));
148 o
= s
.taboption('general', form
.Value
, 'password', _('Password'));
151 o
= s
.taboption('general', form
.Value
, 'password2', _('Password2'));
154 o
= s
.taboption('general', form
.Value
, 'proxy', _('Proxy Server'));
157 o
= s
.taboption('general', form
.TextValue
, 'usercert', _('User certificate (PEM encoded)'));
160 o
.validate
= L
.bind(validateCert
, o
, false);
161 o
.load = function(section_id
) {
162 certLoadPromise
= certLoadPromise
|| callGetCertificateFiles(section_id
);
163 return certLoadPromise
.then(function(certs
) { return certs
.user_certificate
});
165 o
.write = function(section_id
, value
) {
166 return callSetCertificateFiles(section_id
, sanitizeCert(value
), null, null);
169 o
= s
.taboption('general', form
.TextValue
, 'userkey', _('User key (PEM encoded)'));
172 o
.validate
= L
.bind(validateCert
, o
, true);
173 o
.load = function(section_id
) {
174 certLoadPromise
= certLoadPromise
|| callGetCertificateFiles(section_id
);
175 return certLoadPromise
.then(function(certs
) { return certs
.user_privatekey
});
177 o
.write = function(section_id
, value
) {
178 return callSetCertificateFiles(section_id
, null, sanitizeCert(value
), null);
181 o
= s
.taboption('general', form
.TextValue
, 'ca', _('CA certificate; if empty it will be saved after the first connection.'));
184 o
.validate
= L
.bind(validateCert
, o
, false);
185 o
.load = function(section_id
) {
186 certLoadPromise
= certLoadPromise
|| callGetCertificateFiles(section_id
);
187 return certLoadPromise
.then(function(certs
) { return certs
.ca_certificate
});
189 o
.write = function(section_id
, value
) {
190 return callSetCertificateFiles(section_id
, null, null, sanitizeCert(value
));
193 o
= s
.taboption('advanced', form
.Value
, 'mtu', _('Override MTU'));
195 o
.placeholder
= 1406;
196 o
.datatype
= 'range(68, 9200)';
198 o
= s
.taboption('advanced', form
.Value
, 'reconnect_timeout', _('Reconnect Timeout'));
201 o
.datatype
= 'min(10)';