mirror of
https://github.com/openwrt/luci.git
synced 2026-04-15 10:51:51 +00:00
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:
@@ -19,8 +19,8 @@
|
|||||||
* defined here are registered as global `window.*` symbols.
|
* defined here are registered as global `window.*` symbols.
|
||||||
* @module LuCI.cbi
|
* @module LuCI.cbi
|
||||||
*/
|
*/
|
||||||
var cbi_d = [];
|
const cbi_d = [];
|
||||||
var cbi_strings = { path: {}, label: {} };
|
const cbi_strings = { path: {}, label: {} };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read signed 8-bit integer from a byte array at the given offset.
|
* 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).
|
* @returns {number} Signed 8-bit value (returned as unsigned number).
|
||||||
*/
|
*/
|
||||||
function s8(bytes, off) {
|
function s8(bytes, off) {
|
||||||
var n = bytes[off];
|
const n = bytes[off];
|
||||||
return (n > 0x7F) ? (n - 256) >>> 0 : n;
|
return (n > 0x7F) ? (n - 256) >>> 0 : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,10 +53,10 @@ function sfh(s) {
|
|||||||
if (s === null || s.length === 0)
|
if (s === null || s.length === 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var bytes = [];
|
const bytes = [];
|
||||||
|
|
||||||
for (var i = 0; i < s.length; i++) {
|
for (let i = 0; i < s.length; i++) {
|
||||||
var ch = s.charCodeAt(i);
|
let ch = s.charCodeAt(i);
|
||||||
|
|
||||||
// Handle surrogate pairs
|
// Handle surrogate pairs
|
||||||
if (ch >= 0xD800 && ch <= 0xDBFF && i + 1 < s.length) {
|
if (ch >= 0xD800 && ch <= 0xDBFF && i + 1 < s.length) {
|
||||||
@@ -86,9 +86,9 @@ function sfh(s) {
|
|||||||
if (!bytes.length)
|
if (!bytes.length)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var hash = (bytes.length >>> 0),
|
let hash = (bytes.length >>> 0);
|
||||||
len = (bytes.length >>> 2),
|
let len = (bytes.length >>> 2);
|
||||||
off = 0, tmp;
|
let off = 0, tmp;
|
||||||
|
|
||||||
while (len--) {
|
while (len--) {
|
||||||
hash += u16(bytes, off);
|
hash += u16(bytes, off);
|
||||||
@@ -300,7 +300,7 @@ function cbi_d_update() {
|
|||||||
* placeholders with interactive widgets.
|
* placeholders with interactive widgets.
|
||||||
*/
|
*/
|
||||||
function cbi_init() {
|
function cbi_init() {
|
||||||
var nodes;
|
let nodes;
|
||||||
|
|
||||||
document.querySelectorAll('.cbi-dropdown').forEach(function(node) {
|
document.querySelectorAll('.cbi-dropdown').forEach(function(node) {
|
||||||
cbi_dropdown_init(node);
|
cbi_dropdown_init(node);
|
||||||
@@ -309,65 +309,65 @@ function cbi_init() {
|
|||||||
|
|
||||||
nodes = document.querySelectorAll('[data-strings]');
|
nodes = document.querySelectorAll('[data-strings]');
|
||||||
|
|
||||||
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
|
for (let n of nodes) {
|
||||||
var str = JSON.parse(node.getAttribute('data-strings'));
|
const str = JSON.parse(n.getAttribute('data-strings'));
|
||||||
for (var key in str) {
|
for (let key in str) {
|
||||||
for (var key2 in str[key]) {
|
for (let key2 in str[key]) {
|
||||||
var dst = cbi_strings[key] || (cbi_strings[key] = { });
|
const dst = cbi_strings[key] || (cbi_strings[key] = { });
|
||||||
dst[key2] = str[key][key2];
|
dst[key2] = str[key][key2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = document.querySelectorAll('[data-depends]');
|
nodes = document.querySelectorAll('[data-depends]');
|
||||||
|
|
||||||
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
|
for (let n of nodes) {
|
||||||
var index = parseInt(node.getAttribute('data-index'), 10);
|
const index = parseInt(n.getAttribute('data-index'), 10);
|
||||||
var depends = JSON.parse(node.getAttribute('data-depends'));
|
const depends = JSON.parse(n.getAttribute('data-depends'));
|
||||||
if (!isNaN(index) && depends.length > 0) {
|
if (!isNaN(index) && depends.length > 0) {
|
||||||
for (let alt = 0; alt < depends.length; alt++)
|
for (let a of depends)
|
||||||
cbi_d_add(node, depends[alt], index);
|
cbi_d_add(n, depends[a], index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = document.querySelectorAll('[data-update]');
|
nodes = document.querySelectorAll('[data-update]');
|
||||||
|
|
||||||
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
|
for (let n of nodes) {
|
||||||
var events = node.getAttribute('data-update').split(' ');
|
const events = n.getAttribute('data-update').split(' ');
|
||||||
for (let j = 0, event; (event = events[j]) !== undefined; j++)
|
for (let ev of events)
|
||||||
node.addEventListener(event, cbi_d_update);
|
n.addEventListener(ev, cbi_d_update);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = document.querySelectorAll('[data-choices]');
|
nodes = document.querySelectorAll('[data-choices]');
|
||||||
|
|
||||||
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
|
for (let node of nodes) {
|
||||||
let choices = JSON.parse(node.getAttribute('data-choices')),
|
const choices = JSON.parse(node.getAttribute('data-choices'));
|
||||||
options = {};
|
const options = {};
|
||||||
|
|
||||||
for (let j = 0; j < choices[0].length; j++)
|
for (let j = 0; j < choices[0].length; j++)
|
||||||
options[choices[0][j]] = choices[1][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;
|
? 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'),
|
name: node.getAttribute('name'),
|
||||||
sort: choices[0],
|
sort: choices[0],
|
||||||
select_placeholder: def || _('-- Please choose --'),
|
select_placeholder: def || _('-- Please choose --'),
|
||||||
custom_placeholder: node.getAttribute('data-manual') || _('-- custom --')
|
custom_placeholder: node.getAttribute('data-manual') || _('-- custom --')
|
||||||
});
|
});
|
||||||
|
|
||||||
var n = cb.render();
|
const n = cb.render();
|
||||||
n.addEventListener('cbi-dropdown-change', cbi_d_update);
|
n.addEventListener('cbi-dropdown-change', cbi_d_update);
|
||||||
node.parentNode.replaceChild(n, node);
|
node.parentNode.replaceChild(n, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = document.querySelectorAll('[data-dynlist]');
|
nodes = document.querySelectorAll('[data-dynlist]');
|
||||||
|
|
||||||
for (let i = 0, node; (node = nodes[i]) !== undefined; i++) {
|
for (let node of nodes) {
|
||||||
let choices = JSON.parse(node.getAttribute('data-dynlist')),
|
const choices = JSON.parse(node.getAttribute('data-dynlist'));
|
||||||
values = JSON.parse(node.getAttribute('data-values') || '[]'),
|
const values = JSON.parse(node.getAttribute('data-values') || '[]');
|
||||||
options = null;
|
let options = null;
|
||||||
|
|
||||||
if (choices[0] && choices[0].length) {
|
if (choices[0] && choices[0].length) {
|
||||||
options = {};
|
options = {};
|
||||||
@@ -391,7 +391,7 @@ function cbi_init() {
|
|||||||
|
|
||||||
nodes = document.querySelectorAll('[data-type]');
|
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',
|
cbi_validate_field(node, node.getAttribute('data-optional') === 'true',
|
||||||
node.getAttribute('data-type'));
|
node.getAttribute('data-type'));
|
||||||
}
|
}
|
||||||
@@ -415,9 +415,9 @@ function cbi_init() {
|
|||||||
var tasks = [];
|
var tasks = [];
|
||||||
|
|
||||||
document.querySelectorAll('[data-ui-widget]').forEach(function(node) {
|
document.querySelectorAll('[data-ui-widget]').forEach(function(node) {
|
||||||
let args = JSON.parse(node.getAttribute('data-ui-widget') || '[]'),
|
const args = JSON.parse(node.getAttribute('data-ui-widget') || '[]');
|
||||||
widget = new (Function.prototype.bind.apply(L.ui[args[0]], args)),
|
const widget = new (Function.prototype.bind.apply(L.ui[args[0]], args));
|
||||||
markup = widget.render();
|
const markup = widget.render();
|
||||||
|
|
||||||
tasks.push(Promise.resolve(markup).then(function(markup) {
|
tasks.push(Promise.resolve(markup).then(function(markup) {
|
||||||
markup.addEventListener('widget-change', cbi_d_update);
|
markup.addEventListener('widget-change', cbi_d_update);
|
||||||
@@ -441,8 +441,8 @@ function cbi_validate_form(form, errmsg)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (form.cbi_validators) {
|
if (form.cbi_validators) {
|
||||||
for (var i = 0; i < form.cbi_validators.length; i++) {
|
for (let fv of form.cbi_validators) {
|
||||||
var validator = form.cbi_validators[i];
|
const validator = fv;
|
||||||
|
|
||||||
if (!validator() && errmsg) {
|
if (!validator() && errmsg) {
|
||||||
alert(errmsg);
|
alert(errmsg);
|
||||||
@@ -584,10 +584,10 @@ function cbi_row_swap(elem, up, store)
|
|||||||
*/
|
*/
|
||||||
function cbi_tag_last(container)
|
function cbi_tag_last(container)
|
||||||
{
|
{
|
||||||
var last;
|
let last;
|
||||||
|
|
||||||
for (var i = 0; i < container.childNodes.length; i++) {
|
for (let cn of container.childNodes) {
|
||||||
var c = container.childNodes[i];
|
var c = cn;
|
||||||
if (matchesElem(c, 'div')) {
|
if (matchesElem(c, 'div')) {
|
||||||
c.classList.remove('cbi-value-last');
|
c.classList.remove('cbi-value-last');
|
||||||
last = c;
|
last = c;
|
||||||
@@ -608,7 +608,7 @@ function cbi_tag_last(container)
|
|||||||
*/
|
*/
|
||||||
function cbi_submit(elem, name, value, action)
|
function cbi_submit(elem, name, value, action)
|
||||||
{
|
{
|
||||||
var form = elem.form || findParent(elem, 'form');
|
const form = elem.form || findParent(elem, 'form');
|
||||||
|
|
||||||
if (!form)
|
if (!form)
|
||||||
return false;
|
return false;
|
||||||
@@ -644,8 +644,8 @@ String.prototype.format = function()
|
|||||||
if (!RegExp)
|
if (!RegExp)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var html_esc = [/&/g, '&', /"/g, '"', /'/g, ''', /</g, '<', />/g, '>'];
|
const html_esc = [/&/g, '&', /"/g, '"', /'/g, ''', /</g, '<', />/g, '>'];
|
||||||
var quot_esc = [/"/g, '"', /'/g, '''];
|
const quot_esc = [/"/g, '"', /'/g, '''];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escape a string.
|
* Escape a string.
|
||||||
@@ -656,7 +656,7 @@ String.prototype.format = function()
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function esc(s, r) {
|
function esc(s, r) {
|
||||||
var t = typeof(s);
|
const t = typeof(s);
|
||||||
|
|
||||||
if (s == null || t === 'object' || t === 'function')
|
if (s == null || t === 'object' || t === 'function')
|
||||||
return '';
|
return '';
|
||||||
@@ -664,32 +664,31 @@ String.prototype.format = function()
|
|||||||
if (t !== 'string')
|
if (t !== 'string')
|
||||||
s = String(s);
|
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]);
|
s = s.replace(r[i], r[i+1]);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
var str = this;
|
let str = this;
|
||||||
var out = '';
|
let subst, n, pad;
|
||||||
var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
|
let out = '';
|
||||||
var a = b = [], numSubstitutions = 0, numMatches = 0;
|
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) {
|
while ((a = re.exec(str)) !== null) {
|
||||||
var m = a[1];
|
const m = a[1];
|
||||||
var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
|
let leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
|
||||||
var pPrecision = a[6], pType = a[7];
|
let pPrecision = a[6], pType = a[7];
|
||||||
|
|
||||||
numMatches++;
|
|
||||||
|
|
||||||
if (pType == '%') {
|
if (pType == '%') {
|
||||||
subst = '%';
|
subst = '%';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (numSubstitutions < arguments.length) {
|
if (numSubstitutions < arguments.length) {
|
||||||
var param = arguments[numSubstitutions++];
|
let param = arguments[numSubstitutions++];
|
||||||
|
|
||||||
var pad = '';
|
pad = '';
|
||||||
if (pPad && pPad.substr(0,1) == "'")
|
if (pPad && pPad.substr(0,1) == "'")
|
||||||
pad = leftpart.substr(1,1);
|
pad = leftpart.substr(1,1);
|
||||||
else if (pPad)
|
else if (pPad)
|
||||||
@@ -697,19 +696,11 @@ String.prototype.format = function()
|
|||||||
else
|
else
|
||||||
pad = ' ';
|
pad = ' ';
|
||||||
|
|
||||||
var justifyRight = true;
|
|
||||||
if (pJustify && pJustify === "-")
|
|
||||||
justifyRight = false;
|
|
||||||
|
|
||||||
var minLength = -1;
|
|
||||||
if (pMinLength)
|
|
||||||
minLength = +pMinLength;
|
|
||||||
|
|
||||||
var precision = -1;
|
var precision = -1;
|
||||||
if (pPrecision && pType == 'f')
|
if (pPrecision && pType == 'f')
|
||||||
precision = +pPrecision.substring(1);
|
precision = +pPrecision.substring(1);
|
||||||
|
|
||||||
var subst = param;
|
subst = param;
|
||||||
|
|
||||||
switch(pType) {
|
switch(pType) {
|
||||||
case 'b':
|
case 'b':
|
||||||
@@ -725,7 +716,7 @@ String.prototype.format = function()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
var n = +param || 0;
|
n = +param || 0;
|
||||||
subst = Math.floor((n < 0) ? 0x100000000 + n : n).toFixed(0);
|
subst = Math.floor((n < 0) ? 0x100000000 + n : n).toFixed(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -845,10 +836,10 @@ String.prototype.nobr = function()
|
|||||||
*/
|
*/
|
||||||
String.format = function()
|
String.format = function()
|
||||||
{
|
{
|
||||||
var a = [ ];
|
const a = [ ];
|
||||||
|
|
||||||
for (var i = 1; i < arguments.length; i++)
|
for (let ar of arguments)
|
||||||
a.push(arguments[i]);
|
a.push(ar);
|
||||||
|
|
||||||
return ''.format.apply(arguments[0], a);
|
return ''.format.apply(arguments[0], a);
|
||||||
}
|
}
|
||||||
@@ -862,10 +853,10 @@ String.format = function()
|
|||||||
*/
|
*/
|
||||||
String.nobr = function()
|
String.nobr = function()
|
||||||
{
|
{
|
||||||
var a = [ ];
|
const a = [ ];
|
||||||
|
|
||||||
for (var i = 1; i < arguments.length; i++)
|
for (let ar of arguments)
|
||||||
a.push(arguments[i]);
|
a.push(ar);
|
||||||
|
|
||||||
return ''.nobr.apply(arguments[0], a);
|
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)
|
if (sb && L.dom.findClassInstance(sb) instanceof L.ui.Dropdown)
|
||||||
return;
|
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);
|
return dl.bind(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,12 +929,12 @@ function cbi_dropdown_init(sb) {
|
|||||||
* @param {string} [placeholder] - Placeholder text when empty.
|
* @param {string} [placeholder] - Placeholder text when empty.
|
||||||
*/
|
*/
|
||||||
function cbi_update_table(table, data, placeholder) {
|
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))
|
if (!isElem(target))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var t = L.dom.findClassInstance(target);
|
let t = L.dom.findClassInstance(target);
|
||||||
|
|
||||||
if (!(t instanceof L.ui.Table)) {
|
if (!(t instanceof L.ui.Table)) {
|
||||||
t = new L.ui.Table(target);
|
t = new L.ui.Table(target);
|
||||||
|
|||||||
@@ -33,52 +33,43 @@
|
|||||||
* @property {string} [stderr] - The stderr produced by the command, if any
|
* @property {string} [stderr] - The stderr produced by the command, if any
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var callFileList, callFileStat, callFileRead, callFileWrite, callFileRemove,
|
const callFileList = rpc.declare({
|
||||||
callFileExec, callFileMD5;
|
|
||||||
|
|
||||||
callFileList = rpc.declare({
|
|
||||||
object: 'file',
|
object: 'file',
|
||||||
method: 'list',
|
method: 'list',
|
||||||
params: [ 'path' ]
|
params: [ 'path' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
callFileStat = rpc.declare({
|
const callFileStat = rpc.declare({
|
||||||
object: 'file',
|
object: 'file',
|
||||||
method: 'stat',
|
method: 'stat',
|
||||||
params: [ 'path' ]
|
params: [ 'path' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
callFileRead = rpc.declare({
|
const callFileRead = rpc.declare({
|
||||||
object: 'file',
|
object: 'file',
|
||||||
method: 'read',
|
method: 'read',
|
||||||
params: [ 'path' ]
|
params: [ 'path' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
callFileWrite = rpc.declare({
|
const callFileWrite = rpc.declare({
|
||||||
object: 'file',
|
object: 'file',
|
||||||
method: 'write',
|
method: 'write',
|
||||||
params: [ 'path', 'data', 'mode' ]
|
params: [ 'path', 'data', 'mode' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
callFileRemove = rpc.declare({
|
const callFileRemove = rpc.declare({
|
||||||
object: 'file',
|
object: 'file',
|
||||||
method: 'remove',
|
method: 'remove',
|
||||||
params: [ 'path' ]
|
params: [ 'path' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
callFileExec = rpc.declare({
|
const callFileExec = rpc.declare({
|
||||||
object: 'file',
|
object: 'file',
|
||||||
method: 'exec',
|
method: 'exec',
|
||||||
params: [ 'command', 'params', 'env' ]
|
params: [ 'command', 'params', 'env' ]
|
||||||
});
|
});
|
||||||
|
|
||||||
callFileMD5 = rpc.declare({
|
const rpcErrors = [
|
||||||
object: 'file',
|
|
||||||
method: 'md5',
|
|
||||||
params: [ 'path' ]
|
|
||||||
});
|
|
||||||
|
|
||||||
var rpcErrors = [
|
|
||||||
null,
|
null,
|
||||||
'InvalidCommandError',
|
'InvalidCommandError',
|
||||||
'InvalidArgumentError',
|
'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
|
* Returns a promise resolving to an array of stat detail objects or
|
||||||
* rejecting with an error stating the failure reason.
|
* rejecting with an error stating the failure reason.
|
||||||
*/
|
*/
|
||||||
list: function(path) {
|
list(path) {
|
||||||
return callFileList(path).then(handleRpcReply.bind(this, { entries: [] }));
|
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
|
* Returns a promise resolving to a stat detail object or
|
||||||
* rejecting with an error stating the failure reason.
|
* rejecting with an error stating the failure reason.
|
||||||
*/
|
*/
|
||||||
stat: function(path) {
|
stat(path) {
|
||||||
return callFileStat(path).then(handleRpcReply.bind(this, { '': {} }));
|
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
|
* Returns a promise resolving to a string containing the file contents or
|
||||||
* rejecting with an error stating the failure reason.
|
* rejecting with an error stating the failure reason.
|
||||||
*/
|
*/
|
||||||
read: function(path) {
|
read(path) {
|
||||||
return callFileRead(path).then(handleRpcReply.bind(this, { data: '' }));
|
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
|
* Returns a promise resolving to `0` or rejecting with an error stating
|
||||||
* the failure reason.
|
* the failure reason.
|
||||||
*/
|
*/
|
||||||
write: function(path, data, mode) {
|
write(path, data, mode) {
|
||||||
data = (data != null) ? String(data) : '';
|
data = (data != null) ? String(data) : '';
|
||||||
mode = (mode != null) ? mode : 420; // 0644
|
mode = (mode != null) ? mode : 420; // 0644
|
||||||
return callFileWrite(path, data, mode).then(handleRpcReply.bind(this, { '': 0 }));
|
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
|
* Returns a promise resolving to `0` or rejecting with an error stating
|
||||||
* the failure reason.
|
* the failure reason.
|
||||||
*/
|
*/
|
||||||
remove: function(path) {
|
remove(path) {
|
||||||
return callFileRemove(path).then(handleRpcReply.bind(this, { '': 0 }));
|
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
|
* Returns a promise resolving to an object describing the execution
|
||||||
* results or rejecting with an error stating the failure reason.
|
* results or rejecting with an error stating the failure reason.
|
||||||
*/
|
*/
|
||||||
exec: function(command, params, env) {
|
exec(command, params, env) {
|
||||||
if (!Array.isArray(params))
|
if (!Array.isArray(params))
|
||||||
params = null;
|
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
|
* Returns a promise resolving to the file contents or the empty string
|
||||||
* on failure.
|
* on failure.
|
||||||
*/
|
*/
|
||||||
trimmed: function(path) {
|
trimmed(path) {
|
||||||
return L.resolveDefault(this.read(path), '').then(function(s) {
|
return L.resolveDefault(this.read(path), '').then(function(s) {
|
||||||
return s.trim();
|
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
|
* Returns a promise resolving to an array containing the stripped lines
|
||||||
* of the given file or `[]` on failure.
|
* of the given file or `[]` on failure.
|
||||||
*/
|
*/
|
||||||
lines: function(path) {
|
lines(path) {
|
||||||
return L.resolveDefault(this.read(path), '').then(function(s) {
|
return L.resolveDefault(this.read(path), '').then(function(s) {
|
||||||
var lines = [];
|
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
|
* to the specified type or rejecting with an error stating the failure
|
||||||
* reason.
|
* reason.
|
||||||
*/
|
*/
|
||||||
read_direct: function(path, type) {
|
read_direct(path, type) {
|
||||||
var postdata = 'sessionid=%s&path=%s'
|
var postdata = 'sessionid=%s&path=%s'
|
||||||
.format(encodeURIComponent(L.env.sessionid), encodeURIComponent(path));
|
.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
|
* according to the specified type or rejecting with an error stating the
|
||||||
* failure reason.
|
* failure reason.
|
||||||
*/
|
*/
|
||||||
exec_direct: function(command, params, type, latin1, stderr, responseProgress) {
|
exec_direct(command, params, type, latin1, stderr, responseProgress) {
|
||||||
var cmdstr = String(command)
|
var cmdstr = String(command)
|
||||||
.replace(/\\/g, '\\\\').replace(/(\s)/g, '\\$1');
|
.replace(/\\/g, '\\\\').replace(/(\s)/g, '\\$1');
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -67,9 +67,9 @@ function calculateBroadcast(s, use_cfgvalue) {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function validateBroadcast(section_id, value) {
|
function validateBroadcast(section_id, value) {
|
||||||
var opt = this.map.lookupOption('broadcast', section_id),
|
const opt = this.map.lookupOption('broadcast', section_id);
|
||||||
node = opt ? this.map.findElement('id', opt[0].cbid(section_id)) : null,
|
const node = opt ? this.map.findElement('id', opt[0].cbid(section_id)) : null;
|
||||||
addr = node ? calculateBroadcast(this.section, false) : null;
|
const addr = node ? calculateBroadcast(this.section, false) : null;
|
||||||
|
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
if (addr != null)
|
if (addr != null)
|
||||||
@@ -83,38 +83,37 @@ function validateBroadcast(section_id, value) {
|
|||||||
|
|
||||||
return network.registerProtocol('static', {
|
return network.registerProtocol('static', {
|
||||||
CBIIPValue: form.Value.extend({
|
CBIIPValue: form.Value.extend({
|
||||||
handleSwitch: function(section_id, option_index, ev) {
|
handleSwitch(section_id, option_index, ev) {
|
||||||
var maskopt = this.map.lookupOption('netmask', section_id);
|
const maskopt = this.map.lookupOption('netmask', section_id);
|
||||||
|
|
||||||
if (maskopt == null || !this.isValid(section_id))
|
if (maskopt == null || !this.isValid(section_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var maskval = maskopt[0].formvalue(section_id),
|
const maskval = maskopt[0].formvalue(section_id);
|
||||||
addrval = this.formvalue(section_id),
|
const addrval = this.formvalue(section_id);
|
||||||
prefix = maskval ? network.maskToPrefix(maskval) : 32;
|
const prefix = maskval ? network.maskToPrefix(maskval) : 32;
|
||||||
|
|
||||||
if (prefix == null)
|
if (prefix == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.datatype = 'or(cidr4,ipmask4)';
|
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, [
|
L.dom.content(parent, form.DynamicList.prototype.renderWidget.apply(this, [
|
||||||
section_id,
|
section_id,
|
||||||
option_index,
|
option_index,
|
||||||
addrval ? '%s/%d'.format(addrval, prefix) : ''
|
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) {
|
if (masknode) {
|
||||||
parent = L.dom.parent(masknode, '.cbi-value');
|
parent = L.dom.parent(masknode, '.cbi-value');
|
||||||
parent.parentNode.removeChild(parent);
|
parent.parentNode.removeChild(parent);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
var maskopt = this.map.lookupOption('netmask', section_id),
|
const widget = isCIDR(cfgvalue) ? 'DynamicList' : 'Value';
|
||||||
widget = isCIDR(cfgvalue) ? 'DynamicList' : 'Value';
|
|
||||||
|
|
||||||
if (widget == 'DynamicList') {
|
if (widget == 'DynamicList') {
|
||||||
this.datatype = 'or(cidr4,ipmask4)';
|
this.datatype = 'or(cidr4,ipmask4)';
|
||||||
@@ -124,7 +123,7 @@ return network.registerProtocol('static', {
|
|||||||
this.datatype = 'ip4addr("nomask")';
|
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')
|
if (widget == 'Value')
|
||||||
L.dom.append(node, E('button', {
|
L.dom.append(node, E('button', {
|
||||||
@@ -141,7 +140,7 @@ return network.registerProtocol('static', {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
CBINetmaskValue: form.Value.extend({
|
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],
|
var addropt = this.section.children.filter(function(o) { return o.option == 'ipaddr' })[0],
|
||||||
addrval = addropt ? addropt.cfgvalue(section_id) : null;
|
addrval = addropt ? addropt.cfgvalue(section_id) : null;
|
||||||
|
|
||||||
@@ -162,7 +161,7 @@ return network.registerProtocol('static', {
|
|||||||
CBIGatewayValue: form.Value.extend({
|
CBIGatewayValue: form.Value.extend({
|
||||||
datatype: 'ip4addr("nomask")',
|
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) {
|
return network.getWANNetworks().then(L.bind(function(wans) {
|
||||||
if (wans.length == 1) {
|
if (wans.length == 1) {
|
||||||
var gwaddr = wans[0].getGatewayAddr();
|
var gwaddr = wans[0].getGatewayAddr();
|
||||||
@@ -173,13 +172,13 @@ return network.registerProtocol('static', {
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
validate: function(section_id, value) {
|
validate(section_id, value) {
|
||||||
var addropt = this.section.children.filter(function(o) { return o.option == 'ipaddr' })[0],
|
const addropt = this.section.children.filter(function(o) { return o.option == 'ipaddr' })[0];
|
||||||
addrval = addropt ? L.toArray(addropt.cfgvalue(section_id)) : null;
|
const addrval = addropt ? L.toArray(addropt.cfgvalue(section_id)) : null;
|
||||||
|
|
||||||
if (addrval != null) {
|
if (addrval != null) {
|
||||||
for (var i = 0; i < addrval.length; i++) {
|
for (let a of addrval) {
|
||||||
var addr = addrval[i].split('/')[0];
|
const addr = a.split('/')[0];
|
||||||
if (value == addr)
|
if (value == addr)
|
||||||
return _('The gateway address must not be a local IP address');
|
return _('The gateway address must not be a local IP address');
|
||||||
}
|
}
|
||||||
@@ -192,18 +191,18 @@ return network.registerProtocol('static', {
|
|||||||
CBIBroadcastValue: form.Value.extend({
|
CBIBroadcastValue: form.Value.extend({
|
||||||
datatype: 'ip4addr("nomask")',
|
datatype: 'ip4addr("nomask")',
|
||||||
|
|
||||||
render: function(option_index, section_id, in_table) {
|
render(option_index, section_id, in_table) {
|
||||||
this.placeholder = calculateBroadcast(this.section, true);
|
this.placeholder = calculateBroadcast(this.section, true);
|
||||||
return form.Value.prototype.render.apply(this, [ option_index, section_id, in_table ]);
|
return form.Value.prototype.render.apply(this, [ option_index, section_id, in_table ]);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getI18n: function() {
|
getI18n() {
|
||||||
return _('Static address');
|
return _('Static address');
|
||||||
},
|
},
|
||||||
|
|
||||||
renderFormOptions: function(s) {
|
renderFormOptions(s) {
|
||||||
var o;
|
let o;
|
||||||
|
|
||||||
s.taboption('general', this.CBIIPValue, 'ipaddr', _('IPv4 address'));
|
s.taboption('general', this.CBIIPValue, 'ipaddr', _('IPv4 address'));
|
||||||
s.taboption('general', this.CBINetmaskValue, 'netmask', _('IPv4 netmask'));
|
s.taboption('general', this.CBINetmaskValue, 'netmask', _('IPv4 netmask'));
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ var CBILogreadBox = function(logtag, name) {
|
|||||||
'class': 'cbi-input-select',
|
'class': 'cbi-input-select',
|
||||||
'style': 'margin-bottom:10px',
|
'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)
|
(val == 'any') ? E('option', { value: val, selected: '' }, label) : E('option', { value: val }, label)
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ var CBILogreadBox = function(logtag, name) {
|
|||||||
'id': 'logSeveritySelect',
|
'id': 'logSeveritySelect',
|
||||||
'class': 'cbi-input-select',
|
'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)
|
(val == 'any') ? E('option', { value: val, selected: '' }, label) : E('option', { value: val }, label)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ function getDevices(network) {
|
|||||||
var CBIZoneSelect = form.ListValue.extend({
|
var CBIZoneSelect = form.ListValue.extend({
|
||||||
__name__: 'CBI.ZoneSelect',
|
__name__: 'CBI.ZoneSelect',
|
||||||
|
|
||||||
load: function(section_id) {
|
load(section_id) {
|
||||||
return Promise.all([ firewall.getZones(), network.getNetworks() ]).then(L.bind(function(zn) {
|
return Promise.all([ firewall.getZones(), network.getNetworks() ]).then(L.bind(function(zn) {
|
||||||
this.zones = zn[0];
|
this.zones = zn[0];
|
||||||
this.networks = zn[1];
|
this.networks = zn[1];
|
||||||
@@ -52,22 +52,22 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
filter: function(section_id, value) {
|
filter(section_id, value) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupZone: function(name) {
|
lookupZone(name) {
|
||||||
return this.zones.filter(function(zone) { return zone.getName() == name })[0];
|
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];
|
return this.networks.filter(function(network) { return network.getName() == name })[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
|
const values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
|
||||||
isOutputOnly = false,
|
let isOutputOnly = false;
|
||||||
choices = {};
|
const choices = {};
|
||||||
let datatype_str = 'ucifw4zonename';
|
let datatype_str = 'ucifw4zonename';
|
||||||
if (!L.hasSystemFeature('firewall4'))
|
if (!L.hasSystemFeature('firewall4'))
|
||||||
datatype_str = `and(${datatype_str},maxlength(11))`;
|
datatype_str = `and(${datatype_str},maxlength(11))`;
|
||||||
@@ -77,10 +77,10 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
datatype_str = `list(${datatype_str})`;
|
datatype_str = `list(${datatype_str})`;
|
||||||
|
|
||||||
if (this.option == 'dest') {
|
if (this.option == 'dest') {
|
||||||
for (var i = 0; i < this.section.children.length; i++) {
|
for (let c of this.section.children) {
|
||||||
var opt = this.section.children[i];
|
const opt = c;
|
||||||
if (opt.option == 'src') {
|
if (opt.option == 'src') {
|
||||||
var val = opt.cfgvalue(section_id) || opt.default;
|
const val = opt.cfgvalue(section_id) || opt.default;
|
||||||
isOutputOnly = (val == null || val == '');
|
isOutputOnly = (val == null || val == '');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -116,31 +116,30 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < this.zones.length; i++) {
|
for (let zone of this.zones) {
|
||||||
var zone = this.zones[i],
|
const name = zone.getName();
|
||||||
name = zone.getName(),
|
const networks = zone.getNetworks();
|
||||||
networks = zone.getNetworks(),
|
const ifaces = [];
|
||||||
ifaces = [];
|
|
||||||
|
|
||||||
if (!this.filter(section_id, name))
|
if (!this.filter(section_id, name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (var j = 0; j < networks.length; j++) {
|
for (let n of networks) {
|
||||||
var network = this.lookupNetwork(networks[j]);
|
const network = this.lookupNetwork(n);
|
||||||
|
|
||||||
if (!network)
|
if (!network)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var span = E('span', {
|
const span = E('span', {
|
||||||
'class': 'ifacebadge' + (network.isUp() ? ' ifacebadge-active' : '')
|
'class': 'ifacebadge' + (network.isUp() ? ' ifacebadge-active' : '')
|
||||||
}, network.getName() + ': ');
|
}, 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', {
|
span.appendChild(E('img', {
|
||||||
'title': devices[k].getI18n(),
|
'title': d.getI18n(),
|
||||||
'src': L.resource('icons/%s%s.svg'.format(devices[k].getType(), devices[k].isUp() ? '' : '_disabled'))
|
'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));
|
}, [ E('strong', name) ].concat(ifaces));
|
||||||
}
|
}
|
||||||
|
|
||||||
var widget = new ui.Dropdown(values, choices, {
|
const widget = new ui.Dropdown(values, choices, {
|
||||||
id: this.cbid(section_id),
|
id: this.cbid(section_id),
|
||||||
sort: true,
|
sort: true,
|
||||||
multiple: this.multiple,
|
multiple: this.multiple,
|
||||||
@@ -179,19 +178,19 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
'</li>'
|
'</li>'
|
||||||
});
|
});
|
||||||
|
|
||||||
var elem = widget.render();
|
const elem = widget.render();
|
||||||
|
|
||||||
if (this.option == 'src') {
|
if (this.option == 'src') {
|
||||||
elem.addEventListener('cbi-dropdown-change', L.bind(function(ev) {
|
elem.addEventListener('cbi-dropdown-change', L.bind(function(ev) {
|
||||||
var opt = this.map.lookupOption('dest', section_id),
|
const opt = this.map.lookupOption('dest', section_id);
|
||||||
val = ev.detail.instance.getValue();
|
const val = ev.detail.instance.getValue();
|
||||||
|
|
||||||
if (opt == null)
|
if (opt == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var cbid = opt[0].cbid(section_id),
|
const cbid = opt[0].cbid(section_id);
|
||||||
label = document.querySelector('label[for="widget.%s"]'.format(cbid)),
|
const label = document.querySelector('label[for="widget.%s"]'.format(cbid));
|
||||||
node = document.getElementById(cbid);
|
const node = document.getElementById(cbid);
|
||||||
|
|
||||||
L.dom.content(label, val == '' ? _('Output zone') : _('Destination zone'));
|
L.dom.content(label, val == '' ? _('Output zone') : _('Destination zone'));
|
||||||
|
|
||||||
@@ -199,8 +198,8 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
if (L.dom.callClassMethod(node, 'getValue') == '')
|
if (L.dom.callClassMethod(node, 'getValue') == '')
|
||||||
L.dom.callClassMethod(node, 'setValue', '*');
|
L.dom.callClassMethod(node, 'setValue', '*');
|
||||||
|
|
||||||
var emptyval = node.querySelector('[data-value=""]'),
|
const emptyval = node.querySelector('[data-value=""]');
|
||||||
anyval = node.querySelector('[data-value="*"]');
|
const anyval = node.querySelector('[data-value="*"]');
|
||||||
|
|
||||||
L.dom.content(anyval.querySelector('span'), E('strong', _('Any zone')));
|
L.dom.content(anyval.querySelector('span'), E('strong', _('Any zone')));
|
||||||
|
|
||||||
@@ -234,7 +233,7 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
}
|
}
|
||||||
else if (isOutputOnly) {
|
else if (isOutputOnly) {
|
||||||
var emptyval = elem.querySelector('[data-value=""]');
|
const emptyval = elem.querySelector('[data-value=""]');
|
||||||
emptyval.parentNode.removeChild(emptyval);
|
emptyval.parentNode.removeChild(emptyval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +244,7 @@ var CBIZoneSelect = form.ListValue.extend({
|
|||||||
var CBIZoneForwards = form.DummyValue.extend({
|
var CBIZoneForwards = form.DummyValue.extend({
|
||||||
__name__: 'CBI.ZoneForwards',
|
__name__: 'CBI.ZoneForwards',
|
||||||
|
|
||||||
load: function(section_id) {
|
load(section_id) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
firewall.getDefaults(),
|
firewall.getDefaults(),
|
||||||
firewall.getZones(),
|
firewall.getZones(),
|
||||||
@@ -261,29 +260,29 @@ var CBIZoneForwards = form.DummyValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
renderZone: function(zone) {
|
renderZone(zone) {
|
||||||
var name = zone.getName(),
|
const name = zone.getName();
|
||||||
networks = zone.getNetworks(),
|
const networks = zone.getNetworks();
|
||||||
devices = zone.getDevices(),
|
const devices = zone.getDevices();
|
||||||
subnets = zone.getSubnets(),
|
const subnets = zone.getSubnets();
|
||||||
ifaces = [];
|
const ifaces = [];
|
||||||
|
|
||||||
for (var j = 0; j < networks.length; j++) {
|
for (let n of networks) {
|
||||||
var network = this.networks.filter(function(net) { return net.getName() == networks[j] })[0];
|
const network = this.networks.filter(function(net) { return net.getName() == n })[0];
|
||||||
|
|
||||||
if (!network)
|
if (!network)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var span = E('span', {
|
const span = E('span', {
|
||||||
'class': 'ifacebadge' + (network.isUp() ? ' ifacebadge-active' : '')
|
'class': 'ifacebadge' + (network.isUp() ? ' ifacebadge-active' : '')
|
||||||
}, network.getName() + ': ');
|
}, 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', {
|
span.appendChild(E('img', {
|
||||||
'title': subdevs[k].getI18n(),
|
'title': s.getI18n(),
|
||||||
'src': L.resource('icons/%s%s.svg'.format(subdevs[k].getType(), subdevs[k].isUp() ? '' : '_disabled'))
|
'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);
|
ifaces.push(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < devices.length; i++) {
|
for (let d of devices) {
|
||||||
var device = this.devices.filter(function(dev) { return dev.getName() == devices[i] })[0],
|
const device = this.devices.filter(function(dev) { return dev.getName() == d })[0];
|
||||||
title = device ? device.getI18n() : _('Absent Interface'),
|
const title = device ? device.getI18n() : _('Absent Interface');
|
||||||
type = device ? device.getType() : 'ethernet',
|
const type = device ? device.getType() : 'ethernet';
|
||||||
up = device ? device.isUp() : false;
|
const up = device ? device.isUp() : false;
|
||||||
|
|
||||||
ifaces.push(E('span', { 'class': 'ifacebadge' }, [
|
ifaces.push(E('span', { 'class': 'ifacebadge' }, [
|
||||||
E('img', {
|
E('img', {
|
||||||
'title': title,
|
'title': title,
|
||||||
'src': L.resource('icons/%s%s.svg'.format(type, up ? '' : '_disabled'))
|
'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) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
var value = (cfgvalue != null) ? cfgvalue : this.default,
|
const value = (cfgvalue != null) ? cfgvalue : this.default;
|
||||||
zone = this.zones.filter(function(z) { return z.getName() == value })[0];
|
const zone = this.zones.filter(function(z) { return z.getName() == value })[0];
|
||||||
|
|
||||||
if (!zone)
|
if (!zone)
|
||||||
return E([]);
|
return E([]);
|
||||||
|
|
||||||
var forwards = zone.getForwardingsBy('src'),
|
const forwards = zone.getForwardingsBy('src');
|
||||||
dzones = [];
|
const dzones = [];
|
||||||
|
|
||||||
for (var i = 0; i < forwards.length; i++) {
|
for (var i = 0; i < forwards.length; i++) {
|
||||||
var dzone = forwards[i].getDestinationZone();
|
const dzone = forwards[i].getDestinationZone();
|
||||||
|
|
||||||
if (!dzone)
|
if (!dzone)
|
||||||
continue;
|
continue;
|
||||||
@@ -464,7 +463,7 @@ const CBIIPSelect = form.ListValue.extend({
|
|||||||
var CBINetworkSelect = form.ListValue.extend({
|
var CBINetworkSelect = form.ListValue.extend({
|
||||||
__name__: 'CBI.NetworkSelect',
|
__name__: 'CBI.NetworkSelect',
|
||||||
|
|
||||||
load: function(section_id) {
|
load(section_id) {
|
||||||
return network.getNetworks().then(L.bind(function(networks) {
|
return network.getNetworks().then(L.bind(function(networks) {
|
||||||
this.networks = networks;
|
this.networks = networks;
|
||||||
|
|
||||||
@@ -472,18 +471,18 @@ var CBINetworkSelect = form.ListValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
filter: function(section_id, value) {
|
filter(section_id, value) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderIfaceBadge: function(network) {
|
renderIfaceBadge(network) {
|
||||||
var span = E('span', { 'class': 'ifacebadge' }, network.getName() + ': '),
|
const span = E('span', { 'class': 'ifacebadge' }, network.getName() + ': ');
|
||||||
devices = getDevices(network);
|
const devices = getDevices(network);
|
||||||
|
|
||||||
for (var j = 0; j < devices.length && devices[j]; j++) {
|
for (let d of devices) {
|
||||||
span.appendChild(E('img', {
|
span.appendChild(E('img', {
|
||||||
'title': devices[j].getI18n(),
|
'title': d.getI18n(),
|
||||||
'src': L.resource('icons/%s%s.svg'.format(devices[j].getType(), devices[j].isUp() ? '' : '_disabled'))
|
'src': L.resource('icons/%s%s.svg'.format(d.getType(), d.isUp() ? '' : '_disabled'))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,10 +494,10 @@ var CBINetworkSelect = form.ListValue.extend({
|
|||||||
return span;
|
return span;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
|
let values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
|
||||||
choices = {},
|
const choices = {};
|
||||||
checked = {};
|
const checked = {};
|
||||||
|
|
||||||
for (var i = 0; i < values.length; i++)
|
for (var i = 0; i < values.length; i++)
|
||||||
checked[values[i]] = true;
|
checked[values[i]] = true;
|
||||||
@@ -508,9 +507,8 @@ var CBINetworkSelect = form.ListValue.extend({
|
|||||||
if (!this.multiple && (this.rmempty || this.optional))
|
if (!this.multiple && (this.rmempty || this.optional))
|
||||||
choices[''] = E('em', _('unspecified'));
|
choices[''] = E('em', _('unspecified'));
|
||||||
|
|
||||||
for (var i = 0; i < this.networks.length; i++) {
|
for (let network of this.networks) {
|
||||||
var network = this.networks[i],
|
const name = network.getName();
|
||||||
name = network.getName();
|
|
||||||
|
|
||||||
if (name == this.exclude || !this.filter(section_id, name))
|
if (name == this.exclude || !this.filter(section_id, name))
|
||||||
continue;
|
continue;
|
||||||
@@ -527,7 +525,7 @@ var CBINetworkSelect = form.ListValue.extend({
|
|||||||
choices[name] = this.renderIfaceBadge(network);
|
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),
|
id: this.cbid(section_id),
|
||||||
sort: true,
|
sort: true,
|
||||||
multiple: this.multiple,
|
multiple: this.multiple,
|
||||||
@@ -550,14 +548,13 @@ var CBINetworkSelect = form.ListValue.extend({
|
|||||||
return widget.render();
|
return widget.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
textvalue: function(section_id) {
|
textvalue(section_id) {
|
||||||
var cfgvalue = this.cfgvalue(section_id),
|
const cfgvalue = this.cfgvalue(section_id);
|
||||||
values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
|
const values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
|
||||||
rv = E([]);
|
const rv = E([]);
|
||||||
|
|
||||||
for (var i = 0; i < (this.networks || []).length; i++) {
|
for (let network of this.networks) {
|
||||||
var network = this.networks[i],
|
const name = network.getName();
|
||||||
name = network.getName();
|
|
||||||
|
|
||||||
if (values.indexOf(name) == -1)
|
if (values.indexOf(name) == -1)
|
||||||
continue;
|
continue;
|
||||||
@@ -578,7 +575,7 @@ var CBINetworkSelect = form.ListValue.extend({
|
|||||||
var CBIDeviceSelect = form.ListValue.extend({
|
var CBIDeviceSelect = form.ListValue.extend({
|
||||||
__name__: 'CBI.DeviceSelect',
|
__name__: 'CBI.DeviceSelect',
|
||||||
|
|
||||||
load: function(section_id) {
|
load(section_id) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
network.getDevices(),
|
network.getDevices(),
|
||||||
this.noaliases ? null : network.getNetworks()
|
this.noaliases ? null : network.getNetworks()
|
||||||
@@ -590,11 +587,11 @@ var CBIDeviceSelect = form.ListValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
filter: function(section_id, value) {
|
filter(section_id, value) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget(section_id, option_index, cfgvalue) {
|
||||||
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
|
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default),
|
||||||
choices = {},
|
choices = {},
|
||||||
checked = {},
|
checked = {},
|
||||||
@@ -608,10 +605,9 @@ var CBIDeviceSelect = form.ListValue.extend({
|
|||||||
if (!this.multiple && (this.rmempty || this.optional))
|
if (!this.multiple && (this.rmempty || this.optional))
|
||||||
choices[''] = E('em', _('unspecified'));
|
choices[''] = E('em', _('unspecified'));
|
||||||
|
|
||||||
for (var i = 0; i < this.devices.length; i++) {
|
for (let device of this.devices) {
|
||||||
var device = this.devices[i],
|
const name = device.getName();
|
||||||
name = device.getName(),
|
const type = device.getType();
|
||||||
type = device.getType();
|
|
||||||
|
|
||||||
if (name == 'lo' || name == this.exclude || !this.filter(section_id, name))
|
if (name == 'lo' || name == this.exclude || !this.filter(section_id, name))
|
||||||
continue;
|
continue;
|
||||||
@@ -625,7 +621,7 @@ var CBIDeviceSelect = form.ListValue.extend({
|
|||||||
if (this.noinactive && device.isUp() == false)
|
if (this.noinactive && device.isUp() == false)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = E([
|
const item = E([
|
||||||
E('img', {
|
E('img', {
|
||||||
'title': device.getI18n(),
|
'title': device.getI18n(),
|
||||||
'src': L.resource('icons/%s%s.svg'.format(type, device.isUp() ? '' : '_disabled'))
|
'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() ])
|
E('span', { 'class': 'hide-close'}, [ device.getI18n() ])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var networks = device.getNetworks();
|
const networks = device.getNetworks();
|
||||||
|
|
||||||
if (networks.length > 0)
|
if (networks.length > 0)
|
||||||
L.dom.append(item.lastChild, [ ' (', networks.map(function(n) { return n.getName() }).join(', '), ')' ]);
|
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) {
|
if (this.networks != null) {
|
||||||
for (var i = 0; i < this.networks.length; i++) {
|
for (let net of this.networks) {
|
||||||
var net = this.networks[i],
|
const device = network.instantiateDevice('@%s'.format(net.getName()), net);
|
||||||
device = network.instantiateDevice('@%s'.format(net.getName()), net),
|
const name = device.getName();
|
||||||
name = device.getName();
|
|
||||||
|
|
||||||
if (name == '@loopback' || name == this.exclude || !this.filter(section_id, name))
|
if (name == '@loopback' || name == this.exclude || !this.filter(section_id, name))
|
||||||
continue;
|
continue;
|
||||||
@@ -658,7 +653,7 @@ var CBIDeviceSelect = form.ListValue.extend({
|
|||||||
if (this.noinactive && net.isUp() == false)
|
if (this.noinactive && net.isUp() == false)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = E([
|
const item = E([
|
||||||
E('img', {
|
E('img', {
|
||||||
'title': device.getI18n(),
|
'title': device.getI18n(),
|
||||||
'src': L.resource('icons/alias%s.svg'.format(device.isUp() ? '' : '_disabled'))
|
'src': L.resource('icons/alias%s.svg'.format(device.isUp() ? '' : '_disabled'))
|
||||||
@@ -690,27 +685,27 @@ var CBIDeviceSelect = form.ListValue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.nocreate) {
|
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++) {
|
for (let k of keys) {
|
||||||
if (choices.hasOwnProperty(keys[i]))
|
if (choices.hasOwnProperty(k))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
choices[keys[i]] = E([
|
choices[k] = E([
|
||||||
E('img', {
|
E('img', {
|
||||||
'title': _('Absent Interface'),
|
'title': _('Absent Interface'),
|
||||||
'src': L.resource('icons/ethernet_disabled.svg')
|
'src': L.resource('icons/ethernet_disabled.svg')
|
||||||
}),
|
}),
|
||||||
E('span', { 'class': 'hide-open' }, [ keys[i] ]),
|
E('span', { 'class': 'hide-open' }, [ k ]),
|
||||||
E('span', { 'class': 'hide-close'}, [ '%s: "%h"'.format(_('Absent Interface'), keys[i]) ])
|
E('span', { 'class': 'hide-close'}, [ '%s: "%h"'.format(_('Absent Interface'), k) ])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
values.push(keys[i]);
|
values.push(k);
|
||||||
order.push(keys[i]);
|
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),
|
id: this.cbid(section_id),
|
||||||
sort: order,
|
sort: order,
|
||||||
multiple: this.multiple,
|
multiple: this.multiple,
|
||||||
@@ -736,7 +731,7 @@ var CBIDeviceSelect = form.ListValue.extend({
|
|||||||
var CBIUserSelect = form.ListValue.extend({
|
var CBIUserSelect = form.ListValue.extend({
|
||||||
__name__: 'CBI.UserSelect',
|
__name__: 'CBI.UserSelect',
|
||||||
|
|
||||||
load: function(section_id) {
|
load(section_id) {
|
||||||
return getUsers().then(L.bind(function(users) {
|
return getUsers().then(L.bind(function(users) {
|
||||||
delete this.keylist;
|
delete this.keylist;
|
||||||
delete this.vallist;
|
delete this.vallist;
|
||||||
@@ -748,7 +743,7 @@ var CBIUserSelect = form.ListValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
filter: function(section_id, value) {
|
filter(section_id, value) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -756,7 +751,7 @@ var CBIUserSelect = form.ListValue.extend({
|
|||||||
var CBIGroupSelect = form.ListValue.extend({
|
var CBIGroupSelect = form.ListValue.extend({
|
||||||
__name__: 'CBI.GroupSelect',
|
__name__: 'CBI.GroupSelect',
|
||||||
|
|
||||||
load: function(section_id) {
|
load(section_id) {
|
||||||
return getGroups().then(L.bind(function(groups) {
|
return getGroups().then(L.bind(function(groups) {
|
||||||
for (var i = 0; i < groups.length; i++) {
|
for (var i = 0; i < groups.length; i++) {
|
||||||
this.value(groups[i]);
|
this.value(groups[i]);
|
||||||
@@ -766,7 +761,7 @@ var CBIGroupSelect = form.ListValue.extend({
|
|||||||
}, this));
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
filter: function(section_id, value) {
|
filter(section_id, value) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -905,7 +905,6 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
|
|||||||
* have been reloaded by the save operation.
|
* have been reloaded by the save operation.
|
||||||
*/
|
*/
|
||||||
save() {
|
save() {
|
||||||
const v = this.state.values;
|
|
||||||
const n = this.state.creates;
|
const n = this.state.creates;
|
||||||
const c = this.state.changes;
|
const c = this.state.changes;
|
||||||
const d = this.state.deletes;
|
const d = this.state.deletes;
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ var callFileList = rpc.declare({
|
|||||||
|
|
||||||
network.registerPatternVirtual(/^3g-.+$/);
|
network.registerPatternVirtual(/^3g-.+$/);
|
||||||
|
|
||||||
function write_keepalive(section_id, value) {
|
function write_keepalive(section_id) {
|
||||||
var f_opt = this.map.lookupOption('_keepalive_failure', section_id),
|
const f_opt = this.map.lookupOption('_keepalive_failure', section_id);
|
||||||
i_opt = this.map.lookupOption('_keepalive_interval', section_id),
|
const i_opt = this.map.lookupOption('_keepalive_interval', section_id);
|
||||||
f = parseInt(f_opt?.[0]?.formvalue(section_id), 10),
|
let f = parseInt(f_opt?.[0]?.formvalue(section_id), 10);
|
||||||
i = parseInt(i_opt?.[0]?.formvalue(section_id), 10);
|
let i = parseInt(i_opt?.[0]?.formvalue(section_id), 10);
|
||||||
|
|
||||||
if (isNaN(i))
|
if (isNaN(i))
|
||||||
i = 1;
|
i = 1;
|
||||||
@@ -68,18 +68,18 @@ return network.registerProtocol('3g', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderFormOptions: function(s) {
|
renderFormOptions: function(s) {
|
||||||
var o;
|
let o;
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, '_modem_device', _('Modem device'));
|
o = s.taboption('general', form.Value, '_modem_device', _('Modem device'));
|
||||||
o.ucioption = 'device';
|
o.ucioption = 'device';
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.load = function(section_id) {
|
o.load = function(section_id) {
|
||||||
return callFileList('/dev/').then(L.bind(function(devices) {
|
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]);
|
this.value(devices[i]);
|
||||||
return callFileList('/dev/tts/');
|
return callFileList('/dev/tts/');
|
||||||
}, this)).then(L.bind(function(devices) {
|
}, 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]);
|
this.value(devices[i]);
|
||||||
return form.Value.prototype.load.apply(this, [section_id]);
|
return form.Value.prototype.load.apply(this, [section_id]);
|
||||||
}, this));
|
}, this));
|
||||||
@@ -133,9 +133,9 @@ return network.registerProtocol('3g', {
|
|||||||
o.write = write_keepalive;
|
o.write = write_keepalive;
|
||||||
o.remove = write_keepalive;
|
o.remove = write_keepalive;
|
||||||
o.cfgvalue = function(section_id) {
|
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 != '') {
|
if (typeof(v) == 'string' && v != '') {
|
||||||
var m = v.match(/^(\d+)[ ,]\d+$/);
|
const m = v.match(/^(\d+)[ ,]\d+$/);
|
||||||
return m ? m[1] : v;
|
return m ? m[1] : v;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -146,9 +146,9 @@ return network.registerProtocol('3g', {
|
|||||||
o.write = write_keepalive;
|
o.write = write_keepalive;
|
||||||
o.remove = write_keepalive;
|
o.remove = write_keepalive;
|
||||||
o.cfgvalue = function(section_id) {
|
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 != '') {
|
if (typeof(v) == 'string' && v != '') {
|
||||||
var m = v.match(/^\d+[ ,](\d+)$/);
|
const m = v.match(/^\d+[ ,](\d+)$/);
|
||||||
return m ? m[1] : v;
|
return m ? m[1] : v;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,36 +59,35 @@ function validateCert(priv, section_id, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return network.registerProtocol('openconnect', {
|
return network.registerProtocol('openconnect', {
|
||||||
getI18n: function() {
|
getI18n() {
|
||||||
return _('OpenConnect');
|
return _('OpenConnect');
|
||||||
},
|
},
|
||||||
|
|
||||||
getIfname: function() {
|
getIfname() {
|
||||||
return this._ubus('l3_device') || 'vpn-%s'.format(this.sid);
|
return this._ubus('l3_device') || 'vpn-%s'.format(this.sid);
|
||||||
},
|
},
|
||||||
|
|
||||||
getPackageName: function() {
|
getPackageName() {
|
||||||
return 'openconnect';
|
return 'openconnect';
|
||||||
},
|
},
|
||||||
|
|
||||||
isFloating: function() {
|
isFloating() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
isVirtual: function() {
|
isVirtual() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
getDevices: function() {
|
getDevices() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
containsDevice: function(ifname) {
|
containsDevice(ifname) {
|
||||||
return (network.getIfnameOf(ifname) == this.getIfname());
|
return (network.getIfnameOf(ifname) == this.getIfname());
|
||||||
},
|
},
|
||||||
|
|
||||||
renderFormOptions: function(s) {
|
renderFormOptions(s) {
|
||||||
const dev = this.getDevice().getName();
|
|
||||||
let certLoadPromise = null;
|
let certLoadPromise = null;
|
||||||
let o;
|
let o;
|
||||||
|
|
||||||
@@ -104,7 +103,7 @@ return network.registerProtocol('openconnect', {
|
|||||||
o = s.taboption('general', form.Value, 'uri', _('VPN Server'));
|
o = s.taboption('general', form.Value, 'uri', _('VPN Server'));
|
||||||
o.placeholder = 'https://example.com:443/usergroup';
|
o.placeholder = 'https://example.com:443/usergroup';
|
||||||
o.validate = function(section_id, value) {
|
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)
|
if (!m)
|
||||||
return _('Invalid server URL');
|
return _('Invalid server URL');
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
'require network';
|
'require network';
|
||||||
'require tools.widgets as widgets';
|
'require tools.widgets as widgets';
|
||||||
|
|
||||||
var callGetCertificateFiles = rpc.declare({
|
const callGetCertificateFiles = rpc.declare({
|
||||||
object: 'luci.openfortivpn',
|
object: 'luci.openfortivpn',
|
||||||
method: 'getCertificates',
|
method: 'getCertificates',
|
||||||
params: [ 'interface' ],
|
params: [ 'interface' ],
|
||||||
expect: { '': {} }
|
expect: { '': {} }
|
||||||
});
|
});
|
||||||
|
|
||||||
var callSetCertificateFiles = rpc.declare({
|
const callSetCertificateFiles = rpc.declare({
|
||||||
object: 'luci.openfortivpn',
|
object: 'luci.openfortivpn',
|
||||||
method: 'setCertificates',
|
method: 'setCertificates',
|
||||||
params: [ 'interface', 'user_cert', 'user_key', 'ca_file' ],
|
params: [ 'interface', 'user_cert', 'user_key', 'ca_file' ],
|
||||||
@@ -38,9 +38,9 @@ function sanitizeCert(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function validateCert(priv, section_id, value) {
|
function validateCert(priv, section_id, value) {
|
||||||
var lines = value.trim().split(/[\r\n]/),
|
const lines = value.trim().split(/[\r\n]/);
|
||||||
start = false,
|
let start = false;
|
||||||
i;
|
let i;
|
||||||
|
|
||||||
if (value === null || value === '')
|
if (value === null || value === '')
|
||||||
return true;
|
return true;
|
||||||
@@ -48,7 +48,7 @@ function validateCert(priv, section_id, value) {
|
|||||||
for (i = 0; i < lines.length; i++) {
|
for (i = 0; i < lines.length; i++) {
|
||||||
if (lines[i].match(/^-{5}BEGIN ((|RSA |DSA )PRIVATE KEY|(|TRUSTED |X509 )CERTIFICATE)-{5}$/))
|
if (lines[i].match(/^-{5}BEGIN ((|RSA |DSA )PRIVATE KEY|(|TRUSTED |X509 )CERTIFICATE)-{5}$/))
|
||||||
start = true;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,36 +59,36 @@ function validateCert(priv, section_id, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return network.registerProtocol('openfortivpn', {
|
return network.registerProtocol('openfortivpn', {
|
||||||
getI18n: function() {
|
getI18n() {
|
||||||
return _('OpenFortivpn');
|
return _('OpenFortivpn');
|
||||||
},
|
},
|
||||||
|
|
||||||
getIfname: function() {
|
getIfname() {
|
||||||
return this._ubus('l3_device') || 'vpn-%s'.format(this.sid);
|
return this._ubus('l3_device') || 'vpn-%s'.format(this.sid);
|
||||||
},
|
},
|
||||||
|
|
||||||
getPackageName: function() {
|
getPackageName() {
|
||||||
return 'openfortivpn';
|
return 'openfortivpn';
|
||||||
},
|
},
|
||||||
|
|
||||||
isFloating: function() {
|
isFloating() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
isVirtual: function() {
|
isVirtual() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
getDevices: function() {
|
getDevices() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
containsDevice: function(ifname) {
|
containsDevice(ifname) {
|
||||||
return (network.getIfnameOf(ifname) == this.getIfname());
|
return (network.getIfnameOf(ifname) == this.getIfname());
|
||||||
},
|
},
|
||||||
|
|
||||||
renderFormOptions: function(s) {
|
renderFormOptions(s) {
|
||||||
var o;
|
let o, certLoadPromise;
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'peeraddr', _('VPN Server'));
|
o = s.taboption('general', form.Value, 'peeraddr', _('VPN Server'));
|
||||||
o.datatype = 'host(0)';
|
o.datatype = 'host(0)';
|
||||||
@@ -108,7 +108,7 @@ return network.registerProtocol('openfortivpn', {
|
|||||||
o.monospace = true;
|
o.monospace = true;
|
||||||
o.validate = L.bind(validateCert, o, false);
|
o.validate = L.bind(validateCert, o, false);
|
||||||
o.load = function(section_id) {
|
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 });
|
return certLoadPromise.then(function(certs) { return certs.user_cert });
|
||||||
};
|
};
|
||||||
o.write = function(section_id, value) {
|
o.write = function(section_id, value) {
|
||||||
@@ -121,7 +121,7 @@ return network.registerProtocol('openfortivpn', {
|
|||||||
o.monospace = true;
|
o.monospace = true;
|
||||||
o.validate = L.bind(validateCert, o, true);
|
o.validate = L.bind(validateCert, o, true);
|
||||||
o.load = function(section_id) {
|
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 });
|
return certLoadPromise.then(function(certs) { return certs.user_key });
|
||||||
};
|
};
|
||||||
o.write = function(section_id, value) {
|
o.write = function(section_id, value) {
|
||||||
@@ -134,7 +134,7 @@ return network.registerProtocol('openfortivpn', {
|
|||||||
o.monospace = true;
|
o.monospace = true;
|
||||||
o.validate = L.bind(validateCert, o, false);
|
o.validate = L.bind(validateCert, o, false);
|
||||||
o.load = function(section_id) {
|
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 });
|
return certLoadPromise.then(function(certs) { return certs.ca_file });
|
||||||
};
|
};
|
||||||
o.write = function(section_id, value) {
|
o.write = function(section_id, value) {
|
||||||
|
|||||||
@@ -7,17 +7,17 @@
|
|||||||
network.registerPatternVirtual(/^relay-.+$/);
|
network.registerPatternVirtual(/^relay-.+$/);
|
||||||
|
|
||||||
var RelayDevicePrototype = {
|
var RelayDevicePrototype = {
|
||||||
__init__: function(ifname, network) {
|
__init__(ifname, network) {
|
||||||
this.ifname = ifname;
|
this.ifname = ifname;
|
||||||
this.network = network;
|
this.network = network;
|
||||||
},
|
},
|
||||||
|
|
||||||
_aggregateDevices: function(fn, first) {
|
_aggregateDevices(fn, first) {
|
||||||
var devices = this.network ? this.network.getDevices() : [],
|
const devices = this.network ? this.network.getDevices() : [];
|
||||||
rv = 0;
|
let rv = 0;
|
||||||
|
|
||||||
for (var i = 0; i < devices.length; i++) {
|
for (let d of devices) {
|
||||||
var v = devices[i][fn].apply(devices[i]);
|
var v = d[fn].apply(d);
|
||||||
|
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
if (first)
|
if (first)
|
||||||
@@ -30,88 +30,88 @@ var RelayDevicePrototype = {
|
|||||||
return first ? null : [ rv, devices.length ];
|
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' },
|
getType() { return 'tunnel' },
|
||||||
getTypeI18n: function() { return _('Relay Bridge') },
|
getTypeI18n() { return _('Relay Bridge') },
|
||||||
|
|
||||||
getShortName: function() {
|
getShortName() {
|
||||||
return '%s "%h"'.format(_('Relay'), this.ifname);
|
return '%s "%h"'.format(_('Relay'), this.ifname);
|
||||||
},
|
},
|
||||||
|
|
||||||
isUp: function() {
|
isUp() {
|
||||||
var res = this._aggregateDevices('isUp');
|
var res = this._aggregateDevices('isUp');
|
||||||
return (res[1] > 0 && res[0] == res[1]);
|
return (res[1] > 0 && res[0] == res[1]);
|
||||||
},
|
},
|
||||||
|
|
||||||
getTXBytes: function() { return this._aggregateDevices('getTXBytes')[0] },
|
getTXBytes() { return this._aggregateDevices('getTXBytes')[0] },
|
||||||
getRXBytes: function() { return this._aggregateDevices('getRXBytes')[0] },
|
getRXBytes() { return this._aggregateDevices('getRXBytes')[0] },
|
||||||
getTXPackets: function() { return this._aggregateDevices('getTXPackets')[0] },
|
getTXPackets() { return this._aggregateDevices('getTXPackets')[0] },
|
||||||
getRXPackets: function() { return this._aggregateDevices('getRXPackets')[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;
|
var ipaddr = this.network ? L.toArray(uci.get('network', this.network.getName(), 'ipaddr'))[0] : null;
|
||||||
return (ipaddr != null ? [ ipaddr ] : []);
|
return (ipaddr != null ? [ ipaddr ] : []);
|
||||||
},
|
},
|
||||||
|
|
||||||
getIP6Addrs: function() { return [] }
|
getIP6Addrs() { return [] }
|
||||||
};
|
};
|
||||||
|
|
||||||
return network.registerProtocol('relay', {
|
return network.registerProtocol('relay', {
|
||||||
getI18n: function() {
|
getI18n() {
|
||||||
return _('Relay bridge');
|
return _('Relay bridge');
|
||||||
},
|
},
|
||||||
|
|
||||||
getIfname: function() {
|
getIfname() {
|
||||||
return 'relay-%s'.format(this.sid);
|
return 'relay-%s'.format(this.sid);
|
||||||
},
|
},
|
||||||
|
|
||||||
getPackageName: function() {
|
getPackageName() {
|
||||||
return 'relayd';
|
return 'relayd';
|
||||||
},
|
},
|
||||||
|
|
||||||
isFloating: function() {
|
isFloating() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
isVirtual: function() {
|
isVirtual() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
containsDevice: function(ifname) {
|
containsDevice(ifname) {
|
||||||
return (network.getIfnameOf(ifname) == this.getIfname());
|
return (network.getIfnameOf(ifname) == this.getIfname());
|
||||||
},
|
},
|
||||||
|
|
||||||
isUp: function() {
|
isUp() {
|
||||||
var dev = this.getDevice();
|
var dev = this.getDevice();
|
||||||
return (dev ? dev.isUp() : false);
|
return (dev ? dev.isUp() : false);
|
||||||
},
|
},
|
||||||
|
|
||||||
getDevice: function() {
|
getDevice() {
|
||||||
return network.instantiateDevice(this.sid, this, RelayDevicePrototype);
|
return network.instantiateDevice(this.sid, this, RelayDevicePrototype);
|
||||||
},
|
},
|
||||||
|
|
||||||
getDevices: function() {
|
getDevices() {
|
||||||
if (this.devices)
|
if (this.devices)
|
||||||
return this.devices;
|
return this.devices;
|
||||||
|
|
||||||
var networkNames = L.toArray(uci.get('network', this.sid, 'network')),
|
const networkNames = L.toArray(uci.get('network', this.sid, 'network'));
|
||||||
deviceNames = L.toArray(uci.get('network', this.sid, 'ifname')),
|
let deviceNames = L.toArray(uci.get('network', this.sid, 'ifname'));
|
||||||
devices = {},
|
const devices = {};
|
||||||
rv = [];
|
const rv = [];
|
||||||
|
|
||||||
for (var i = 0; i < networkNames.length; i++) {
|
for (let nn of networkNames) {
|
||||||
var net = network.instantiateNetwork(networkNames[i]),
|
var net = network.instantiateNetwork(nn),
|
||||||
dev = net ? net.getDevice() : null;
|
dev = net ? net.getDevice() : null;
|
||||||
|
|
||||||
if (dev)
|
if (dev)
|
||||||
devices[dev.getName()] = dev;
|
devices[dev.getName()] = dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < deviceNames.length; i++) {
|
for (let dn of deviceNames) {
|
||||||
var dev = network.getDevice(deviceNames[i]);
|
const dev = network.getDevice(dn);
|
||||||
|
|
||||||
if (dev)
|
if (dev)
|
||||||
devices[dev.getName()] = dev;
|
devices[dev.getName()] = dev;
|
||||||
@@ -120,20 +120,20 @@ return network.registerProtocol('relay', {
|
|||||||
deviceNames = Object.keys(devices);
|
deviceNames = Object.keys(devices);
|
||||||
deviceNames.sort();
|
deviceNames.sort();
|
||||||
|
|
||||||
for (var i = 0; i < deviceNames.length; i++)
|
for (let dn of deviceNames)
|
||||||
rv.push(devices[deviceNames[i]]);
|
rv.push(devices[dn]);
|
||||||
|
|
||||||
this.devices = rv;
|
this.devices = rv;
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
},
|
},
|
||||||
|
|
||||||
getUptime: function() {
|
getUptime() {
|
||||||
var networkNames = L.toArray(uci.get('network', this.sid, 'network')),
|
const networkNames = L.toArray(uci.get('network', this.sid, 'network'));
|
||||||
uptime = 0;
|
let uptime = 0;
|
||||||
|
|
||||||
for (var i = 0; i < networkNames.length; i++) {
|
for (let nn of networkNames) {
|
||||||
var net = network.instantiateNetwork(networkNames[i]);
|
const net = network.instantiateNetwork(nn);
|
||||||
if (net)
|
if (net)
|
||||||
uptime = Math.max(uptime, net.getUptime());
|
uptime = Math.max(uptime, net.getUptime());
|
||||||
}
|
}
|
||||||
@@ -141,11 +141,11 @@ return network.registerProtocol('relay', {
|
|||||||
return uptime;
|
return uptime;
|
||||||
},
|
},
|
||||||
|
|
||||||
getErrors: function() {
|
getErrors() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderFormOptions: function(s) {
|
renderFormOptions(s) {
|
||||||
var o;
|
var o;
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'ipaddr', _('Local IPv4 address'), _('Address to access local relay bridge'));
|
o = s.taboption('general', form.Value, 'ipaddr', _('Local IPv4 address'), _('Address to access local relay bridge'));
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function validateBase64(section_id, value) {
|
|||||||
if (value.length == 0)
|
if (value.length == 0)
|
||||||
return true;
|
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');
|
return _('Invalid Base64 key string');
|
||||||
|
|
||||||
if (value[43] != "=" )
|
if (value[43] != "=" )
|
||||||
@@ -45,26 +45,17 @@ function validateBase64(section_id, value) {
|
|||||||
|
|
||||||
var stubValidator = {
|
var stubValidator = {
|
||||||
factory: validation,
|
factory: validation,
|
||||||
apply: function(type, value, args) {
|
apply(type, value, args) {
|
||||||
if (value != null)
|
if (value != null)
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|
||||||
return validation.types[type].apply(this, args);
|
return validation.types[type].apply(this, args);
|
||||||
},
|
},
|
||||||
assert: function(condition) {
|
assert(condition) {
|
||||||
return !!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) {
|
function buildSVGQRCode(data, code) {
|
||||||
// pixel size larger than 4 clips right and bottom edges of complex configs
|
// pixel size larger than 4 clips right and bottom edges of complex configs
|
||||||
const options = {
|
const options = {
|
||||||
@@ -78,7 +69,7 @@ function buildSVGQRCode(data, code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cbiKeyPairGenerate = form.DummyValue.extend({
|
var cbiKeyPairGenerate = form.DummyValue.extend({
|
||||||
cfgvalue: function(section_id, value) {
|
cfgvalue(section_id, value) {
|
||||||
return E('button', {
|
return E('button', {
|
||||||
'class': 'btn',
|
'class': 'btn',
|
||||||
'click': ui.createHandlerFn(this, function(section_id, ev) {
|
'click': ui.createHandlerFn(this, function(section_id, ev) {
|
||||||
@@ -101,36 +92,36 @@ function handleWindowDragDropIgnore(ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return network.registerProtocol('wireguard', {
|
return network.registerProtocol('wireguard', {
|
||||||
getI18n: function() {
|
getI18n() {
|
||||||
return _('WireGuard VPN');
|
return _('WireGuard VPN');
|
||||||
},
|
},
|
||||||
|
|
||||||
getIfname: function() {
|
getIfname() {
|
||||||
return this._ubus('l3_device') || this.sid;
|
return this._ubus('l3_device') || this.sid;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPackageName: function() {
|
getPackageName() {
|
||||||
return 'wireguard-tools';
|
return 'wireguard-tools';
|
||||||
},
|
},
|
||||||
|
|
||||||
isFloating: function() {
|
isFloating() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
isVirtual: function() {
|
isVirtual() {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
getDevices: function() {
|
getDevices() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
containsDevice: function(ifname) {
|
containsDevice(ifname) {
|
||||||
return (network.getIfnameOf(ifname) == this.getIfname());
|
return (network.getIfnameOf(ifname) == this.getIfname());
|
||||||
},
|
},
|
||||||
|
|
||||||
renderFormOptions: function(s) {
|
renderFormOptions(s) {
|
||||||
var o, ss, ss2;
|
var o, ss;
|
||||||
|
|
||||||
// -- general ---------------------------------------------------------------------
|
// -- general ---------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -139,8 +130,6 @@ return network.registerProtocol('wireguard', {
|
|||||||
o.validate = validateBase64;
|
o.validate = validateBase64;
|
||||||
o.rmempty = false;
|
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 = s.taboption('general', form.Value, 'public_key', _('Public Key'), _('Base64-encoded public key of this interface for sharing.'));
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.write = function() {/* write nothing */};
|
o.write = function() {/* write nothing */};
|
||||||
@@ -268,16 +257,16 @@ return network.registerProtocol('wireguard', {
|
|||||||
if (config.interface_address) {
|
if (config.interface_address) {
|
||||||
config.interface_address = config.interface_address.split(/[, ]+/);
|
config.interface_address = config.interface_address.split(/[, ]+/);
|
||||||
|
|
||||||
for (var i = 0; i < config.interface_address.length; i++)
|
for (let cfia of config.interface_address)
|
||||||
if (!stubValidator.apply('ipaddr', config.interface_address[i]))
|
if (!stubValidator.apply('ipaddr', cfia))
|
||||||
return _('Address setting is invalid');
|
return _('Address setting is invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.interface_dns) {
|
if (config.interface_dns) {
|
||||||
config.interface_dns = config.interface_dns.split(/[, ]+/);
|
config.interface_dns = config.interface_dns.split(/[, ]+/);
|
||||||
|
|
||||||
for (var i = 0; i < config.interface_dns.length; i++)
|
for (let cfid of config.interface_dns)
|
||||||
if (!stubValidator.apply('ipaddr', config.interface_dns[i], ['nomask']))
|
if (!stubValidator.apply('ipaddr', cfid, ['nomask']))
|
||||||
return _('DNS setting is invalid');
|
return _('DNS setting is invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,9 +276,7 @@ return network.registerProtocol('wireguard', {
|
|||||||
if (!stubValidator.apply('port', config.interface_listenport || '0'))
|
if (!stubValidator.apply('port', config.interface_listenport || '0'))
|
||||||
return _('ListenPort setting is invalid');
|
return _('ListenPort setting is invalid');
|
||||||
|
|
||||||
for (var i = 0; i < config.peers.length; i++) {
|
for (let pconf of config.peers) {
|
||||||
var pconf = config.peers[i];
|
|
||||||
|
|
||||||
if (pconf.peer_publickey != null && validateBase64(null, pconf.peer_publickey) !== true)
|
if (pconf.peer_publickey != null && validateBase64(null, pconf.peer_publickey) !== true)
|
||||||
return _('PublicKey setting is invalid');
|
return _('PublicKey setting is invalid');
|
||||||
|
|
||||||
@@ -327,10 +314,10 @@ return network.registerProtocol('wireguard', {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ss.handleApplyConfig = function(mode, nodes, comment, ev) {
|
ss.handleApplyConfig = function(mode, nodes, comment, ev) {
|
||||||
var input = nodes.querySelector('textarea').value,
|
const input = nodes.querySelector('textarea').value;
|
||||||
error = nodes.querySelector('.alert-message'),
|
const error = nodes.querySelector('.alert-message');
|
||||||
cancel = nodes.nextElementSibling.querySelector('.btn'),
|
const cancel = nodes.nextElementSibling.querySelector('.btn');
|
||||||
config = this.parseConfig(input);
|
const config = this.parseConfig(input);
|
||||||
|
|
||||||
if (typeof(config) == 'string') {
|
if (typeof(config) == 'string') {
|
||||||
error.firstChild.data = _('Cannot parse configuration: %s').format(config);
|
error.firstChild.data = _('Cannot parse configuration: %s').format(config);
|
||||||
@@ -339,7 +326,7 @@ return network.registerProtocol('wireguard', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 'full') {
|
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?')))
|
if (prv && prv != config.interface_privatekey && !confirm(_('Overwrite the current settings with the imported configuration?')))
|
||||||
return;
|
return;
|
||||||
@@ -353,9 +340,8 @@ return network.registerProtocol('wireguard', {
|
|||||||
if (config.interface_dns)
|
if (config.interface_dns)
|
||||||
s.getOption('dns').getUIElement(s.section).setValue(config.interface_dns);
|
s.getOption('dns').getUIElement(s.section).setValue(config.interface_dns);
|
||||||
|
|
||||||
for (var i = 0; i < config.peers.length; i++) {
|
for (let pconf of config.peers) {
|
||||||
var pconf = config.peers[i];
|
const sid = uci.add('network', 'wireguard_' + s.section);
|
||||||
var sid = uci.add('network', 'wireguard_' + s.section);
|
|
||||||
|
|
||||||
uci.sections('network', 'wireguard_' + s.section, function(peer) {
|
uci.sections('network', 'wireguard_' + s.section, function(peer) {
|
||||||
if (peer.public_key == pconf.peer_publickey)
|
if (peer.public_key == pconf.peer_publickey)
|
||||||
@@ -381,8 +367,8 @@ return network.registerProtocol('wireguard', {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return getPublicAndPrivateKeyFromPrivate(config.interface_privatekey).then(function(keypair) {
|
return getPublicAndPrivateKeyFromPrivate(config.interface_privatekey).then(function(keypair) {
|
||||||
var sid = uci.add('network', 'wireguard_' + s.section);
|
const sid = uci.add('network', 'wireguard_' + s.section);
|
||||||
var pub = s.formvalue(s.section, 'public_key');
|
const pub = s.formvalue(s.section, 'public_key');
|
||||||
|
|
||||||
uci.sections('network', 'wireguard_' + s.section, function(peer) {
|
uci.sections('network', 'wireguard_' + s.section, function(peer) {
|
||||||
if (peer.public_key == keypair.pub)
|
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, 'public_key', keypair.pub);
|
||||||
uci.set('network', sid, 'private_key', keypair.priv);
|
uci.set('network', sid, 'private_key', keypair.priv);
|
||||||
|
|
||||||
for (var i = 0; i < config.peers.length; i++) {
|
for (let pconf of config.peers) {
|
||||||
var pconf = config.peers[i];
|
|
||||||
|
|
||||||
if (pconf.peer_publickey == pub) {
|
if (pconf.peer_publickey == pub) {
|
||||||
uci.set('network', sid, 'preshared_key', pconf.peer_presharedkey);
|
uci.set('network', sid, 'preshared_key', pconf.peer_presharedkey);
|
||||||
uci.set('network', sid, 'allowed_ips', pconf.peer_allowedips);
|
uci.set('network', sid, 'allowed_ips', pconf.peer_allowedips);
|
||||||
@@ -412,11 +396,10 @@ return network.registerProtocol('wireguard', {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ss.handleConfigImport = function(mode) {
|
ss.handleConfigImport = function(mode) {
|
||||||
var mapNode = ss.getActiveModalMap(),
|
const mapNode = ss.getActiveModalMap();
|
||||||
headNode = mapNode.parentNode.querySelector('h4'),
|
const headNode = mapNode.parentNode.querySelector('h4');
|
||||||
parent = this.map;
|
|
||||||
|
|
||||||
var nodes = E('div', {
|
const nodes = E('div', {
|
||||||
'dragover': this.handleDragConfig,
|
'dragover': this.handleDragConfig,
|
||||||
'drop': this.handleDropConfig.bind(this, mode)
|
'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.nextSibling);
|
||||||
nodes.parentNode.removeChild(nodes);
|
nodes.parentNode.removeChild(nodes);
|
||||||
mapNode.classList.remove('hidden');
|
mapNode.classList.remove('hidden');
|
||||||
@@ -450,7 +433,7 @@ return network.registerProtocol('wireguard', {
|
|||||||
window.removeEventListener('drop', handleWindowDragDropIgnore);
|
window.removeEventListener('drop', handleWindowDragDropIgnore);
|
||||||
};
|
};
|
||||||
|
|
||||||
var a = nodes.querySelector('a.full-import');
|
const a = nodes.querySelector('a.full-import');
|
||||||
|
|
||||||
if (a) {
|
if (a) {
|
||||||
a.addEventListener('click', ui.createHandlerFn(this, function(mode) {
|
a.addEventListener('click', ui.createHandlerFn(this, function(mode) {
|
||||||
@@ -485,7 +468,7 @@ return network.registerProtocol('wireguard', {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ss.renderSectionAdd = function(/* ... */) {
|
ss.renderSectionAdd = function(/* ... */) {
|
||||||
var nodes = this.super('renderSectionAdd', arguments);
|
const nodes = this.super('renderSectionAdd', arguments);
|
||||||
|
|
||||||
nodes.appendChild(E('button', {
|
nodes.appendChild(E('button', {
|
||||||
'class': 'btn',
|
'class': 'btn',
|
||||||
@@ -510,14 +493,14 @@ return network.registerProtocol('wireguard', {
|
|||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.width = '30%';
|
o.width = '30%';
|
||||||
o.textvalue = function(section_id) {
|
o.textvalue = function(section_id) {
|
||||||
var dis = ss.getOption('disabled'),
|
const dis = ss.getOption('disabled');
|
||||||
pub = ss.getOption('public_key'),
|
const pub = ss.getOption('public_key');
|
||||||
prv = ss.getOption('private_key'),
|
const prv = ss.getOption('private_key');
|
||||||
psk = ss.getOption('preshared_key'),
|
const psk = ss.getOption('preshared_key');
|
||||||
name = this.cfgvalue(section_id),
|
const name = this.cfgvalue(section_id);
|
||||||
key = pub.cfgvalue(section_id);
|
const key = pub.cfgvalue(section_id);
|
||||||
|
|
||||||
var desc = [
|
const desc = [
|
||||||
E('p', [
|
E('p', [
|
||||||
name ? E('span', [ name ]) : E('em', [ _('Untitled peer') ])
|
name ? E('span', [ name ]) : E('em', [ _('Untitled peer') ])
|
||||||
])
|
])
|
||||||
@@ -566,8 +549,8 @@ return network.registerProtocol('wireguard', {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function handleKeyChange(ev, section_id, value) {
|
function handleKeyChange(ev, section_id, value) {
|
||||||
var prv = this.section.getUIElement(section_id, 'private_key'),
|
const prv = this.section.getUIElement(section_id, 'private_key');
|
||||||
btn = this.map.findElement('.btn.qr-code');
|
const btn = this.map.findElement('.btn.qr-code');
|
||||||
|
|
||||||
btn.disabled = (!prv.isValid() || !prv.getValue());
|
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 = 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.datatype = 'ipaddr';
|
||||||
o.textvalue = function(section_id) {
|
o.textvalue = function(section_id) {
|
||||||
var ips = L.toArray(this.cfgvalue(section_id)),
|
const ips = L.toArray(this.cfgvalue(section_id));
|
||||||
list = [];
|
const list = [];
|
||||||
|
|
||||||
for (var i = 0; i < ips.length; i++) {
|
for (var i = 0; i < ips.length; i++) {
|
||||||
if (i > 7) {
|
if (i > 7) {
|
||||||
@@ -650,8 +633,8 @@ return network.registerProtocol('wireguard', {
|
|||||||
o.placeholder = 'vpn.example.com';
|
o.placeholder = 'vpn.example.com';
|
||||||
o.datatype = 'host';
|
o.datatype = 'host';
|
||||||
o.textvalue = function(section_id) {
|
o.textvalue = function(section_id) {
|
||||||
var host = this.cfgvalue(section_id),
|
const host = this.cfgvalue(section_id);
|
||||||
port = this.section.cfgvalue(section_id, 'endpoint_port');
|
const port = this.section.cfgvalue(section_id, 'endpoint_port');
|
||||||
|
|
||||||
return (host && port)
|
return (host && port)
|
||||||
? '%h:%d'.format(host, port)
|
? '%h:%d'.format(host, port)
|
||||||
@@ -680,12 +663,12 @@ return network.registerProtocol('wireguard', {
|
|||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
|
||||||
o.createPeerConfig = function(section_id, endpoint, ips, eips, dns) {
|
o.createPeerConfig = function(section_id, endpoint, ips, eips, dns) {
|
||||||
var pub = s.formvalue(s.section, 'public_key'),
|
const pub = s.formvalue(s.section, 'public_key');
|
||||||
port = s.formvalue(s.section, 'listen_port') || '51820',
|
const port = s.formvalue(s.section, 'listen_port') || '51820';
|
||||||
prv = this.section.formvalue(section_id, 'private_key'),
|
const prv = this.section.formvalue(section_id, 'private_key');
|
||||||
psk = this.section.formvalue(section_id, 'preshared_key'),
|
const psk = this.section.formvalue(section_id, 'preshared_key');
|
||||||
eport = this.section.formvalue(section_id, 'endpoint_port'),
|
const eport = this.section.formvalue(section_id, 'endpoint_port');
|
||||||
keep = this.section.formvalue(section_id, 'persistent_keepalive');
|
const keep = this.section.formvalue(section_id, 'persistent_keepalive');
|
||||||
|
|
||||||
// If endpoint is IPv6 we must escape it with []
|
// If endpoint is IPv6 we must escape it with []
|
||||||
if (endpoint.indexOf(':') > 0) {
|
if (endpoint.indexOf(':') > 0) {
|
||||||
@@ -709,11 +692,11 @@ return network.registerProtocol('wireguard', {
|
|||||||
};
|
};
|
||||||
|
|
||||||
o.handleGenerateQR = function(section_id, ev) {
|
o.handleGenerateQR = function(section_id, ev) {
|
||||||
var mapNode = ss.getActiveModalMap(),
|
const mapNode = ss.getActiveModalMap();
|
||||||
headNode = mapNode.parentNode.querySelector('h4'),
|
const headNode = mapNode.parentNode.querySelector('h4');
|
||||||
configGenerator = this.createPeerConfig.bind(this, section_id),
|
const configGenerator = this.createPeerConfig.bind(this, section_id);
|
||||||
parent = this.map,
|
const parent = this.map;
|
||||||
eips = this.section.formvalue(section_id, 'allowed_ips');
|
const eips = this.section.formvalue(section_id, 'allowed_ips');
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
network.getWANNetworks(),
|
network.getWANNetworks(),
|
||||||
@@ -722,8 +705,8 @@ return network.registerProtocol('wireguard', {
|
|||||||
L.resolveDefault(uci.load('ddns')),
|
L.resolveDefault(uci.load('ddns')),
|
||||||
L.resolveDefault(uci.load('system')),
|
L.resolveDefault(uci.load('system')),
|
||||||
parent.save(null, true)
|
parent.save(null, true)
|
||||||
]).then(function(data) {
|
]).then(function([wNets, w6Nets, lnet]) {
|
||||||
var hostnames = [];
|
const hostnames = [];
|
||||||
|
|
||||||
uci.sections('ddns', 'service', function(s) {
|
uci.sections('ddns', 'service', function(s) {
|
||||||
if (typeof(s?.lookup_host) == 'string' && s?.enabled == '1')
|
if (typeof(s?.lookup_host) == 'string' && s?.enabled == '1')
|
||||||
@@ -735,25 +718,24 @@ return network.registerProtocol('wireguard', {
|
|||||||
hostnames.push(s.hostname);
|
hostnames.push(s.hostname);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (var i = 0; i < data[0].length; i++)
|
for (let wNet of wNets)
|
||||||
hostnames.push.apply(hostnames, data[0][i].getIPAddrs().map(function(ip) { return ip.split('/')[0] }));
|
hostnames.push.apply(hostnames, wNet.getIPAddrs().map(function(ip) { return ip.split('/')[0] }));
|
||||||
|
|
||||||
for (var i = 0; i < data[1].length; i++)
|
for (let w6Net of w6Nets)
|
||||||
hostnames.push.apply(hostnames, data[1][i].getIP6Addrs().map(function(ip) { return ip.split('/')[0] }));
|
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 (lnet) {
|
||||||
if (lan) {
|
const lanIp = lnet.getIPAddr();
|
||||||
var lanIp = lan.getIPAddr();
|
|
||||||
if (lanIp) {
|
if (lanIp) {
|
||||||
dns.unshift(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 = 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;
|
qrm.parent = parent;
|
||||||
@@ -761,12 +743,12 @@ return network.registerProtocol('wireguard', {
|
|||||||
qrs = qrm.section(form.NamedSection, 'config');
|
qrs = qrm.section(form.NamedSection, 'config');
|
||||||
|
|
||||||
function handleConfigChange(ev, section_id, value) {
|
function handleConfigChange(ev, section_id, value) {
|
||||||
var code = this.map.findElement('.qr-code'),
|
const code = this.map.findElement('.qr-code');
|
||||||
conf = this.map.findElement('.client-config'),
|
const conf = this.map.findElement('.client-config');
|
||||||
endpoint = this.section.getUIElement(section_id, 'endpoint'),
|
const endpoint = this.section.getUIElement(section_id, 'endpoint');
|
||||||
ips = this.section.getUIElement(section_id, 'allowed_ips');
|
const ips = this.section.getUIElement(section_id, 'allowed_ips');
|
||||||
eips = this.section.getUIElement(section_id, 'addresses');
|
const eips = this.section.getUIElement(section_id, 'addresses');
|
||||||
dns = this.section.getUIElement(section_id, 'dns_servers');
|
const dns = this.section.getUIElement(section_id, 'dns_servers');
|
||||||
|
|
||||||
if (this.isValid(section_id)) {
|
if (this.isValid(section_id)) {
|
||||||
conf.firstChild.data = configGenerator(endpoint.getValue(), ips.getValue(), eips.getValue(), dns.getValue());
|
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 = qrs.option(form.DummyValue, 'output');
|
||||||
qro.renderWidget = function() {
|
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%'
|
'style': 'display:flex;flex-wrap:wrap;align-items:center;gap:.5em;width:100%'
|
||||||
}, [
|
}, [
|
||||||
E('div', {
|
E('div', {
|
||||||
@@ -814,9 +796,9 @@ return network.registerProtocol('wireguard', {
|
|||||||
E('pre', {
|
E('pre', {
|
||||||
'class': 'client-config',
|
'class': 'client-config',
|
||||||
'style': 'flex:1;white-space:pre;overflow:auto',
|
'style': 'flex:1;white-space:pre;overflow:auto',
|
||||||
'click': function(ev) {
|
'click'(ev) {
|
||||||
var sel = window.getSelection(),
|
const sel = window.getSelection();
|
||||||
range = document.createRange();
|
const range = document.createRange();
|
||||||
|
|
||||||
range.selectNodeContents(ev.currentTarget);
|
range.selectNodeContents(ev.currentTarget);
|
||||||
|
|
||||||
@@ -849,7 +831,7 @@ return network.registerProtocol('wireguard', {
|
|||||||
}, [
|
}, [
|
||||||
E('button', {
|
E('button', {
|
||||||
'class': 'btn',
|
'class': 'btn',
|
||||||
'click': function() {
|
'click'() {
|
||||||
// Remove QR code button (row)
|
// Remove QR code button (row)
|
||||||
nodes.parentNode.removeChild(nodes.nextSibling);
|
nodes.parentNode.removeChild(nodes.nextSibling);
|
||||||
// Remove QR code form
|
// 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.sections('network', 'wireguard_%s'.format(this.sid), function(s) {
|
||||||
uci.remove('network', s['.name']);
|
uci.remove('network', s['.name']);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user