luci-base: js linting fixes / ES6 treatment

prevent global variable bleed and reduce size somewhat

-cbi
-network
-protocol/static
-rpc
-tools/widgets
-tools/views
-uci

protocols

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
This commit is contained in:
Paul Donald
2026-02-14 19:46:15 +01:00
parent 394d92e042
commit 50a8d5325d
12 changed files with 996 additions and 1045 deletions

View File

@@ -19,8 +19,8 @@
* defined here are registered as global `window.*` symbols.
* @module LuCI.cbi
*/
var cbi_d = [];
var cbi_strings = { path: {}, label: {} };
const cbi_d = [];
const cbi_strings = { path: {}, label: {} };
/**
* Read signed 8-bit integer from a byte array at the given offset.
@@ -29,7 +29,7 @@ var cbi_strings = { path: {}, label: {} };
* @returns {number} Signed 8-bit value (returned as unsigned number).
*/
function s8(bytes, off) {
var n = bytes[off];
const n = bytes[off];
return (n > 0x7F) ? (n - 256) >>> 0 : n;
}
@@ -53,10 +53,10 @@ function sfh(s) {
if (s === null || s.length === 0)
return null;
var bytes = [];
const bytes = [];
for (var i = 0; i < s.length; i++) {
var ch = s.charCodeAt(i);
for (let i = 0; i < s.length; i++) {
let ch = s.charCodeAt(i);
// Handle surrogate pairs
if (ch >= 0xD800 && ch <= 0xDBFF && i + 1 < s.length) {
@@ -86,9 +86,9 @@ function sfh(s) {
if (!bytes.length)
return null;
var hash = (bytes.length >>> 0),
len = (bytes.length >>> 2),
off = 0, tmp;
let hash = (bytes.length >>> 0);
let len = (bytes.length >>> 2);
let off = 0, tmp;
while (len--) {
hash += u16(bytes, off);
@@ -300,7 +300,7 @@ function cbi_d_update() {
* placeholders with interactive widgets.
*/
function cbi_init() {
var nodes;
let nodes;
document.querySelectorAll('.cbi-dropdown').forEach(function(node) {
cbi_dropdown_init(node);
@@ -309,65 +309,65 @@ function cbi_init() {
nodes = document.querySelectorAll('[data-strings]');
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
var str = JSON.parse(node.getAttribute('data-strings'));
for (var key in str) {
for (var key2 in str[key]) {
var dst = cbi_strings[key] || (cbi_strings[key] = { });
dst[key2] = str[key][key2];
for (let n of nodes) {
const str = JSON.parse(n.getAttribute('data-strings'));
for (let key in str) {
for (let key2 in str[key]) {
const dst = cbi_strings[key] || (cbi_strings[key] = { });
dst[key2] = str[key][key2];
}
}
}
nodes = document.querySelectorAll('[data-depends]');
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
var index = parseInt(node.getAttribute('data-index'), 10);
var depends = JSON.parse(node.getAttribute('data-depends'));
for (let n of nodes) {
const index = parseInt(n.getAttribute('data-index'), 10);
const depends = JSON.parse(n.getAttribute('data-depends'));
if (!isNaN(index) && depends.length > 0) {
for (let alt = 0; alt < depends.length; alt++)
cbi_d_add(node, depends[alt], index);
for (let a of depends)
cbi_d_add(n, depends[a], index);
}
}
nodes = document.querySelectorAll('[data-update]');
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
var events = node.getAttribute('data-update').split(' ');
for (let j = 0, event; (event = events[j]) !== undefined; j++)
node.addEventListener(event, cbi_d_update);
for (let n of nodes) {
const events = n.getAttribute('data-update').split(' ');
for (let ev of events)
n.addEventListener(ev, cbi_d_update);
}
nodes = document.querySelectorAll('[data-choices]');
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
let choices = JSON.parse(node.getAttribute('data-choices')),
options = {};
for (let node of nodes) {
const choices = JSON.parse(node.getAttribute('data-choices'));
const options = {};
for (let j = 0; j < choices[0].length; j++)
options[choices[0][j]] = choices[1][j];
var def = (node.getAttribute('data-optional') === 'true')
const def = (node.getAttribute('data-optional') === 'true')
? node.placeholder || '' : null;
var cb = new L.ui.Combobox(node.value, options, {
const cb = new L.ui.Combobox(node.value, options, {
name: node.getAttribute('name'),
sort: choices[0],
select_placeholder: def || _('-- Please choose --'),
custom_placeholder: node.getAttribute('data-manual') || _('-- custom --')
});
var n = cb.render();
const n = cb.render();
n.addEventListener('cbi-dropdown-change', cbi_d_update);
node.parentNode.replaceChild(n, node);
}
nodes = document.querySelectorAll('[data-dynlist]');
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
let choices = JSON.parse(node.getAttribute('data-dynlist')),
values = JSON.parse(node.getAttribute('data-values') || '[]'),
options = null;
for (let node of nodes) {
const choices = JSON.parse(node.getAttribute('data-dynlist'));
const values = JSON.parse(node.getAttribute('data-values') || '[]');
let options = null;
if (choices[0] && choices[0].length) {
options = {};
@@ -391,7 +391,7 @@ function cbi_init() {
nodes = document.querySelectorAll('[data-type]');
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
for (let node of nodes) {
cbi_validate_field(node, node.getAttribute('data-optional') === 'true',
node.getAttribute('data-type'));
}
@@ -415,9 +415,9 @@ function cbi_init() {
var tasks = [];
document.querySelectorAll('[data-ui-widget]').forEach(function(node) {
let args = JSON.parse(node.getAttribute('data-ui-widget') || '[]'),
widget = new (Function.prototype.bind.apply(L.ui[args[0]], args)),
markup = widget.render();
const args = JSON.parse(node.getAttribute('data-ui-widget') || '[]');
const widget = new (Function.prototype.bind.apply(L.ui[args[0]], args));
const markup = widget.render();
tasks.push(Promise.resolve(markup).then(function(markup) {
markup.addEventListener('widget-change', cbi_d_update);
@@ -441,8 +441,8 @@ function cbi_validate_form(form, errmsg)
return true;
if (form.cbi_validators) {
for (var i = 0; i < form.cbi_validators.length; i++) {
var validator = form.cbi_validators[i];
for (let fv of form.cbi_validators) {
const validator = fv;
if (!validator() && errmsg) {
alert(errmsg);
@@ -584,10 +584,10 @@ function cbi_row_swap(elem, up, store)
*/
function cbi_tag_last(container)
{
var last;
let last;
for (var i = 0; i < container.childNodes.length; i++) {
var c = container.childNodes[i];
for (let cn of container.childNodes) {
var c = cn;
if (matchesElem(c, 'div')) {
c.classList.remove('cbi-value-last');
last = c;
@@ -608,7 +608,7 @@ function cbi_tag_last(container)
*/
function cbi_submit(elem, name, value, action)
{
var form = elem.form || findParent(elem, 'form');
const form = elem.form || findParent(elem, 'form');
if (!form)
return false;
@@ -644,8 +644,8 @@ String.prototype.format = function()
if (!RegExp)
return;
var html_esc = [/&/g, '&#38;', /"/g, '&#34;', /'/g, '&#39;', /</g, '&#60;', />/g, '&#62;'];
var quot_esc = [/"/g, '&#34;', /'/g, '&#39;'];
const html_esc = [/&/g, '&#38;', /"/g, '&#34;', /'/g, '&#39;', /</g, '&#60;', />/g, '&#62;'];
const quot_esc = [/"/g, '&#34;', /'/g, '&#39;'];
/**
* Escape a string.
@@ -656,7 +656,7 @@ String.prototype.format = function()
* @returns {string}
*/
function esc(s, r) {
var t = typeof(s);
const t = typeof(s);
if (s == null || t === 'object' || t === 'function')
return '';
@@ -664,32 +664,31 @@ String.prototype.format = function()
if (t !== 'string')
s = String(s);
for (var i = 0; i < r.length; i += 2)
for (let i = 0; i < r.length; i += 2)
s = s.replace(r[i], r[i+1]);
return s;
}
var str = this;
var out = '';
var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
var a = b = [], numSubstitutions = 0, numMatches = 0;
let str = this;
let subst, n, pad;
let out = '';
const re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
let a = [], numSubstitutions = 0;
while ((a = re.exec(str)) !== null) {
var m = a[1];
var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
var pPrecision = a[6], pType = a[7];
numMatches++;
const m = a[1];
let leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
let pPrecision = a[6], pType = a[7];
if (pType == '%') {
subst = '%';
}
else {
if (numSubstitutions < arguments.length) {
var param = arguments[numSubstitutions++];
let param = arguments[numSubstitutions++];
var pad = '';
pad = '';
if (pPad && pPad.substr(0,1) == "'")
pad = leftpart.substr(1,1);
else if (pPad)
@@ -697,19 +696,11 @@ String.prototype.format = function()
else
pad = ' ';
var justifyRight = true;
if (pJustify && pJustify === "-")
justifyRight = false;
var minLength = -1;
if (pMinLength)
minLength = +pMinLength;
var precision = -1;
if (pPrecision && pType == 'f')
precision = +pPrecision.substring(1);
var subst = param;
subst = param;
switch(pType) {
case 'b':
@@ -725,7 +716,7 @@ String.prototype.format = function()
break;
case 'u':
var n = +param || 0;
n = +param || 0;
subst = Math.floor((n < 0) ? 0x100000000 + n : n).toFixed(0);
break;
@@ -845,10 +836,10 @@ String.prototype.nobr = function()
*/
String.format = function()
{
var a = [ ];
const a = [ ];
for (var i = 1; i < arguments.length; i++)
a.push(arguments[i]);
for (let ar of arguments)
a.push(ar);
return ''.format.apply(arguments[0], a);
}
@@ -862,10 +853,10 @@ String.format = function()
*/
String.nobr = function()
{
var a = [ ];
const a = [ ];
for (var i = 1; i < arguments.length; i++)
a.push(arguments[i]);
for (let ar of arguments)
a.push(ar);
return ''.nobr.apply(arguments[0], a);
}
@@ -927,7 +918,7 @@ function cbi_dropdown_init(sb) {
if (sb && L.dom.findClassInstance(sb) instanceof L.ui.Dropdown)
return;
var dl = new L.ui.Dropdown(sb, null, { name: sb.getAttribute('name') });
const dl = new L.ui.Dropdown(sb, null, { name: sb.getAttribute('name') });
return dl.bind(sb);
}
@@ -938,12 +929,12 @@ function cbi_dropdown_init(sb) {
* @param {string} [placeholder] - Placeholder text when empty.
*/
function cbi_update_table(table, data, placeholder) {
var target = isElem(table) ? table : document.querySelector(table);
const target = isElem(table) ? table : document.querySelector(table);
if (!isElem(target))
return;
var t = L.dom.findClassInstance(target);
let t = L.dom.findClassInstance(target);
if (!(t instanceof L.ui.Table)) {
t = new L.ui.Table(target);

View File

@@ -33,52 +33,43 @@
* @property {string} [stderr] - The stderr produced by the command, if any
*/
var callFileList, callFileStat, callFileRead, callFileWrite, callFileRemove,
callFileExec, callFileMD5;
callFileList = rpc.declare({
const callFileList = rpc.declare({
object: 'file',
method: 'list',
params: [ 'path' ]
});
callFileStat = rpc.declare({
const callFileStat = rpc.declare({
object: 'file',
method: 'stat',
params: [ 'path' ]
});
callFileRead = rpc.declare({
const callFileRead = rpc.declare({
object: 'file',
method: 'read',
params: [ 'path' ]
});
callFileWrite = rpc.declare({
const callFileWrite = rpc.declare({
object: 'file',
method: 'write',
params: [ 'path', 'data', 'mode' ]
});
callFileRemove = rpc.declare({
const callFileRemove = rpc.declare({
object: 'file',
method: 'remove',
params: [ 'path' ]
});
callFileExec = rpc.declare({
const callFileExec = rpc.declare({
object: 'file',
method: 'exec',
params: [ 'command', 'params', 'env' ]
});
callFileMD5 = rpc.declare({
object: 'file',
method: 'md5',
params: [ 'path' ]
});
var rpcErrors = [
const rpcErrors = [
null,
'InvalidCommandError',
'InvalidArgumentError',
@@ -183,7 +174,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to an array of stat detail objects or
* rejecting with an error stating the failure reason.
*/
list: function(path) {
list(path) {
return callFileList(path).then(handleRpcReply.bind(this, { entries: [] }));
},
@@ -197,7 +188,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to a stat detail object or
* rejecting with an error stating the failure reason.
*/
stat: function(path) {
stat(path) {
return callFileStat(path).then(handleRpcReply.bind(this, { '': {} }));
},
@@ -212,7 +203,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to a string containing the file contents or
* rejecting with an error stating the failure reason.
*/
read: function(path) {
read(path) {
return callFileRead(path).then(handleRpcReply.bind(this, { data: '' }));
},
@@ -238,7 +229,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to `0` or rejecting with an error stating
* the failure reason.
*/
write: function(path, data, mode) {
write(path, data, mode) {
data = (data != null) ? String(data) : '';
mode = (mode != null) ? mode : 420; // 0644
return callFileWrite(path, data, mode).then(handleRpcReply.bind(this, { '': 0 }));
@@ -254,7 +245,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to `0` or rejecting with an error stating
* the failure reason.
*/
remove: function(path) {
remove(path) {
return callFileRemove(path).then(handleRpcReply.bind(this, { '': 0 }));
},
@@ -283,7 +274,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to an object describing the execution
* results or rejecting with an error stating the failure reason.
*/
exec: function(command, params, env) {
exec(command, params, env) {
if (!Array.isArray(params))
params = null;
@@ -311,7 +302,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to the file contents or the empty string
* on failure.
*/
trimmed: function(path) {
trimmed(path) {
return L.resolveDefault(this.read(path), '').then(function(s) {
return s.trim();
});
@@ -332,7 +323,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* Returns a promise resolving to an array containing the stripped lines
* of the given file or `[]` on failure.
*/
lines: function(path) {
lines(path) {
return L.resolveDefault(this.read(path), '').then(function(s) {
var lines = [];
@@ -373,7 +364,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* to the specified type or rejecting with an error stating the failure
* reason.
*/
read_direct: function(path, type) {
read_direct(path, type) {
var postdata = 'sessionid=%s&path=%s'
.format(encodeURIComponent(L.env.sessionid), encodeURIComponent(path));
@@ -430,7 +421,7 @@ var FileSystem = baseclass.extend(/** @lends LuCI.fs.prototype */ {
* according to the specified type or rejecting with an error stating the
* failure reason.
*/
exec_direct: function(command, params, type, latin1, stderr, responseProgress) {
exec_direct(command, params, type, latin1, stderr, responseProgress) {
var cmdstr = String(command)
.replace(/\\/g, '\\\\').replace(/(\s)/g, '\\$1');

File diff suppressed because it is too large Load Diff

View File

@@ -67,9 +67,9 @@ function calculateBroadcast(s, use_cfgvalue) {
* @returns {boolean}
*/
function validateBroadcast(section_id, value) {
var opt = this.map.lookupOption('broadcast', section_id),
node = opt ? this.map.findElement('id', opt[0].cbid(section_id)) : null,
addr = node ? calculateBroadcast(this.section, false) : null;
const opt = this.map.lookupOption('broadcast', section_id);
const node = opt ? this.map.findElement('id', opt[0].cbid(section_id)) : null;
const addr = node ? calculateBroadcast(this.section, false) : null;
if (node != null) {
if (addr != null)
@@ -83,38 +83,37 @@ function validateBroadcast(section_id, value) {
return network.registerProtocol('static', {
CBIIPValue: form.Value.extend({
handleSwitch: function(section_id, option_index, ev) {
var maskopt = this.map.lookupOption('netmask', section_id);
handleSwitch(section_id, option_index, ev) {
const maskopt = this.map.lookupOption('netmask', section_id);
if (maskopt == null || !this.isValid(section_id))
return;
var maskval = maskopt[0].formvalue(section_id),
addrval = this.formvalue(section_id),
prefix = maskval ? network.maskToPrefix(maskval) : 32;
const maskval = maskopt[0].formvalue(section_id);
const addrval = this.formvalue(section_id);
const prefix = maskval ? network.maskToPrefix(maskval) : 32;
if (prefix == null)
return;
this.datatype = 'or(cidr4,ipmask4)';
var parent = L.dom.parent(ev.target, '.cbi-value-field');
let parent = L.dom.parent(ev.target, '.cbi-value-field');
L.dom.content(parent, form.DynamicList.prototype.renderWidget.apply(this, [
section_id,
option_index,
addrval ? '%s/%d'.format(addrval, prefix) : ''
]));
var masknode = this.map.findElement('id', maskopt[0].cbid(section_id));
const masknode = this.map.findElement('id', maskopt[0].cbid(section_id));
if (masknode) {
parent = L.dom.parent(masknode, '.cbi-value');
parent.parentNode.removeChild(parent);
}
},
renderWidget: function(section_id, option_index, cfgvalue) {
var maskopt = this.map.lookupOption('netmask', section_id),
widget = isCIDR(cfgvalue) ? 'DynamicList' : 'Value';
renderWidget(section_id, option_index, cfgvalue) {
const widget = isCIDR(cfgvalue) ? 'DynamicList' : 'Value';
if (widget == 'DynamicList') {
this.datatype = 'or(cidr4,ipmask4)';
@@ -124,7 +123,7 @@ return network.registerProtocol('static', {
this.datatype = 'ip4addr("nomask")';
}
var node = form[widget].prototype.renderWidget.apply(this, [ section_id, option_index, cfgvalue ]);
const node = form[widget].prototype.renderWidget.apply(this, [ section_id, option_index, cfgvalue ]);
if (widget == 'Value')
L.dom.append(node, E('button', {
@@ -141,7 +140,7 @@ return network.registerProtocol('static', {
}),
CBINetmaskValue: form.Value.extend({
render: function(option_index, section_id, in_table) {
render(option_index, section_id, in_table) {
var addropt = this.section.children.filter(function(o) { return o.option == 'ipaddr' })[0],
addrval = addropt ? addropt.cfgvalue(section_id) : null;
@@ -162,7 +161,7 @@ return network.registerProtocol('static', {
CBIGatewayValue: form.Value.extend({
datatype: 'ip4addr("nomask")',
render: function(option_index, section_id, in_table) {
render(option_index, section_id, in_table) {
return network.getWANNetworks().then(L.bind(function(wans) {
if (wans.length == 1) {
var gwaddr = wans[0].getGatewayAddr();
@@ -173,13 +172,13 @@ return network.registerProtocol('static', {
}, this));
},
validate: function(section_id, value) {
var addropt = this.section.children.filter(function(o) { return o.option == 'ipaddr' })[0],
addrval = addropt ? L.toArray(addropt.cfgvalue(section_id)) : null;
validate(section_id, value) {
const addropt = this.section.children.filter(function(o) { return o.option == 'ipaddr' })[0];
const addrval = addropt ? L.toArray(addropt.cfgvalue(section_id)) : null;
if (addrval != null) {
for (var i = 0; i < addrval.length; i++) {
var addr = addrval[i].split('/')[0];
for (let a of addrval) {
const addr = a.split('/')[0];
if (value == addr)
return _('The gateway address must not be a local IP address');
}
@@ -192,18 +191,18 @@ return network.registerProtocol('static', {
CBIBroadcastValue: form.Value.extend({
datatype: 'ip4addr("nomask")',
render: function(option_index, section_id, in_table) {
render(option_index, section_id, in_table) {
this.placeholder = calculateBroadcast(this.section, true);
return form.Value.prototype.render.apply(this, [ option_index, section_id, in_table ]);
}
}),
getI18n: function() {
getI18n() {
return _('Static address');
},
renderFormOptions: function(s) {
var o;
renderFormOptions(s) {
let o;
s.taboption('general', this.CBIIPValue, 'ipaddr', _('IPv4 address'));
s.taboption('general', this.CBINetmaskValue, 'netmask', _('IPv4 netmask'));

View File

@@ -173,7 +173,7 @@ var CBILogreadBox = function(logtag, name) {
'class': 'cbi-input-select',
'style': 'margin-bottom:10px',
},
this.facilities.map(([_, val, label]) =>
this.facilities.map(([ , val, label]) =>
(val == 'any') ? E('option', { value: val, selected: '' }, label) : E('option', { value: val }, label)
));
@@ -189,7 +189,7 @@ var CBILogreadBox = function(logtag, name) {
'id': 'logSeveritySelect',
'class': 'cbi-input-select',
},
this.severity.map(([_, val, label]) =>
this.severity.map(([ , val, label]) =>
(val == 'any') ? E('option', { value: val, selected: '' }, label) : E('option', { value: val }, label)
));

View File

@@ -43,7 +43,7 @@ function getDevices(network) {
var CBIZoneSelect = form.ListValue.extend({
__name__: 'CBI.ZoneSelect',
load: function(section_id) {
load(section_id) {
return Promise.all([ firewall.getZones(), network.getNetworks() ]).then(L.bind(function(zn) {
this.zones = zn[0];
this.networks = zn[1];
@@ -52,22 +52,22 @@ var CBIZoneSelect = form.ListValue.extend({
}, this));
},
filter: function(section_id, value) {
filter(section_id, value) {
return true;
},
lookupZone: function(name) {
lookupZone(name) {
return this.zones.filter(function(zone) { return zone.getName() == name })[0];
},
lookupNetwork: function(name) {
lookupNetwork(name) {
return this.networks.filter(function(network) { return network.getName() == name })[0];
},
renderWidget: function(section_id, option_index, cfgvalue) {
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
isOutputOnly = false,
choices = {};
renderWidget(section_id, option_index, cfgvalue) {
const values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
let isOutputOnly = false;
const choices = {};
let datatype_str = 'ucifw4zonename';
if (!L.hasSystemFeature('firewall4'))
datatype_str = `and(${datatype_str},maxlength(11))`;
@@ -77,10 +77,10 @@ var CBIZoneSelect = form.ListValue.extend({
datatype_str = `list(${datatype_str})`;
if (this.option == 'dest') {
for (var i = 0; i < this.section.children.length; i++) {
var opt = this.section.children[i];
for (let c of this.section.children) {
const opt = c;
if (opt.option == 'src') {
var val = opt.cfgvalue(section_id) || opt.default;
const val = opt.cfgvalue(section_id) || opt.default;
isOutputOnly = (val == null || val == '');
break;
}
@@ -116,31 +116,30 @@ var CBIZoneSelect = form.ListValue.extend({
]);
}
for (var i = 0; i < this.zones.length; i++) {
var zone = this.zones[i],
name = zone.getName(),
networks = zone.getNetworks(),
ifaces = [];
for (let zone of this.zones) {
const name = zone.getName();
const networks = zone.getNetworks();
const ifaces = [];
if (!this.filter(section_id, name))
continue;
for (var j = 0; j < networks.length; j++) {
var network = this.lookupNetwork(networks[j]);
for (let n of networks) {
const network = this.lookupNetwork(n);
if (!network)
continue;
var span = E('span', {
const span = E('span', {
'class': 'ifacebadge' + (network.isUp() ? ' ifacebadge-active' : '')
}, network.getName() + ': ');
var devices = getDevices(network);
const devices = getDevices(network);
for (var k = 0; k < devices.length; k++) {
for (let d of devices) {
span.appendChild(E('img', {
'title': devices[k].getI18n(),
'src': L.resource('icons/%s%s.svg'.format(devices[k].getType(), devices[k].isUp() ? '' : '_disabled'))
'title': d.getI18n(),
'src': L.resource('icons/%s%s.svg'.format(d.getType(), d.isUp() ? '' : '_disabled'))
}));
}
@@ -159,7 +158,7 @@ var CBIZoneSelect = form.ListValue.extend({
}, [ E('strong', name) ].concat(ifaces));
}
var widget = new ui.Dropdown(values, choices, {
const widget = new ui.Dropdown(values, choices, {
id: this.cbid(section_id),
sort: true,
multiple: this.multiple,
@@ -179,19 +178,19 @@ var CBIZoneSelect = form.ListValue.extend({
'</li>'
});
var elem = widget.render();
const elem = widget.render();
if (this.option == 'src') {
elem.addEventListener('cbi-dropdown-change', L.bind(function(ev) {
var opt = this.map.lookupOption('dest', section_id),
val = ev.detail.instance.getValue();
const opt = this.map.lookupOption('dest', section_id);
const val = ev.detail.instance.getValue();
if (opt == null)
return;
var cbid = opt[0].cbid(section_id),
label = document.querySelector('label[for="widget.%s"]'.format(cbid)),
node = document.getElementById(cbid);
const cbid = opt[0].cbid(section_id);
const label = document.querySelector('label[for="widget.%s"]'.format(cbid));
const node = document.getElementById(cbid);
L.dom.content(label, val == '' ? _('Output zone') : _('Destination zone'));
@@ -199,8 +198,8 @@ var CBIZoneSelect = form.ListValue.extend({
if (L.dom.callClassMethod(node, 'getValue') == '')
L.dom.callClassMethod(node, 'setValue', '*');
var emptyval = node.querySelector('[data-value=""]'),
anyval = node.querySelector('[data-value="*"]');
const emptyval = node.querySelector('[data-value=""]');
const anyval = node.querySelector('[data-value="*"]');
L.dom.content(anyval.querySelector('span'), E('strong', _('Any zone')));
@@ -234,7 +233,7 @@ var CBIZoneSelect = form.ListValue.extend({
}, this));
}
else if (isOutputOnly) {
var emptyval = elem.querySelector('[data-value=""]');
const emptyval = elem.querySelector('[data-value=""]');
emptyval.parentNode.removeChild(emptyval);
}
@@ -245,7 +244,7 @@ var CBIZoneSelect = form.ListValue.extend({
var CBIZoneForwards = form.DummyValue.extend({
__name__: 'CBI.ZoneForwards',
load: function(section_id) {
load(section_id) {
return Promise.all([
firewall.getDefaults(),
firewall.getZones(),
@@ -261,29 +260,29 @@ var CBIZoneForwards = form.DummyValue.extend({
}, this));
},
renderZone: function(zone) {
var name = zone.getName(),
networks = zone.getNetworks(),
devices = zone.getDevices(),
subnets = zone.getSubnets(),
ifaces = [];
renderZone(zone) {
const name = zone.getName();
const networks = zone.getNetworks();
const devices = zone.getDevices();
const subnets = zone.getSubnets();
const ifaces = [];
for (var j = 0; j < networks.length; j++) {
var network = this.networks.filter(function(net) { return net.getName() == networks[j] })[0];
for (let n of networks) {
const network = this.networks.filter(function(net) { return net.getName() == n })[0];
if (!network)
continue;
var span = E('span', {
const span = E('span', {
'class': 'ifacebadge' + (network.isUp() ? ' ifacebadge-active' : '')
}, network.getName() + ': ');
var subdevs = getDevices(network);
const subdevs = getDevices(network);
for (var k = 0; k < subdevs.length && subdevs[k]; k++) {
for (let s of subdevs) {
span.appendChild(E('img', {
'title': subdevs[k].getI18n(),
'src': L.resource('icons/%s%s.svg'.format(subdevs[k].getType(), subdevs[k].isUp() ? '' : '_disabled'))
'title': s.getI18n(),
'src': L.resource('icons/%s%s.svg'.format(s.getType(), s.isUp() ? '' : '_disabled'))
}));
}
@@ -293,18 +292,18 @@ var CBIZoneForwards = form.DummyValue.extend({
ifaces.push(span);
}
for (var i = 0; i < devices.length; i++) {
var device = this.devices.filter(function(dev) { return dev.getName() == devices[i] })[0],
title = device ? device.getI18n() : _('Absent Interface'),
type = device ? device.getType() : 'ethernet',
up = device ? device.isUp() : false;
for (let d of devices) {
const device = this.devices.filter(function(dev) { return dev.getName() == d })[0];
const title = device ? device.getI18n() : _('Absent Interface');
const type = device ? device.getType() : 'ethernet';
const up = device ? device.isUp() : false;
ifaces.push(E('span', { 'class': 'ifacebadge' }, [
E('img', {
'title': title,
'src': L.resource('icons/%s%s.svg'.format(type, up ? '' : '_disabled'))
}),
device ? device.getName() : devices[i]
device ? device.getName() : d
]));
}
@@ -323,18 +322,18 @@ var CBIZoneForwards = form.DummyValue.extend({
]);
},
renderWidget: function(section_id, option_index, cfgvalue) {
var value = (cfgvalue != null) ? cfgvalue : this.default,
zone = this.zones.filter(function(z) { return z.getName() == value })[0];
renderWidget(section_id, option_index, cfgvalue) {
const value = (cfgvalue != null) ? cfgvalue : this.default;
const zone = this.zones.filter(function(z) { return z.getName() == value })[0];
if (!zone)
return E([]);
var forwards = zone.getForwardingsBy('src'),
dzones = [];
const forwards = zone.getForwardingsBy('src');
const dzones = [];
for (var i = 0; i < forwards.length; i++) {
var dzone = forwards[i].getDestinationZone();
const dzone = forwards[i].getDestinationZone();
if (!dzone)
continue;
@@ -464,7 +463,7 @@ const CBIIPSelect = form.ListValue.extend({
var CBINetworkSelect = form.ListValue.extend({
__name__: 'CBI.NetworkSelect',
load: function(section_id) {
load(section_id) {
return network.getNetworks().then(L.bind(function(networks) {
this.networks = networks;
@@ -472,18 +471,18 @@ var CBINetworkSelect = form.ListValue.extend({
}, this));
},
filter: function(section_id, value) {
filter(section_id, value) {
return true;
},
renderIfaceBadge: function(network) {
var span = E('span', { 'class': 'ifacebadge' }, network.getName() + ': '),
devices = getDevices(network);
renderIfaceBadge(network) {
const span = E('span', { 'class': 'ifacebadge' }, network.getName() + ': ');
const devices = getDevices(network);
for (var j = 0; j < devices.length && devices[j]; j++) {
for (let d of devices) {
span.appendChild(E('img', {
'title': devices[j].getI18n(),
'src': L.resource('icons/%s%s.svg'.format(devices[j].getType(), devices[j].isUp() ? '' : '_disabled'))
'title': d.getI18n(),
'src': L.resource('icons/%s%s.svg'.format(d.getType(), d.isUp() ? '' : '_disabled'))
}));
}
@@ -495,10 +494,10 @@ var CBINetworkSelect = form.ListValue.extend({
return span;
},
renderWidget: function(section_id, option_index, cfgvalue) {
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
choices = {},
checked = {};
renderWidget(section_id, option_index, cfgvalue) {
let values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
const choices = {};
const checked = {};
for (var i = 0; i < values.length; i++)
checked[values[i]] = true;
@@ -508,9 +507,8 @@ var CBINetworkSelect = form.ListValue.extend({
if (!this.multiple && (this.rmempty || this.optional))
choices[''] = E('em', _('unspecified'));
for (var i = 0; i < this.networks.length; i++) {
var network = this.networks[i],
name = network.getName();
for (let network of this.networks) {
const name = network.getName();
if (name == this.exclude || !this.filter(section_id, name))
continue;
@@ -527,7 +525,7 @@ var CBINetworkSelect = form.ListValue.extend({
choices[name] = this.renderIfaceBadge(network);
}
var widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
const widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
id: this.cbid(section_id),
sort: true,
multiple: this.multiple,
@@ -550,14 +548,13 @@ var CBINetworkSelect = form.ListValue.extend({
return widget.render();
},
textvalue: function(section_id) {
var cfgvalue = this.cfgvalue(section_id),
values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
rv = E([]);
textvalue(section_id) {
const cfgvalue = this.cfgvalue(section_id);
const values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
const rv = E([]);
for (var i = 0; i < (this.networks || []).length; i++) {
var network = this.networks[i],
name = network.getName();
for (let network of this.networks) {
const name = network.getName();
if (values.indexOf(name) == -1)
continue;
@@ -578,7 +575,7 @@ var CBINetworkSelect = form.ListValue.extend({
var CBIDeviceSelect = form.ListValue.extend({
__name__: 'CBI.DeviceSelect',
load: function(section_id) {
load(section_id) {
return Promise.all([
network.getDevices(),
this.noaliases ? null : network.getNetworks()
@@ -590,11 +587,11 @@ var CBIDeviceSelect = form.ListValue.extend({
}, this));
},
filter: function(section_id, value) {
filter(section_id, value) {
return true;
},
renderWidget: function(section_id, option_index, cfgvalue) {
renderWidget(section_id, option_index, cfgvalue) {
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
choices = {},
checked = {},
@@ -608,10 +605,9 @@ var CBIDeviceSelect = form.ListValue.extend({
if (!this.multiple && (this.rmempty || this.optional))
choices[''] = E('em', _('unspecified'));
for (var i = 0; i < this.devices.length; i++) {
var device = this.devices[i],
name = device.getName(),
type = device.getType();
for (let device of this.devices) {
const name = device.getName();
const type = device.getType();
if (name == 'lo' || name == this.exclude || !this.filter(section_id, name))
continue;
@@ -625,7 +621,7 @@ var CBIDeviceSelect = form.ListValue.extend({
if (this.noinactive && device.isUp() == false)
continue;
var item = E([
const item = E([
E('img', {
'title': device.getI18n(),
'src': L.resource('icons/%s%s.svg'.format(type, device.isUp() ? '' : '_disabled'))
@@ -634,7 +630,7 @@ var CBIDeviceSelect = form.ListValue.extend({
E('span', { 'class': 'hide-close'}, [ device.getI18n() ])
]);
var networks = device.getNetworks();
const networks = device.getNetworks();
if (networks.length > 0)
L.dom.append(item.lastChild, [ ' (', networks.map(function(n) { return n.getName() }).join(', '), ')' ]);
@@ -647,10 +643,9 @@ var CBIDeviceSelect = form.ListValue.extend({
}
if (this.networks != null) {
for (var i = 0; i < this.networks.length; i++) {
var net = this.networks[i],
device = network.instantiateDevice('@%s'.format(net.getName()), net),
name = device.getName();
for (let net of this.networks) {
const device = network.instantiateDevice('@%s'.format(net.getName()), net);
const name = device.getName();
if (name == '@loopback' || name == this.exclude || !this.filter(section_id, name))
continue;
@@ -658,7 +653,7 @@ var CBIDeviceSelect = form.ListValue.extend({
if (this.noinactive && net.isUp() == false)
continue;
var item = E([
const item = E([
E('img', {
'title': device.getI18n(),
'src': L.resource('icons/alias%s.svg'.format(device.isUp() ? '' : '_disabled'))
@@ -690,27 +685,27 @@ var CBIDeviceSelect = form.ListValue.extend({
}
if (!this.nocreate) {
var keys = Object.keys(checked).sort(L.naturalCompare);
const keys = Object.keys(checked).sort(L.naturalCompare);
for (var i = 0; i < keys.length; i++) {
if (choices.hasOwnProperty(keys[i]))
for (let k of keys) {
if (choices.hasOwnProperty(k))
continue;
choices[keys[i]] = E([
choices[k] = E([
E('img', {
'title': _('Absent Interface'),
'src': L.resource('icons/ethernet_disabled.svg')
}),
E('span', { 'class': 'hide-open' }, [ keys[i] ]),
E('span', { 'class': 'hide-close'}, [ '%s: "%h"'.format(_('Absent Interface'), keys[i]) ])
E('span', { 'class': 'hide-open' }, [ k ]),
E('span', { 'class': 'hide-close'}, [ '%s: "%h"'.format(_('Absent Interface'), k) ])
]);
values.push(keys[i]);
order.push(keys[i]);
values.push(k);
order.push(k);
}
}
var widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
const widget = new ui.Dropdown(this.multiple ? values : values[0], choices, {
id: this.cbid(section_id),
sort: order,
multiple: this.multiple,
@@ -736,7 +731,7 @@ var CBIDeviceSelect = form.ListValue.extend({
var CBIUserSelect = form.ListValue.extend({
__name__: 'CBI.UserSelect',
load: function(section_id) {
load(section_id) {
return getUsers().then(L.bind(function(users) {
delete this.keylist;
delete this.vallist;
@@ -748,7 +743,7 @@ var CBIUserSelect = form.ListValue.extend({
}, this));
},
filter: function(section_id, value) {
filter(section_id, value) {
return true;
},
});
@@ -756,7 +751,7 @@ var CBIUserSelect = form.ListValue.extend({
var CBIGroupSelect = form.ListValue.extend({
__name__: 'CBI.GroupSelect',
load: function(section_id) {
load(section_id) {
return getGroups().then(L.bind(function(groups) {
for (var i = 0; i < groups.length; i++) {
this.value(groups[i]);
@@ -766,7 +761,7 @@ var CBIGroupSelect = form.ListValue.extend({
}, this));
},
filter: function(section_id, value) {
filter(section_id, value) {
return true;
},
});

View File

@@ -905,7 +905,6 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* have been reloaded by the save operation.
*/
save() {
const v = this.state.values;
const n = this.state.creates;
const c = this.state.changes;
const d = this.state.deletes;

View File

@@ -20,11 +20,11 @@ var callFileList = rpc.declare({
network.registerPatternVirtual(/^3g-.+$/);
function write_keepalive(section_id, value) {
var f_opt = this.map.lookupOption('_keepalive_failure', section_id),
i_opt = this.map.lookupOption('_keepalive_interval', section_id),
f = parseInt(f_opt?.[0]?.formvalue(section_id), 10),
i = parseInt(i_opt?.[0]?.formvalue(section_id), 10);
function write_keepalive(section_id) {
const f_opt = this.map.lookupOption('_keepalive_failure', section_id);
const i_opt = this.map.lookupOption('_keepalive_interval', section_id);
let f = parseInt(f_opt?.[0]?.formvalue(section_id), 10);
let i = parseInt(i_opt?.[0]?.formvalue(section_id), 10);
if (isNaN(i))
i = 1;
@@ -68,18 +68,18 @@ return network.registerProtocol('3g', {
},
renderFormOptions: function(s) {
var o;
let o;
o = s.taboption('general', form.Value, '_modem_device', _('Modem device'));
o.ucioption = 'device';
o.rmempty = false;
o.load = function(section_id) {
return callFileList('/dev/').then(L.bind(function(devices) {
for (var i = 0; i < devices.length; i++)
for (let i = 0; i < devices.length; i++)
this.value(devices[i]);
return callFileList('/dev/tts/');
}, this)).then(L.bind(function(devices) {
for (var i = 0; i < devices.length; i++)
for (let i = 0; i < devices.length; i++)
this.value(devices[i]);
return form.Value.prototype.load.apply(this, [section_id]);
}, this));
@@ -133,9 +133,9 @@ return network.registerProtocol('3g', {
o.write = write_keepalive;
o.remove = write_keepalive;
o.cfgvalue = function(section_id) {
var v = uci.get('network', section_id, 'keepalive');
let v = uci.get('network', section_id, 'keepalive');
if (typeof(v) == 'string' && v != '') {
var m = v.match(/^(\d+)[ ,]\d+$/);
const m = v.match(/^(\d+)[ ,]\d+$/);
return m ? m[1] : v;
}
};
@@ -146,9 +146,9 @@ return network.registerProtocol('3g', {
o.write = write_keepalive;
o.remove = write_keepalive;
o.cfgvalue = function(section_id) {
var v = uci.get('network', section_id, 'keepalive');
let v = uci.get('network', section_id, 'keepalive');
if (typeof(v) == 'string' && v != '') {
var m = v.match(/^\d+[ ,](\d+)$/);
const m = v.match(/^\d+[ ,](\d+)$/);
return m ? m[1] : v;
}
};

View File

@@ -59,36 +59,35 @@ function validateCert(priv, section_id, value) {
}
return network.registerProtocol('openconnect', {
getI18n: function() {
getI18n() {
return _('OpenConnect');
},
getIfname: function() {
getIfname() {
return this._ubus('l3_device') || 'vpn-%s'.format(this.sid);
},
getPackageName: function() {
getPackageName() {
return 'openconnect';
},
isFloating: function() {
isFloating() {
return true;
},
isVirtual: function() {
isVirtual() {
return true;
},
getDevices: function() {
getDevices() {
return null;
},
containsDevice: function(ifname) {
containsDevice(ifname) {
return (network.getIfnameOf(ifname) == this.getIfname());
},
renderFormOptions: function(s) {
const dev = this.getDevice().getName();
renderFormOptions(s) {
let certLoadPromise = null;
let o;
@@ -104,7 +103,7 @@ return network.registerProtocol('openconnect', {
o = s.taboption('general', form.Value, 'uri', _('VPN Server'));
o.placeholder = 'https://example.com:443/usergroup';
o.validate = function(section_id, value) {
const m = String(value).match(/^(?:(\w+):\/\/|)(?:\[([0-9a-f:.]{2,45})\]|([^\/:]+))(?::([0-9]{1,5}))?(?:\/.*)?$/i);
const m = String(value).match(/^(?:(\w+):\/\/|)(?:\[([0-9a-f:.]{2,45})\]|([^/:]+))(?::([0-9]{1,5}))?(?:\/.*)?$/i);
if (!m)
return _('Invalid server URL');

View File

@@ -4,14 +4,14 @@
'require network';
'require tools.widgets as widgets';
var callGetCertificateFiles = rpc.declare({
const callGetCertificateFiles = rpc.declare({
object: 'luci.openfortivpn',
method: 'getCertificates',
params: [ 'interface' ],
expect: { '': {} }
});
var callSetCertificateFiles = rpc.declare({
const callSetCertificateFiles = rpc.declare({
object: 'luci.openfortivpn',
method: 'setCertificates',
params: [ 'interface', 'user_cert', 'user_key', 'ca_file' ],
@@ -38,9 +38,9 @@ function sanitizeCert(s) {
}
function validateCert(priv, section_id, value) {
var lines = value.trim().split(/[\r\n]/),
start = false,
i;
const lines = value.trim().split(/[\r\n]/);
let start = false;
let i;
if (value === null || value === '')
return true;
@@ -48,7 +48,7 @@ function validateCert(priv, section_id, value) {
for (i = 0; i < lines.length; i++) {
if (lines[i].match(/^-{5}BEGIN ((|RSA |DSA )PRIVATE KEY|(|TRUSTED |X509 )CERTIFICATE)-{5}$/))
start = true;
else if (start && !lines[i].match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/))
else if (start && !lines[i].match(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/))
break;
}
@@ -59,36 +59,36 @@ function validateCert(priv, section_id, value) {
}
return network.registerProtocol('openfortivpn', {
getI18n: function() {
getI18n() {
return _('OpenFortivpn');
},
getIfname: function() {
getIfname() {
return this._ubus('l3_device') || 'vpn-%s'.format(this.sid);
},
getPackageName: function() {
getPackageName() {
return 'openfortivpn';
},
isFloating: function() {
isFloating() {
return true;
},
isVirtual: function() {
isVirtual() {
return true;
},
getDevices: function() {
getDevices() {
return null;
},
containsDevice: function(ifname) {
containsDevice(ifname) {
return (network.getIfnameOf(ifname) == this.getIfname());
},
renderFormOptions: function(s) {
var o;
renderFormOptions(s) {
let o, certLoadPromise;
o = s.taboption('general', form.Value, 'peeraddr', _('VPN Server'));
o.datatype = 'host(0)';
@@ -108,7 +108,7 @@ return network.registerProtocol('openfortivpn', {
o.monospace = true;
o.validate = L.bind(validateCert, o, false);
o.load = function(section_id) {
var certLoadPromise = certLoadPromise || callGetCertificateFiles(section_id);
certLoadPromise = certLoadPromise || callGetCertificateFiles(section_id);
return certLoadPromise.then(function(certs) { return certs.user_cert });
};
o.write = function(section_id, value) {
@@ -121,7 +121,7 @@ return network.registerProtocol('openfortivpn', {
o.monospace = true;
o.validate = L.bind(validateCert, o, true);
o.load = function(section_id) {
var certLoadPromise = certLoadPromise || callGetCertificateFiles(section_id);
certLoadPromise = certLoadPromise || callGetCertificateFiles(section_id);
return certLoadPromise.then(function(certs) { return certs.user_key });
};
o.write = function(section_id, value) {
@@ -134,7 +134,7 @@ return network.registerProtocol('openfortivpn', {
o.monospace = true;
o.validate = L.bind(validateCert, o, false);
o.load = function(section_id) {
var certLoadPromise = certLoadPromise || callGetCertificateFiles(section_id);
certLoadPromise = certLoadPromise || callGetCertificateFiles(section_id);
return certLoadPromise.then(function(certs) { return certs.ca_file });
};
o.write = function(section_id, value) {

View File

@@ -7,17 +7,17 @@
network.registerPatternVirtual(/^relay-.+$/);
var RelayDevicePrototype = {
__init__: function(ifname, network) {
__init__(ifname, network) {
this.ifname = ifname;
this.network = network;
},
_aggregateDevices: function(fn, first) {
var devices = this.network ? this.network.getDevices() : [],
rv = 0;
_aggregateDevices(fn, first) {
const devices = this.network ? this.network.getDevices() : [];
let rv = 0;
for (var i = 0; i < devices.length; i++) {
var v = devices[i][fn].apply(devices[i]);
for (let d of devices) {
var v = d[fn].apply(d);
if (v != null) {
if (first)
@@ -30,88 +30,88 @@ var RelayDevicePrototype = {
return first ? null : [ rv, devices.length ];
},
getPorts: function() { return this.network ? this.network.getDevices() : [] },
getPorts() { return this.network ? this.network.getDevices() : [] },
getType: function() { return 'tunnel' },
getTypeI18n: function() { return _('Relay Bridge') },
getType() { return 'tunnel' },
getTypeI18n() { return _('Relay Bridge') },
getShortName: function() {
getShortName() {
return '%s "%h"'.format(_('Relay'), this.ifname);
},
isUp: function() {
isUp() {
var res = this._aggregateDevices('isUp');
return (res[1] > 0 && res[0] == res[1]);
},
getTXBytes: function() { return this._aggregateDevices('getTXBytes')[0] },
getRXBytes: function() { return this._aggregateDevices('getRXBytes')[0] },
getTXPackets: function() { return this._aggregateDevices('getTXPackets')[0] },
getRXPackets: function() { return this._aggregateDevices('getRXPackets')[0] },
getTXBytes() { return this._aggregateDevices('getTXBytes')[0] },
getRXBytes() { return this._aggregateDevices('getRXBytes')[0] },
getTXPackets() { return this._aggregateDevices('getTXPackets')[0] },
getRXPackets() { return this._aggregateDevices('getRXPackets')[0] },
getMAC: function() { return this._aggregateDevices('getMAC', true) },
getMAC() { return this._aggregateDevices('getMAC', true) },
getIPAddrs: function() {
getIPAddrs() {
var ipaddr = this.network ? L.toArray(uci.get('network', this.network.getName(), 'ipaddr'))[0] : null;
return (ipaddr != null ? [ ipaddr ] : []);
},
getIP6Addrs: function() { return [] }
getIP6Addrs() { return [] }
};
return network.registerProtocol('relay', {
getI18n: function() {
getI18n() {
return _('Relay bridge');
},
getIfname: function() {
getIfname() {
return 'relay-%s'.format(this.sid);
},
getPackageName: function() {
getPackageName() {
return 'relayd';
},
isFloating: function() {
isFloating() {
return true;
},
isVirtual: function() {
isVirtual() {
return true;
},
containsDevice: function(ifname) {
containsDevice(ifname) {
return (network.getIfnameOf(ifname) == this.getIfname());
},
isUp: function() {
isUp() {
var dev = this.getDevice();
return (dev ? dev.isUp() : false);
},
getDevice: function() {
getDevice() {
return network.instantiateDevice(this.sid, this, RelayDevicePrototype);
},
getDevices: function() {
getDevices() {
if (this.devices)
return this.devices;
var networkNames = L.toArray(uci.get('network', this.sid, 'network')),
deviceNames = L.toArray(uci.get('network', this.sid, 'ifname')),
devices = {},
rv = [];
const networkNames = L.toArray(uci.get('network', this.sid, 'network'));
let deviceNames = L.toArray(uci.get('network', this.sid, 'ifname'));
const devices = {};
const rv = [];
for (var i = 0; i < networkNames.length; i++) {
var net = network.instantiateNetwork(networkNames[i]),
for (let nn of networkNames) {
var net = network.instantiateNetwork(nn),
dev = net ? net.getDevice() : null;
if (dev)
devices[dev.getName()] = dev;
}
for (var i = 0; i < deviceNames.length; i++) {
var dev = network.getDevice(deviceNames[i]);
for (let dn of deviceNames) {
const dev = network.getDevice(dn);
if (dev)
devices[dev.getName()] = dev;
@@ -120,20 +120,20 @@ return network.registerProtocol('relay', {
deviceNames = Object.keys(devices);
deviceNames.sort();
for (var i = 0; i < deviceNames.length; i++)
rv.push(devices[deviceNames[i]]);
for (let dn of deviceNames)
rv.push(devices[dn]);
this.devices = rv;
return rv;
},
getUptime: function() {
var networkNames = L.toArray(uci.get('network', this.sid, 'network')),
uptime = 0;
getUptime() {
const networkNames = L.toArray(uci.get('network', this.sid, 'network'));
let uptime = 0;
for (var i = 0; i < networkNames.length; i++) {
var net = network.instantiateNetwork(networkNames[i]);
for (let nn of networkNames) {
const net = network.instantiateNetwork(nn);
if (net)
uptime = Math.max(uptime, net.getUptime());
}
@@ -141,11 +141,11 @@ return network.registerProtocol('relay', {
return uptime;
},
getErrors: function() {
getErrors() {
return null;
},
renderFormOptions: function(s) {
renderFormOptions(s) {
var o;
o = s.taboption('general', form.Value, 'ipaddr', _('Local IPv4 address'), _('Address to access local relay bridge'));

View File

@@ -34,7 +34,7 @@ function validateBase64(section_id, value) {
if (value.length == 0)
return true;
if (value.length != 44 || !value.match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/))
if (value.length != 44 || !value.match(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/))
return _('Invalid Base64 key string');
if (value[43] != "=" )
@@ -45,26 +45,17 @@ function validateBase64(section_id, value) {
var stubValidator = {
factory: validation,
apply: function(type, value, args) {
apply(type, value, args) {
if (value != null)
this.value = value;
return validation.types[type].apply(this, args);
},
assert: function(condition) {
assert(condition) {
return !!condition;
}
};
function generateDescription(name, texts) {
return E('li', { 'style': 'color: inherit;' }, [
E('span', name),
E('ul', texts.map(function (text) {
return E('li', { 'style': 'color: inherit;' }, text);
}))
]);
}
function buildSVGQRCode(data, code) {
// pixel size larger than 4 clips right and bottom edges of complex configs
const options = {
@@ -78,7 +69,7 @@ function buildSVGQRCode(data, code) {
}
var cbiKeyPairGenerate = form.DummyValue.extend({
cfgvalue: function(section_id, value) {
cfgvalue(section_id, value) {
return E('button', {
'class': 'btn',
'click': ui.createHandlerFn(this, function(section_id, ev) {
@@ -101,36 +92,36 @@ function handleWindowDragDropIgnore(ev) {
}
return network.registerProtocol('wireguard', {
getI18n: function() {
getI18n() {
return _('WireGuard VPN');
},
getIfname: function() {
getIfname() {
return this._ubus('l3_device') || this.sid;
},
getPackageName: function() {
getPackageName() {
return 'wireguard-tools';
},
isFloating: function() {
isFloating() {
return true;
},
isVirtual: function() {
isVirtual() {
return true;
},
getDevices: function() {
getDevices() {
return null;
},
containsDevice: function(ifname) {
containsDevice(ifname) {
return (network.getIfnameOf(ifname) == this.getIfname());
},
renderFormOptions: function(s) {
var o, ss, ss2;
renderFormOptions(s) {
var o, ss;
// -- general ---------------------------------------------------------------------
@@ -139,8 +130,6 @@ return network.registerProtocol('wireguard', {
o.validate = validateBase64;
o.rmempty = false;
var serverName = this.getIfname();
o = s.taboption('general', form.Value, 'public_key', _('Public Key'), _('Base64-encoded public key of this interface for sharing.'));
o.rmempty = false;
o.write = function() {/* write nothing */};
@@ -268,16 +257,16 @@ return network.registerProtocol('wireguard', {
if (config.interface_address) {
config.interface_address = config.interface_address.split(/[, ]+/);
for (var i = 0; i < config.interface_address.length; i++)
if (!stubValidator.apply('ipaddr', config.interface_address[i]))
for (let cfia of config.interface_address)
if (!stubValidator.apply('ipaddr', cfia))
return _('Address setting is invalid');
}
if (config.interface_dns) {
config.interface_dns = config.interface_dns.split(/[, ]+/);
for (var i = 0; i < config.interface_dns.length; i++)
if (!stubValidator.apply('ipaddr', config.interface_dns[i], ['nomask']))
for (let cfid of config.interface_dns)
if (!stubValidator.apply('ipaddr', cfid, ['nomask']))
return _('DNS setting is invalid');
}
@@ -287,9 +276,7 @@ return network.registerProtocol('wireguard', {
if (!stubValidator.apply('port', config.interface_listenport || '0'))
return _('ListenPort setting is invalid');
for (var i = 0; i < config.peers.length; i++) {
var pconf = config.peers[i];
for (let pconf of config.peers) {
if (pconf.peer_publickey != null && validateBase64(null, pconf.peer_publickey) !== true)
return _('PublicKey setting is invalid');
@@ -327,10 +314,10 @@ return network.registerProtocol('wireguard', {
};
ss.handleApplyConfig = function(mode, nodes, comment, ev) {
var input = nodes.querySelector('textarea').value,
error = nodes.querySelector('.alert-message'),
cancel = nodes.nextElementSibling.querySelector('.btn'),
config = this.parseConfig(input);
const input = nodes.querySelector('textarea').value;
const error = nodes.querySelector('.alert-message');
const cancel = nodes.nextElementSibling.querySelector('.btn');
const config = this.parseConfig(input);
if (typeof(config) == 'string') {
error.firstChild.data = _('Cannot parse configuration: %s').format(config);
@@ -339,7 +326,7 @@ return network.registerProtocol('wireguard', {
}
if (mode == 'full') {
var prv = s.formvalue(s.section, 'private_key');
const prv = s.formvalue(s.section, 'private_key');
if (prv && prv != config.interface_privatekey && !confirm(_('Overwrite the current settings with the imported configuration?')))
return;
@@ -353,9 +340,8 @@ return network.registerProtocol('wireguard', {
if (config.interface_dns)
s.getOption('dns').getUIElement(s.section).setValue(config.interface_dns);
for (var i = 0; i < config.peers.length; i++) {
var pconf = config.peers[i];
var sid = uci.add('network', 'wireguard_' + s.section);
for (let pconf of config.peers) {
const sid = uci.add('network', 'wireguard_' + s.section);
uci.sections('network', 'wireguard_' + s.section, function(peer) {
if (peer.public_key == pconf.peer_publickey)
@@ -381,8 +367,8 @@ return network.registerProtocol('wireguard', {
}
else {
return getPublicAndPrivateKeyFromPrivate(config.interface_privatekey).then(function(keypair) {
var sid = uci.add('network', 'wireguard_' + s.section);
var pub = s.formvalue(s.section, 'public_key');
const sid = uci.add('network', 'wireguard_' + s.section);
const pub = s.formvalue(s.section, 'public_key');
uci.sections('network', 'wireguard_' + s.section, function(peer) {
if (peer.public_key == keypair.pub)
@@ -393,9 +379,7 @@ return network.registerProtocol('wireguard', {
uci.set('network', sid, 'public_key', keypair.pub);
uci.set('network', sid, 'private_key', keypair.priv);
for (var i = 0; i < config.peers.length; i++) {
var pconf = config.peers[i];
for (let pconf of config.peers) {
if (pconf.peer_publickey == pub) {
uci.set('network', sid, 'preshared_key', pconf.peer_presharedkey);
uci.set('network', sid, 'allowed_ips', pconf.peer_allowedips);
@@ -412,11 +396,10 @@ return network.registerProtocol('wireguard', {
};
ss.handleConfigImport = function(mode) {
var mapNode = ss.getActiveModalMap(),
headNode = mapNode.parentNode.querySelector('h4'),
parent = this.map;
const mapNode = ss.getActiveModalMap();
const headNode = mapNode.parentNode.querySelector('h4');
var nodes = E('div', {
const nodes = E('div', {
'dragover': this.handleDragConfig,
'drop': this.handleDropConfig.bind(this, mode)
}, [
@@ -440,7 +423,7 @@ return network.registerProtocol('wireguard', {
}, [''])
]);
var cancelFn = function() {
const cancelFn = function() {
nodes.parentNode.removeChild(nodes.nextSibling);
nodes.parentNode.removeChild(nodes);
mapNode.classList.remove('hidden');
@@ -450,7 +433,7 @@ return network.registerProtocol('wireguard', {
window.removeEventListener('drop', handleWindowDragDropIgnore);
};
var a = nodes.querySelector('a.full-import');
const a = nodes.querySelector('a.full-import');
if (a) {
a.addEventListener('click', ui.createHandlerFn(this, function(mode) {
@@ -485,7 +468,7 @@ return network.registerProtocol('wireguard', {
};
ss.renderSectionAdd = function(/* ... */) {
var nodes = this.super('renderSectionAdd', arguments);
const nodes = this.super('renderSectionAdd', arguments);
nodes.appendChild(E('button', {
'class': 'btn',
@@ -510,14 +493,14 @@ return network.registerProtocol('wireguard', {
o.optional = true;
o.width = '30%';
o.textvalue = function(section_id) {
var dis = ss.getOption('disabled'),
pub = ss.getOption('public_key'),
prv = ss.getOption('private_key'),
psk = ss.getOption('preshared_key'),
name = this.cfgvalue(section_id),
key = pub.cfgvalue(section_id);
const dis = ss.getOption('disabled');
const pub = ss.getOption('public_key');
const prv = ss.getOption('private_key');
const psk = ss.getOption('preshared_key');
const name = this.cfgvalue(section_id);
const key = pub.cfgvalue(section_id);
var desc = [
const desc = [
E('p', [
name ? E('span', [ name ]) : E('em', [ _('Untitled peer') ])
])
@@ -566,8 +549,8 @@ return network.registerProtocol('wireguard', {
};
function handleKeyChange(ev, section_id, value) {
var prv = this.section.getUIElement(section_id, 'private_key'),
btn = this.map.findElement('.btn.qr-code');
const prv = this.section.getUIElement(section_id, 'private_key');
const btn = this.map.findElement('.btn.qr-code');
btn.disabled = (!prv.isValid() || !prv.getValue());
}
@@ -611,8 +594,8 @@ return network.registerProtocol('wireguard', {
o = ss.option(form.DynamicList, 'allowed_ips', _('Allowed IPs'), _("Optional. IP addresses and prefixes that this peer is allowed to use inside the tunnel. Usually the peer's tunnel IP addresses and the networks the peer routes through the tunnel."));
o.datatype = 'ipaddr';
o.textvalue = function(section_id) {
var ips = L.toArray(this.cfgvalue(section_id)),
list = [];
const ips = L.toArray(this.cfgvalue(section_id));
const list = [];
for (var i = 0; i < ips.length; i++) {
if (i > 7) {
@@ -650,8 +633,8 @@ return network.registerProtocol('wireguard', {
o.placeholder = 'vpn.example.com';
o.datatype = 'host';
o.textvalue = function(section_id) {
var host = this.cfgvalue(section_id),
port = this.section.cfgvalue(section_id, 'endpoint_port');
const host = this.cfgvalue(section_id);
const port = this.section.cfgvalue(section_id, 'endpoint_port');
return (host && port)
? '%h:%d'.format(host, port)
@@ -680,12 +663,12 @@ return network.registerProtocol('wireguard', {
o.modalonly = true;
o.createPeerConfig = function(section_id, endpoint, ips, eips, dns) {
var pub = s.formvalue(s.section, 'public_key'),
port = s.formvalue(s.section, 'listen_port') || '51820',
prv = this.section.formvalue(section_id, 'private_key'),
psk = this.section.formvalue(section_id, 'preshared_key'),
eport = this.section.formvalue(section_id, 'endpoint_port'),
keep = this.section.formvalue(section_id, 'persistent_keepalive');
const pub = s.formvalue(s.section, 'public_key');
const port = s.formvalue(s.section, 'listen_port') || '51820';
const prv = this.section.formvalue(section_id, 'private_key');
const psk = this.section.formvalue(section_id, 'preshared_key');
const eport = this.section.formvalue(section_id, 'endpoint_port');
const keep = this.section.formvalue(section_id, 'persistent_keepalive');
// If endpoint is IPv6 we must escape it with []
if (endpoint.indexOf(':') > 0) {
@@ -709,11 +692,11 @@ return network.registerProtocol('wireguard', {
};
o.handleGenerateQR = function(section_id, ev) {
var mapNode = ss.getActiveModalMap(),
headNode = mapNode.parentNode.querySelector('h4'),
configGenerator = this.createPeerConfig.bind(this, section_id),
parent = this.map,
eips = this.section.formvalue(section_id, 'allowed_ips');
const mapNode = ss.getActiveModalMap();
const headNode = mapNode.parentNode.querySelector('h4');
const configGenerator = this.createPeerConfig.bind(this, section_id);
const parent = this.map;
const eips = this.section.formvalue(section_id, 'allowed_ips');
return Promise.all([
network.getWANNetworks(),
@@ -722,8 +705,8 @@ return network.registerProtocol('wireguard', {
L.resolveDefault(uci.load('ddns')),
L.resolveDefault(uci.load('system')),
parent.save(null, true)
]).then(function(data) {
var hostnames = [];
]).then(function([wNets, w6Nets, lnet]) {
const hostnames = [];
uci.sections('ddns', 'service', function(s) {
if (typeof(s?.lookup_host) == 'string' && s?.enabled == '1')
@@ -735,25 +718,24 @@ return network.registerProtocol('wireguard', {
hostnames.push(s.hostname);
});
for (var i = 0; i < data[0].length; i++)
hostnames.push.apply(hostnames, data[0][i].getIPAddrs().map(function(ip) { return ip.split('/')[0] }));
for (let wNet of wNets)
hostnames.push.apply(hostnames, wNet.getIPAddrs().map(function(ip) { return ip.split('/')[0] }));
for (var i = 0; i < data[1].length; i++)
hostnames.push.apply(hostnames, data[1][i].getIP6Addrs().map(function(ip) { return ip.split('/')[0] }));
for (let w6Net of w6Nets)
hostnames.push.apply(hostnames, w6Net.getIP6Addrs().map(function(ip) { return ip.split('/')[0] }));
var ips = [ '0.0.0.0/0', '::/0' ];
const ips = [ '0.0.0.0/0', '::/0' ];
var dns = [];
const dns = [];
var lan = data[2];
if (lan) {
var lanIp = lan.getIPAddr();
if (lnet) {
const lanIp = lnet.getIPAddr();
if (lanIp) {
dns.unshift(lanIp)
}
}
var qrm, qrs, qro;
let qrm, qrs, qro;
qrm = new form.JSONMap({ config: { endpoint: hostnames[0], allowed_ips: ips, addresses: eips, dns_servers: dns } }, null, _('The generated configuration can be imported into a WireGuard client application to set up a connection towards this device.'));
qrm.parent = parent;
@@ -761,12 +743,12 @@ return network.registerProtocol('wireguard', {
qrs = qrm.section(form.NamedSection, 'config');
function handleConfigChange(ev, section_id, value) {
var code = this.map.findElement('.qr-code'),
conf = this.map.findElement('.client-config'),
endpoint = this.section.getUIElement(section_id, 'endpoint'),
ips = this.section.getUIElement(section_id, 'allowed_ips');
eips = this.section.getUIElement(section_id, 'addresses');
dns = this.section.getUIElement(section_id, 'dns_servers');
const code = this.map.findElement('.qr-code');
const conf = this.map.findElement('.client-config');
const endpoint = this.section.getUIElement(section_id, 'endpoint');
const ips = this.section.getUIElement(section_id, 'allowed_ips');
const eips = this.section.getUIElement(section_id, 'addresses');
const dns = this.section.getUIElement(section_id, 'dns_servers');
if (this.isValid(section_id)) {
conf.firstChild.data = configGenerator(endpoint.getValue(), ips.getValue(), eips.getValue(), dns.getValue());
@@ -800,9 +782,9 @@ return network.registerProtocol('wireguard', {
qro = qrs.option(form.DummyValue, 'output');
qro.renderWidget = function() {
var peer_config = configGenerator(hostnames[0], ips, eips, dns);
const peer_config = configGenerator(hostnames[0], ips, eips, dns);
var node = E('div', {
const node = E('div', {
'style': 'display:flex;flex-wrap:wrap;align-items:center;gap:.5em;width:100%'
}, [
E('div', {
@@ -814,9 +796,9 @@ return network.registerProtocol('wireguard', {
E('pre', {
'class': 'client-config',
'style': 'flex:1;white-space:pre;overflow:auto',
'click': function(ev) {
var sel = window.getSelection(),
range = document.createRange();
'click'(ev) {
const sel = window.getSelection();
const range = document.createRange();
range.selectNodeContents(ev.currentTarget);
@@ -849,7 +831,7 @@ return network.registerProtocol('wireguard', {
}, [
E('button', {
'class': 'btn',
'click': function() {
'click'() {
// Remove QR code button (row)
nodes.parentNode.removeChild(nodes.nextSibling);
// Remove QR code form
@@ -891,7 +873,7 @@ return network.registerProtocol('wireguard', {
};
},
deleteConfiguration: function() {
deleteConfiguration() {
uci.sections('network', 'wireguard_%s'.format(this.sid), function(s) {
uci.remove('network', s['.name']);
});