diff options
Diffstat (limited to 'applications/luci-app-pbr/htdocs/luci-static/resources')
3 files changed, 848 insertions, 446 deletions
diff --git a/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js b/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js index 24f624c945..99a6e73844 100644 --- a/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js +++ b/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js @@ -3,7 +3,6 @@ "require ui"; "require rpc"; -"require uci"; "require form"; "require baseclass"; @@ -55,8 +54,8 @@ var _setInitAction = rpc.declare({ var RPC = { listeners: [], - on: function on(event, callback) { - var pair = { event: event, callback: callback } + on: function (event, callback) { + var pair = { event: event, callback: callback }; this.listeners.push(pair); return function unsubscribe() { this.listeners = this.listeners.filter(function (listener) { @@ -64,65 +63,77 @@ var RPC = { }); }.bind(this); }, - emit: function emit(event, data) { + emit: function (event, data) { this.listeners.forEach(function (listener) { if (listener.event === event) { listener.callback(data); } }); }, - getInitList: function getInitList(name) { - getInitList(name).then(function (result) { - this.emit('getInitList', result); - }.bind(this)); + getInitList: function (name) { + getInitList(name).then( + function (result) { + this.emit("getInitList", result); + }.bind(this) + ); }, - getInitStatus: function getInitStatus(name) { - getInitStatus(name).then(function (result) { - this.emit('getInitStatus', result); - }.bind(this)); + getInitStatus: function (name) { + getInitStatus(name).then( + function (result) { + this.emit("getInitStatus", result); + }.bind(this) + ); }, - getGateways: function getGateways(name) { - getGateways(name).then(function (result) { - this.emit('getGateways', result); - }.bind(this)); + getGateways: function (name) { + getGateways(name).then( + function (result) { + this.emit("getGateways", result); + }.bind(this) + ); }, - getPlatformSupport: function getPlatformSupport(name) { - getPlatformSupport(name).then(function (result) { - this.emit('getPlatformSupport', result); - }.bind(this)); + getPlatformSupport: function (name) { + getPlatformSupport(name).then( + function (result) { + this.emit("getPlatformSupport", result); + }.bind(this) + ); }, - getInterfaces: function getInterfaces(name) { - getInterfaces(name).then(function (result) { - this.emit('getInterfaces', result); - }.bind(this)); + getInterfaces: function (name) { + getInterfaces(name).then( + function (result) { + this.emit("getInterfaces", result); + }.bind(this) + ); }, - setInitAction: function setInitAction(name, action) { - _setInitAction(name, action).then(function (result) { - this.emit('setInitAction', result); - }.bind(this)); + setInitAction: function (name, action) { + _setInitAction(name, action).then( + function (result) { + this.emit("setInitAction", result); + }.bind(this) + ); }, -} +}; var status = baseclass.extend({ render: function () { return Promise.all([ - L.resolveDefault(getInitStatus(), {}), -// L.resolveDefault(getGateways(), {}), + L.resolveDefault(getInitStatus(pkg.Name), {}), + // L.resolveDefault(getGateways(pkg.Name), {}), ]).then(function (data) { -// var replyStatus = data[0]; -// var replyGateways = data[1]; + // var replyStatus = data[0]; + // var replyGateways = data[1]; var reply; var text; if (data[0] && data[0][pkg.Name]) { reply = data[0][pkg.Name]; - } - else { + } else { reply = { enabled: null, running: null, running_iptables: null, running_nft: null, + running_nft_file: null, version: null, gateways: null, errors: [], @@ -130,187 +141,351 @@ var status = baseclass.extend({ }; } - var header = E('h2', {}, _("Policy Based Routing - Status")); - var statusTitle = E('label', { class: 'cbi-value-title' }, _("Service Status")); + var header = E("h2", {}, _("Policy Based Routing - Status")); + var statusTitle = E( + "label", + { class: "cbi-value-title" }, + _("Service Status") + ); if (reply.version) { + text = _("Version %s").format(reply.version) + " - "; if (reply.running) { + text += _("Running"); if (reply.running_iptables) { - text = _("Running (version: %s using iptables)").format(reply.version); - } - else if (reply.running_nft) { - text = _("Running (version: %s using nft)").format(reply.version); + text += " (" + _("iptables mode") + ")."; + } else if (reply.running_nft_file) { + text += " (" + _("fw4 nft file mode") + ")."; + } else if (reply.running_nft) { + text += " (" + _("nft mode") + ")."; + } else { + text += "."; } - else { - text = _("Running (version: %s)").format(reply.version); - } - } - else { + } else { if (reply.enabled) { - text = _("Stopped (version: %s)").format(reply.version); - } - else { - text = _("Stopped (Disabled)"); + text += _("Stopped."); + } else { + text += _("Stopped (Disabled)."); } } - } - else { + } else { text = _("Not installed or not found"); } - var statusText = E('div', {}, text); - var statusField = E('div', { class: 'cbi-value-field' }, statusText); - var statusDiv = E('div', { class: 'cbi-value' }, [statusTitle, statusField]); + var statusText = E("div", {}, text); + var statusField = E("div", { class: "cbi-value-field" }, statusText); + var statusDiv = E("div", { class: "cbi-value" }, [ + statusTitle, + statusField, + ]); var gatewaysDiv = []; if (reply.gateways) { - var gatewaysTitle = E('label', { class: 'cbi-value-title' }, _("Service Gateways")); - text = _("The %s indicates default gateway. See the %sREADME%s for details.").format("<strong>✓</strong>", - "<a href=\"" + pkg.URL + "#a-word-about-default-routing \" target=\"_blank\">", "</a>") - var gatewaysDescr = E('div', { class: 'cbi-value-description' }, text); - var gatewaysText = E('div', {}, reply.gateways); - var gatewaysField = E('div', { class: 'cbi-value-field' }, [gatewaysText, gatewaysDescr]); - gatewaysDiv = E('div', { class: 'cbi-value' }, [gatewaysTitle, gatewaysField]); + var gatewaysTitle = E( + "label", + { class: "cbi-value-title" }, + _("Service Gateways") + ); + text = _( + "The %s indicates default gateway. See the %sREADME%s for details." + ).format( + "<strong>✓</strong>", + '<a href="' + pkg.URL + '#AWordAboutDefaultRouting" target="_blank">', + "</a>" + ); + var gatewaysDescr = E("div", { class: "cbi-value-description" }, text); + var gatewaysText = E("div", {}, reply.gateways); + var gatewaysField = E("div", { class: "cbi-value-field" }, [ + gatewaysText, + gatewaysDescr, + ]); + gatewaysDiv = E("div", { class: "cbi-value" }, [ + gatewaysTitle, + gatewaysField, + ]); } var warningsDiv = []; if (reply.warnings && reply.warnings.length) { var textLabelsTable = { - warningResolverNotSupported: _("Resolver set (%s) is not supported on this system.").format(uci.get(pkg.Name, 'config', 'resolver_set')), - warningAGHVersionTooLow: _("Installed AdGuardHome (%s) doesn't support 'ipset_file' option."), + warningResolverNotSupported: _( + "Resolver set (%s) is not supported on this system." + ).format(L.uci.get(pkg.Name, "config", "resolver_set")), + warningAGHVersionTooLow: _( + "Installed AdGuardHome (%s) doesn't support 'ipset_file' option." + ), warningPolicyProcessCMD: _("%s"), - warningTorUnsetParams: _("Please unset 'src_addr', 'src_port' and 'dest_port' for policy '%s'"), - warningTorUnsetProto: _("Please unset 'proto' or set 'proto' to 'all' for policy '%s'"), - warningTorUnsetChainIpt: _("Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '%s'"), - warningTorUnsetChainNft: _("Please unset 'chain' or set 'chain' to 'prerouting' for policy '%s'"), - warningInvalidOVPNConfig: _("Invalid OpenVPN config for %s interface"), - warningOutdatedWebUIApp: _("The WebUI application is outdated (version %s), please update it"), + warningTorUnsetParams: _( + "Please unset 'src_addr', 'src_port' and 'dest_port' for policy '%s'" + ), + warningTorUnsetProto: _( + "Please unset 'proto' or set 'proto' to 'all' for policy '%s'" + ), + warningTorUnsetChainIpt: _( + "Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '%s'" + ), + warningTorUnsetChainNft: _( + "Please unset 'chain' or set 'chain' to 'prerouting' for policy '%s'" + ), + warningInvalidOVPNConfig: _( + "Invalid OpenVPN config for %s interface" + ), + warningOutdatedWebUIApp: _( + "The WebUI application is outdated (version %s), please update it" + ), + warningBadNftCallsInUserFile: _( + "Incompatible nft calls detected in user include file, disabling fw4 nft file support." + ), + warningDnsmasqInstanceNoConfdir: _( + "Dnsmasq instance (%s) targeted in settings, but it doesn't have its own confdir." + ), }; - var warningsTitle = E('label', { class: 'cbi-value-title' }, _("Service Warnings")); + var warningsTitle = E( + "label", + { class: "cbi-value-title" }, + _("Service Warnings") + ); var text = ""; - (reply.warnings).forEach(element => { + reply.warnings.forEach((element) => { if (element.id && textLabelsTable[element.id]) { - if (element.id !== 'warningPolicyProcessCMD') { - text += (textLabelsTable[element.id] + '.').format(element.extra || ' ') + "<br />"; + if (element.id !== "warningPolicyProcessCMD") { + text += + (textLabelsTable[element.id] + ".").format( + element.extra || " " + ) + "<br />"; } - } - else { - text += _("Unknown Warning.") + "<br />"; + } else { + text += _("Unknown warning") + "<br />"; } }); - var warningsText = E('div', {}, text); - var warningsField = E('div', { class: 'cbi-value-field' }, warningsText); - warningsDiv = E('div', { class: 'cbi-value' }, [warningsTitle, warningsField]); + var warningsText = E("div", {}, text); + var warningsField = E( + "div", + { class: "cbi-value-field" }, + warningsText + ); + warningsDiv = E("div", { class: "cbi-value" }, [ + warningsTitle, + warningsField, + ]); } var errorsDiv = []; if (reply.errors && reply.errors.length) { var textLabelsTable = { - errorConfigValidation: _("Config (%s) validation failure").format('/etc/config/' + pkg.Name), - errorNoIpFull: _("%s binary cannot be found").format('ip-full'), - errorNoIptables: _("%s binary cannot be found").format('iptables'), - errorNoIpset: _("Resolver set support (%s) requires ipset, but ipset binary cannot be found").format(uci.get(pkg.Name, 'config', 'resolver_set')), - errorNoNft: _("Resolver set support (%s) requires nftables, but nft binary cannot be found").format(uci.get(pkg.Name, 'config', 'resolver_set')), - errorResolverNotSupported: _("Resolver set (%s) is not supported on this system").format(uci.get(pkg.Name, 'config', 'resolver_set')), - errorServiceDisabled: _("The %s service is currently disabled").format(pkg.Name), - errorNoWanGateway: _("The %s service failed to discover WAN gateway").format(pkg.Name), - errorIpsetNameTooLong: _("The ipset name '%s' is longer than allowed 31 characters"), - errorNftsetNameTooLong: _("The nft set name '%s' is longer than allowed 31 characters"), - errorUnexpectedExit: _("Unexpected exit or service termination: '%s'"), - errorPolicyNoSrcDest: _("Policy '%s' has no source/destination parameters"), + errorConfigValidation: _("Config (%s) validation failure").format( + "/etc/config/" + pkg.Name + ), + errorNoIpFull: _("%s binary cannot be found").format("ip-full"), + errorNoIptables: _("%s binary cannot be found").format("iptables"), + errorNoIpset: _( + "Resolver set support (%s) requires ipset, but ipset binary cannot be found" + ).format(L.uci.get(pkg.Name, "config", "resolver_set")), + errorNoNft: _( + "Resolver set support (%s) requires nftables, but nft binary cannot be found" + ).format(L.uci.get(pkg.Name, "config", "resolver_set")), + errorResolverNotSupported: _( + "Resolver set (%s) is not supported on this system" + ).format(L.uci.get(pkg.Name, "config", "resolver_set")), + errorServiceDisabled: _( + "The %s service is currently disabled" + ).format(pkg.Name), + errorNoWanGateway: _( + "The %s service failed to discover WAN gateway" + ).format(pkg.Name), + errorIpsetNameTooLong: _( + "The ipset name '%s' is longer than allowed 31 characters" + ), + errorNftsetNameTooLong: _( + "The nft set name '%s' is longer than allowed 255 characters" + ), + errorUnexpectedExit: _( + "Unexpected exit or service termination: '%s'" + ), + errorPolicyNoSrcDest: _( + "Policy '%s' has no source/destination parameters" + ), errorPolicyNoInterface: _("Policy '%s' has no assigned interface"), - errorPolicyUnknownInterface: _("Policy '%s' has an unknown interface"), + errorPolicyUnknownInterface: _( + "Policy '%s' has an unknown interface" + ), errorPolicyProcessCMD: _("%s"), errorFailedSetup: _("Failed to set up '%s'"), errorFailedReload: _("Failed to reload '%s'"), errorUserFileNotFound: _("Custom user file '%s' not found or empty"), errorUserFileSyntax: _("Syntax error in custom user file '%s'"), errorUserFileRunning: _("Error running custom user file '%s'"), - errorUserFileNoCurl: _("Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed"), + errorUserFileNoCurl: _( + "Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed" + ), errorNoGateways: _("Failed to set up any gateway"), - errorResolver: _("Resolver %s"), - errorPolicyProcessNoIpv6: _("Skipping IPv6 policy '%s' as IPv6 support is disabled"), - errorPolicyProcessUnknownFwmark: _("Unknown packet mark for interface '%s'"), - errorPolicyProcessMismatchFamily: _("Mismatched IP family between in policy %s"), - errorPolicyProcessUnknownProtocol: _("Unknown protocol in policy %s"), - errorPolicyProcessInsertionFailed: _("Insertion failed for both IPv4 and IPv6 for policy %s"), - errorPolicyProcessInsertionFailedIpv4: _("Insertion failed for IPv4 for policy %s"), - errorInterfaceRoutingEmptyValues: _("Received empty tid/mark or interface name when setting up routing"), - errorFailedToResolve: _("Failed to resolve %s"), - errorInvalidOVPNConfig: _("Invalid OpenVPN config for %s interface"), + errorResolver: _("Resolver '%s'"), + errorPolicyProcessNoIpv6: _( + "Skipping IPv6 policy '%s' as IPv6 support is disabled" + ), + errorPolicyProcessUnknownFwmark: _( + "Unknown packet mark for interface '%s'" + ), + errorPolicyProcessMismatchFamily: _( + "Mismatched IP family between in policy '%s'" + ), + errorPolicyProcessUnknownProtocol: _( + "Unknown protocol in policy '%s'" + ), + errorPolicyProcessInsertionFailed: _( + "Insertion failed for both IPv4 and IPv6 for policy '%s'" + ), + errorPolicyProcessInsertionFailedIpv4: _( + "Insertion failed for IPv4 for policy '%s'" + ), + errorInterfaceRoutingEmptyValues: _( + "Received empty tid/mark or interface name when setting up routing" + ), + errorFailedToResolve: _("Failed to resolve '%s'"), + errorInvalidOVPNConfig: _( + "Invalid OpenVPN config for '%s' interface" + ), + errorNftFileInstall: _("Failed to install fw4 nft file '%s'"), + errorNoDownloadWithSecureReload: _( + "Policy '%s' refers to URL which can't be downloaded in 'secure_reload' mode!" + ), + errorDownloadUrlNoHttps: _( + "Failed to download '%s', HTTPS is not supported!" + ), + errorDownloadUrl: _("Failed to download '%s'!"), + errorFileSchemaRequiresCurl: _( + "The file:// schema requires curl, but it's not detected on this system!" + ), }; - var errorsTitle = E('label', { class: 'cbi-value-title' }, _("Service Errors")); + var errorsTitle = E( + "label", + { class: "cbi-value-title" }, + _("Service Errors") + ); var text = ""; - (reply.errors).forEach(element => { + reply.errors.forEach((element) => { if (element.id && textLabelsTable[element.id]) { - if (element.id !== 'errorPolicyProcessCMD') { - text += (textLabelsTable[element.id] + '!').format(element.extra || ' ') + "<br />"; + if (element.id !== "errorPolicyProcessCMD") { + text += + (textLabelsTable[element.id] + "!").format( + element.extra || " " + ) + "<br />"; } - } - else { - text += _("Unknown Error!") + "<br />"; + } else { + text += _("Unknown error!") + "<br />"; } }); - var errorsText = E('div', {}, text); - var errorsField = E('div', { class: 'cbi-value-field' }, errorsText); - errorsDiv = E('div', { class: 'cbi-value' }, [errorsTitle, errorsField]); + text += _("Errors encountered, please check the %sREADME%s!").format( + '<a href="' + pkg.URL + '" target="_blank">', + "</a><br />" + ); + var errorsText = E("div", {}, text); + var errorsField = E("div", { class: "cbi-value-field" }, errorsText); + errorsDiv = E("div", { class: "cbi-value" }, [ + errorsTitle, + errorsField, + ]); } - var btn_gap = E('span', {}, '  '); - var btn_gap_long = E('span', {}, '        '); + var btn_gap = E("span", {}, "  "); + var btn_gap_long = E( + "span", + {}, + "        " + ); - var btn_start = E('button', { - 'class': 'btn cbi-button cbi-button-apply', - disabled: true, - click: function (ev) { - ui.showModal(null, [ - E('p', { 'class': 'spinning' }, _('Starting %s service').format(pkg.Name)) - ]); - return RPC.setInitAction(pkg.Name, 'start'); - } - }, _('Start')); + var btn_start = E( + "button", + { + class: "btn cbi-button cbi-button-apply", + disabled: true, + click: function (ev) { + ui.showModal(null, [ + E( + "p", + { class: "spinning" }, + _("Starting %s service").format(pkg.Name) + ), + ]); + return RPC.setInitAction(pkg.Name, "start"); + }, + }, + _("Start") + ); - var btn_action = E('button', { - 'class': 'btn cbi-button cbi-button-apply', - disabled: true, - click: function (ev) { - ui.showModal(null, [ - E('p', { 'class': 'spinning' }, _('Restarting %s service').format(pkg.Name)) - ]); - return RPC.setInitAction(pkg.Name, 'restart'); - } - }, _('Restart')); + var btn_action = E( + "button", + { + class: "btn cbi-button cbi-button-apply", + disabled: true, + click: function (ev) { + ui.showModal(null, [ + E( + "p", + { class: "spinning" }, + _("Restarting %s service").format(pkg.Name) + ), + ]); + return RPC.setInitAction(pkg.Name, "restart"); + }, + }, + _("Restart") + ); - var btn_stop = E('button', { - 'class': 'btn cbi-button cbi-button-reset', - disabled: true, - click: function (ev) { - ui.showModal(null, [ - E('p', { 'class': 'spinning' }, _('Stopping %s service').format(pkg.Name)) - ]); - return RPC.setInitAction(pkg.Name, 'stop'); - } - }, _('Stop')); + var btn_stop = E( + "button", + { + class: "btn cbi-button cbi-button-reset", + disabled: true, + click: function (ev) { + ui.showModal(null, [ + E( + "p", + { class: "spinning" }, + _("Stopping %s service").format(pkg.Name) + ), + ]); + return RPC.setInitAction(pkg.Name, "stop"); + }, + }, + _("Stop") + ); - var btn_enable = E('button', { - 'class': 'btn cbi-button cbi-button-apply', - disabled: true, - click: function (ev) { - ui.showModal(null, [ - E('p', { 'class': 'spinning' }, _('Enabling %s service').format(pkg.Name)) - ]); - return RPC.setInitAction(pkg.Name, 'enable'); - } - }, _('Enable')); + var btn_enable = E( + "button", + { + class: "btn cbi-button cbi-button-apply", + disabled: true, + click: function (ev) { + ui.showModal(null, [ + E( + "p", + { class: "spinning" }, + _("Enabling %s service").format(pkg.Name) + ), + ]); + return RPC.setInitAction(pkg.Name, "enable"); + }, + }, + _("Enable") + ); - var btn_disable = E('button', { - 'class': 'btn cbi-button cbi-button-reset', - disabled: true, - click: function (ev) { - ui.showModal(null, [ - E('p', { 'class': 'spinning' }, _('Disabling %s service').format(pkg.Name)) - ]); - return RPC.setInitAction(pkg.Name, 'disable'); - } - }, _('Disable')); + var btn_disable = E( + "button", + { + class: "btn cbi-button cbi-button-reset", + disabled: true, + click: function (ev) { + ui.showModal(null, [ + E( + "p", + { class: "spinning" }, + _("Disabling %s service").format(pkg.Name) + ), + ]); + return RPC.setInitAction(pkg.Name, "disable"); + }, + }, + _("Disable") + ); if (reply.enabled) { btn_enable.disabled = true; @@ -319,14 +494,12 @@ var status = baseclass.extend({ btn_start.disabled = true; btn_action.disabled = false; btn_stop.disabled = false; - } - else { + } else { btn_start.disabled = false; btn_action.disabled = true; btn_stop.disabled = true; } - } - else { + } else { btn_start.disabled = true; btn_action.disabled = true; btn_stop.disabled = true; @@ -334,22 +507,39 @@ var status = baseclass.extend({ btn_disable.disabled = true; } - var buttonsTitle = E('label', { class: 'cbi-value-title' }, _("Service Control")) - var buttonsText = E('div', {}, [btn_start, btn_gap, btn_action, btn_gap, btn_stop, btn_gap_long, btn_enable, btn_gap, btn_disable]); - var buttonsField = E('div', { class: 'cbi-value-field' }, buttonsText); - if (reply.version) { - var buttonsDiv = E('div', { class: 'cbi-value' }, [buttonsTitle, buttonsField]); - } - else { - var buttonsDiv = []; - } - - return E('div', {}, [header, statusDiv, gatewaysDiv, warningsDiv, errorsDiv, buttonsDiv]); + var buttonsTitle = E( + "label", + { class: "cbi-value-title" }, + _("Service Control") + ); + var buttonsText = E("div", {}, [ + btn_start, + btn_gap, + btn_action, + btn_gap, + btn_stop, + btn_gap_long, + btn_enable, + btn_gap, + btn_disable, + ]); + var buttonsField = E("div", { class: "cbi-value-field" }, buttonsText); + var buttonsDiv = reply.version + ? E("div", { class: "cbi-value" }, [buttonsTitle, buttonsField]) + : ""; + return E("div", {}, [ + header, + statusDiv, + gatewaysDiv, + warningsDiv, + errorsDiv, + buttonsDiv, + ]); }); }, }); -RPC.on('setInitAction', function (reply) { +RPC.on("setInitAction", function (reply) { ui.hideModal(); location.reload(); }); @@ -357,5 +547,5 @@ RPC.on('setInitAction', function (reply) { return L.Class.extend({ status: status, getInterfaces: getInterfaces, - getPlatformSupport: getPlatformSupport + getPlatformSupport: getPlatformSupport, }); diff --git a/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js b/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js index 2b5adaeb2e..99f8a502fa 100644 --- a/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js +++ b/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js @@ -1,280 +1,404 @@ // Copyright 2022 Stan Grishin <stangri@melmac.ca> // This code wouldn't have been possible without help from [@vsviridov](https://github.com/vsviridov) -'use strict'; -'require form'; -'require rpc'; -'require uci'; -'require view'; -'require pbr.status as pbr'; +"use strict"; +"require form"; +"require rpc"; +"require view"; +"require pbr.status as pbr"; var pkg = { - get Name() { return 'pbr'; }, - get URL() { return 'https://docs.openwrt.melmac.net/' + pkg.Name + '/'; } + get Name() { + return "pbr"; + }, + + get URL() { + return "https://docs.openwrt.melmac.net/" + pkg.Name + "/"; + }, }; return view.extend({ load: function () { return Promise.all([ - uci.load(pkg.Name) + L.resolveDefault(pbr.getInterfaces(pkg.Name), {}), + L.resolveDefault(pbr.getPlatformSupport(pkg.Name), {}), + L.resolveDefault(L.uci.load(pkg.Name), {}), ]); }, - render: function () { - return Promise.all([ - L.resolveDefault(pbr.getInterfaces(), {}), - L.resolveDefault(pbr.getPlatformSupport(), {}), - ]).then(function (data) { - var arrInterfaces; - var replyPlatform; - var status, m, s, o; - - if (data[0] && data[0][pkg.Name] && data[0][pkg.Name].interfaces) { - arrInterfaces = data[0][pkg.Name].interfaces; - } - else { - arrInterfaces = ["wan"]; - } - - if (data[1] && data[1][pkg.Name]) { - replyPlatform = data[1][pkg.Name]; - } - else { - replyPlatform = { - ipset_installed: null, - nft_installed: null, - adguardhome_installed: null, - dnsmasq_installed: null, - unbound_installed: null, - adguardhome_ipset_support: null, - dnsmasq_ipset_support: null, - dnsmasq_nftset_support: null, - }; - } - - status = new pbr.status(); - m = new form.Map(pkg.Name, _("Policy Based Routing - Configuration")); - - s = m.section(form.NamedSection, 'config', pkg.Name); - s.tab("tab_basic", _("Basic Configuration")); - s.tab("tab_advanced", _("Advanced Configuration"), - _("%sWARNING:%s Please make sure to check the %sREADME%s before changing anything in this section! " + - "Change any of the settings below with extreme caution!%s").format( - "<br/>    <b>", "</b>", - "<a href=\"" + pkg.URL + "#service-configuration-settings\" target=\"_blank\">", "</a>", "<br/><br/>")); - s.tab("tab_webui", _("Web UI Configuration")) - - o = s.taboption("tab_basic", form.ListValue, "verbosity", _("Output verbosity"), - _("Controls both system log and console output verbosity.")); - o.value("0", _("Suppress/No output")); - o.value("1", _("Condensed output")); - o.value("2", _("Verbose output")); - o.default = "2"; - - o = s.taboption("tab_basic", form.ListValue, "strict_enforcement", _("Strict enforcement"), - _("See the %sREADME%s for details.").format( - "<a href=\"" + pkg.URL + "#strict-enforcement\" target=\"_blank\">", "</a>")); - o.value("0", _("Do not enforce policies when their gateway is down")); - o.value("1", _("Strictly enforce policies when their gateway is down")); - o.default = "1"; - - var text = ""; - if (replyPlatform.adguardhome_ipset_support === null) { - text += _("The %s support is unknown.").format("<i>adguardhome.ipset</i>") + "<br />" - } - else if (!(replyPlatform.adguardhome_ipset_support)) { - text += _("The %s is not supported on this system.").format("<i>adguardhome.ipset</i>") + "<br />" - } - if (replyPlatform.dnsmasq_ipset_support === null) { - text += _("The %s support is unknown.").format("<i>dnsmasq.ipset</i>") + "<br />" - } - else if (!(replyPlatform.dnsmasq_ipset_support)) { - text += _("The %s is not supported on this system.").format("<i>dnsmasq.ipset</i>") + "<br />" - } - if (replyPlatform.dnsmasq_nftset_support === null) { - text += _("The %s support is unknown.").format("<i>dnsmasq.nftset</i>") + "<br />" - } - else if (!(replyPlatform.dnsmasq_nftset_support)) { - text += _("The %s is not supported on this system.").format("<i>dnsmasq.nftset</i>") + "<br />" - } - text += _("Please check the %sREADME%s before changing this option.").format( - "<a href=\"" + pkg.URL + "#use-resolvers-set-support\" target=\"_blank\">", "</a>"); - o = s.taboption("tab_basic", form.ListValue, "resolver_set", _("Use resolver set support for domains"), text); - o.value("none", _("Disabled")); - if (replyPlatform.adguardhome_ipset_support) { - o.value("adguardhome.ipset", _("AdGuardHome ipset")); - o.default = ("adguardhome.ipset", _("AdGuardHome ipset")); - } - if (replyPlatform.dnsmasq_ipset_support) { - o.value("dnsmasq.ipset", _("Dnsmasq ipset")); - o.default = ("dnsmasq.ipset", _("Dnsmasq ipset")); - } - if (replyPlatform.dnsmasq_nftset_support) { - o.value("dnsmasq.nftset", _("Dnsmasq nft set")); - o.default = ("dnsmasq.nftset", _("Dnsmasq nft set")); + render: function (data) { + var status, m, s, o; + var reply = { + interfaces: (data[0] && + data[0][pkg.Name] && + data[0][pkg.Name].interfaces) || ["wan"], + platform: (data[1] && data[1][pkg.Name]) || { + ipset_installed: null, + nft_installed: null, + adguardhome_installed: null, + dnsmasq_installed: null, + unbound_installed: null, + adguardhome_ipset_support: null, + dnsmasq_ipset_support: null, + dnsmasq_nftset_support: null, + }, + }; + + status = new pbr.status(); + m = new form.Map(pkg.Name, _("Policy Based Routing - Configuration")); + + s = m.section(form.NamedSection, "config", pkg.Name); + s.tab("tab_basic", _("Basic Configuration")); + s.tab( + "tab_advanced", + _("Advanced Configuration"), + _( + "%sWARNING:%s Please make sure to check the %sREADME%s before changing anything in this section! " + + "Change any of the settings below with extreme caution!%s" + ).format( + "<br/>    <b>", + "</b>", + '<a href="' + + pkg.URL + + '#ServiceConfigurationSettings" target="_blank">', + "</a>", + "<br/><br/>" + ) + ); + + s.tab("tab_webui", _("Web UI Configuration")); + + o = s.taboption( + "tab_basic", + form.ListValue, + "verbosity", + _("Output verbosity"), + _("Controls both system log and console output verbosity.") + ); + o.value("0", _("Suppress/No output")); + o.value("1", _("Condensed output")); + o.value("2", _("Verbose output")); + o.default = "2"; + + o = s.taboption( + "tab_basic", + form.ListValue, + "strict_enforcement", + _("Strict enforcement"), + _("See the %sREADME%s for details.").format( + '<a href="' + pkg.URL + '#StrictEnforcement" target="_blank">', + "</a>" + ) + ); + o.value("0", _("Do not enforce policies when their gateway is down")); + o.value("1", _("Strictly enforce policies when their gateway is down")); + o.default = "1"; + + var text = ""; + if (reply.platform.adguardhome_ipset_support === null) { + text += + _("The %s support is unknown.").format("<i>adguardhome.ipset</i>") + + "<br />"; + } else if (!reply.platform.adguardhome_ipset_support) { + text += + _("The %s is not supported on this system.").format( + "<i>adguardhome.ipset</i>" + ) + "<br />"; + } + if (reply.platform.dnsmasq_ipset_support === null) { + text += + _("The %s support is unknown.").format("<i>dnsmasq.ipset</i>") + + "<br />"; + } else if (!reply.platform.dnsmasq_ipset_support) { + text += + _("The %s is not supported on this system.").format( + "<i>dnsmasq.ipset</i>" + ) + "<br />"; + } + if (reply.platform.dnsmasq_nftset_support === null) { + text += + _("The %s support is unknown.").format("<i>dnsmasq.nftset</i>") + + "<br />"; + } else if (!reply.platform.dnsmasq_nftset_support) { + text += + _("The %s is not supported on this system.").format( + "<i>dnsmasq.nftset</i>" + ) + "<br />"; + } + text += _( + "Please check the %sREADME%s before changing this option." + ).format( + '<a href="' + pkg.URL + '#UseResolversSetSupport" target="_blank">', + "</a>" + ); + + o = s.taboption( + "tab_basic", + form.ListValue, + "resolver_set", + _("Use resolver set support for domains"), + text + ); + o.value("none", _("Disabled")); + if (reply.platform.adguardhome_ipset_support) { + o.value("adguardhome.ipset", _("AdGuardHome ipset")); + o.default = "adguardhome.ipset"; + } + if (reply.platform.dnsmasq_ipset_support) { + o.value("dnsmasq.ipset", _("Dnsmasq ipset")); + o.default = "dnsmasq.ipset"; + } + if (reply.platform.dnsmasq_nftset_support) { + o.value("dnsmasq.nftset", _("Dnsmasq nft set")); + o.default = "dnsmasq.nftset"; + } + + o = s.taboption( + "tab_basic", + form.ListValue, + "ipv6_enabled", + _("IPv6 Support") + ); + o.value("0", _("Disabled")); + o.value("1", _("Enabled")); + + o = s.taboption( + "tab_advanced", + form.DynamicList, + "supported_interface", + _("Supported Interfaces"), + _( + "Allows to specify the list of interface names (in lower case) to be explicitly supported by the service. " + + "Can be useful if your OpenVPN tunnels have dev option other than tun* or tap*." + ) + ); + o.optional = false; + + o = s.taboption( + "tab_advanced", + form.DynamicList, + "ignored_interface", + _("Ignored Interfaces"), + _( + "Allows to specify the list of interface names (in lower case) to be ignored by the service. " + + "Can be useful if running both VPN server and VPN client on the router." + ) + ); + o.optional = false; + + o = s.taboption( + "tab_advanced", + form.ListValue, + "rule_create_option", + _("Rule Create option"), + _("Select Add for -A/add and Insert for -I/Insert.") + ); + o.value("add", _("Add")); + o.value("insert", _("Insert")); + o.default = "add"; + + o = s.taboption( + "tab_advanced", + form.ListValue, + "icmp_interface", + _("Default ICMP Interface"), + _("Force the ICMP protocol interface.") + ); + o.value("", _("No Change")); + reply.interfaces.forEach((element) => { + if (element.toLowerCase() !== "ignore") { + o.value(element); } - - o = s.taboption("tab_basic", form.ListValue, "ipv6_enabled", _("IPv6 Support")); - o.value("0", _("Disabled")); - o.value("1", _("Enabled")); - - o = s.taboption("tab_advanced", form.DynamicList, "supported_interface", _("Supported Interfaces"), - _("Allows to specify the list of interface names (in lower case) to be explicitly supported by the service. " + - "Can be useful if your OpenVPN tunnels have dev option other than tun* or tap*.")); - o.optional = false; - - o = s.taboption("tab_advanced", form.DynamicList, "ignored_interface", _("Ignored Interfaces"), - _("Allows to specify the list of interface names (in lower case) to be ignored by the service. " + - "Can be useful if running both VPN server and VPN client on the router.")); - o.optional = false; - - o = s.taboption("tab_advanced", form.ListValue, "rule_create_option", _("Rule Create option"), - _("Select Add for -A/add and Insert for -I/Insert.")); - o.value("add", _("Add")); - o.value("insert", _("Insert")); - o.default = "add"; - - o = s.taboption("tab_advanced", form.ListValue, "icmp_interface", _("Default ICMP Interface"), - _("Force the ICMP protocol interface.")); - o.value("", _("No Change")); - arrInterfaces.forEach(element => { - if (element.toLowerCase() !== "ignore") { - o.value(element); - } - }); - o.rmempty = true; - - o = s.taboption("tab_advanced", form.Value, "wan_tid", _("WAN Table ID"), - _("Starting (WAN) Table ID number for tables created by the service.")); - o.rmempty = true; - o.placeholder = "201"; - o.datatype = "and(uinteger, min(201))"; - - o = s.taboption("tab_advanced", form.Value, "wan_mark", _("WAN Table FW Mark"), - _("Starting (WAN) FW Mark for marks used by the service. High starting mark is " + - "used to avoid conflict with SQM/QoS. Change with caution together with") + - " " + _("Service FW Mask") + "."); - o.rmempty = true; - o.placeholder = "010000"; - o.datatype = "hexstring"; - - o = s.taboption("tab_advanced", form.Value, "fw_mask", _("Service FW Mask"), - _("FW Mask used by the service. High mask is used to avoid conflict with SQM/QoS. " + - "Change with caution together with") + " " + _("WAN Table FW Mark") + "."); - o.rmempty = true; - o.placeholder = "ff0000"; - o.datatype = "hexstring"; - - o = s.taboption("tab_webui", form.ListValue, "webui_show_ignore_target", _("Add Ignore Target"), - _("Adds 'ignore' to the list of interfaces for policies. See the %sREADME%s for details.").format( - "<a href=\"" + pkg.URL + "#ignore-target\" target=\"_blank\">", "</a>")); - o.value("0", _("Disabled")) - o.value("1", _("Enabled")) - o.default = "0"; - o.optional = false; - - o = s.taboption("tab_webui", form.DynamicList, "webui_supported_protocol", _("Supported Protocols"), - _("Display these protocols in protocol column in Web UI.")); - o.optional = false; - - s = m.section(form.GridSection, 'policy', _('Policies'), - _("Name, interface and at least one other field are required. Multiple local and remote " + + }); + o.rmempty = true; + + o = s.taboption( + "tab_advanced", + form.Value, + "wan_mark", + _("WAN Table FW Mark"), + _( + "Starting (WAN) FW Mark for marks used by the service. High starting mark is " + + "used to avoid conflict with SQM/QoS. Change with caution together with" + ) + + " " + + _("Service FW Mask") + + "." + ); + o.rmempty = true; + o.placeholder = "010000"; + o.datatype = "hexstring"; + + o = s.taboption( + "tab_advanced", + form.Value, + "fw_mask", + _("Service FW Mask"), + _( + "FW Mask used by the service. High mask is used to avoid conflict with SQM/QoS. " + + "Change with caution together with" + ) + + " " + + _("WAN Table FW Mark") + + "." + ); + o.rmempty = true; + o.placeholder = "ff0000"; + o.datatype = "hexstring"; + + o = s.taboption( + "tab_webui", + form.ListValue, + "webui_show_ignore_target", + _("Add Ignore Target"), + _( + "Adds 'ignore' to the list of interfaces for policies. See the %sREADME%s for details." + ).format( + '<a href="' + pkg.URL + '#IgnoreTarget" target="_blank">', + "</a>" + ) + ); + o.value("0", _("Disabled")); + o.value("1", _("Enabled")); + o.default = "0"; + o.optional = false; + + o = s.taboption( + "tab_webui", + form.DynamicList, + "webui_supported_protocol", + _("Supported Protocols"), + _("Display these protocols in protocol column in Web UI.") + ); + o.optional = false; + + s = m.section( + form.GridSection, + "policy", + _("Policies"), + _( + "Name, interface and at least one other field are required. Multiple local and remote " + "addresses/devices/domains and ports can be space separated. Placeholders below represent just " + - "the format/syntax and will not be used if fields are left blank.")); - s.rowcolors = true; - s.sortable = true; - s.anonymous = true; - s.addremove = true; - - o = s.option(form.Flag, "enabled", _("Enabled")); - o.default = "1"; - o.editable = true; - - o = s.option(form.Value, "name", _("Name")); - - o = s.option(form.Value, "src_addr", _("Local addresses / devices")); - o.datatype = "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network)))"; - o.rmempty = true; - o.default = ""; - - o = s.option(form.Value, "src_port", _("Local ports")); - o.datatype = "list(neg(or(portrange,port)))"; - o.placeholder = "0-65535"; - o.rmempty = true; - o.default = ""; - - o = s.option(form.Value, "dest_addr", _("Remote addresses / domains")); - o.datatype = "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network)))"; - o.rmempty = true; - o.default = ""; - - o = s.option(form.Value, "dest_port", _("Remote ports")); - o.datatype = "list(neg(or(portrange,port)))"; - o.placeholder = "0-65535"; - o.rmempty = true; - o.default = ""; - - o = s.option(form.ListValue, "proto", _("Protocol")); - var proto = L.toArray(uci.get(pkg.Name, "config", "webui_supported_protocol")); - if (!proto.length) { - proto = ["all", "tcp", "udp", "tcp udp", "icmp"] + "the format/syntax and will not be used if fields are left blank." + ) + ); + s.rowcolors = true; + s.sortable = true; + s.anonymous = true; + s.addremove = true; + + o = s.option(form.Flag, "enabled", _("Enabled")); + o.default = "1"; + o.editable = true; + + o = s.option(form.Value, "name", _("Name")); + + o = s.option(form.Value, "src_addr", _("Local addresses / devices")); + o.datatype = + "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network,string)))"; + o.rmempty = true; + o.default = ""; + + o = s.option(form.Value, "src_port", _("Local ports")); + o.datatype = "list(neg(or(portrange,port)))"; + o.placeholder = "0-65535"; + o.rmempty = true; + o.default = ""; + + o = s.option(form.Value, "dest_addr", _("Remote addresses / domains")); + o.datatype = + "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network,string)))"; + o.rmempty = true; + o.default = ""; + + o = s.option(form.Value, "dest_port", _("Remote ports")); + o.datatype = "list(neg(or(portrange,port)))"; + o.placeholder = "0-65535"; + o.rmempty = true; + o.default = ""; + + o = s.option(form.ListValue, "proto", _("Protocol")); + var proto = L.toArray( + L.uci.get(pkg.Name, "config", "webui_supported_protocol") + ); + if (!proto.length) { + proto = ["all", "tcp", "udp", "tcp udp", "icmp"]; + } + proto.forEach((element) => { + if (element === "all") { + o.value("", _("all")); + o.default = ""; + } else { + o.value(element.toLowerCase()); } - proto.forEach(element => { - if (element === "all") { - o.value("", _("all")); - o.default = ("", _("all")); - } - else { - o.value(element.toLowerCase()); - } - }); - o.rmempty = true; - - o = s.option(form.ListValue, "chain", _("Chain")); - o.value("", "prerouting"); - o.value("forward", "forward"); - o.value("input", "input"); - o.value("output", "output"); - o.value("postrouting", "postrouting"); - o.default = ("", "prerouting"); - o.rmempty = true; - - o = s.option(form.ListValue, "interface", _("Interface")); - arrInterfaces.forEach(element => { - o.value(element); - }); - o.datatype = "network"; - o.rmempty = false; - - s = m.section(form.NamedSection, 'config', pkg.Name, _("DSCP Tagging"), - _("Set DSCP tags (in range between 1 and 63) for specific interfaces. See the %sREADME%s for details.").format( - "<a href=\"" + pkg.URL + "#dscp-tag-based-policies" + "\" target=\"_blank\">", "</a>")); - arrInterfaces.forEach(element => { - if (element.toLowerCase() !== "ignore") { - o = s.option(form.Value, element + "_dscp", element.toUpperCase() + " " + _("DSCP Tag")); - o.datatype = "and(uinteger, min(1), max(63))"; - } - }); - - s = m.section(form.GridSection, 'include', _("Custom User File Includes"), - _("Run the following user files after setting up but before restarting DNSMASQ. " + - "See the %sREADME%s for details.").format( - "<a href=\"" + pkg.URL + "#custom-user-files\" target=\"_blank\">", "</a>")); - s.sortable = true; - s.anonymous = true; - s.addremove = true; - - o = s.option(form.Flag, "enabled", _("Enabled")); - o.optional = false; - o.editable = true; - o.rmempty = false; - - o = s.option(form.Value, "path", _("Path")); - o.optional = false; - o.editable = true; - o.rmempty = false; - - return Promise.all([status.render(), m.render()]); - }) - } + }); + o.rmempty = true; + + o = s.option(form.ListValue, "chain", _("Chain")); + o.value("", "prerouting"); + o.value("forward", "forward"); + o.value("input", "input"); + o.value("output", "output"); + o.value("postrouting", "postrouting"); + o.default = ""; + o.rmempty = true; + + o = s.option(form.ListValue, "interface", _("Interface")); + reply.interfaces.forEach((element) => { + o.value(element); + }); + o.datatype = "network"; + o.rmempty = false; + + s = m.section( + form.NamedSection, + "config", + pkg.Name, + _("DSCP Tagging"), + _( + "Set DSCP tags (in range between 1 and 63) for specific interfaces. See the %sREADME%s for details." + ).format( + '<a href="' + pkg.URL + "#DSCPTag-BasedPolicies" + '" target="_blank">', + "</a>" + ) + ); + reply.interfaces.forEach((element) => { + if (element.toLowerCase() !== "ignore") { + o = s.option( + form.Value, + element + "_dscp", + element.toUpperCase() + " " + _("DSCP Tag") + ); + o.datatype = "and(uinteger, min(1), max(63))"; + } + }); + + s = m.section( + form.GridSection, + "include", + _("Custom User File Includes"), + _( + "Run the following user files after setting up but before restarting DNSMASQ. " + + "See the %sREADME%s for details." + ).format( + '<a href="' + pkg.URL + '#CustomUserFiles" target="_blank">', + "</a>" + ) + ); + s.sortable = true; + s.anonymous = true; + s.addremove = true; + + o = s.option(form.Flag, "enabled", _("Enabled")); + o.optional = false; + o.editable = true; + o.rmempty = false; + + o = s.option(form.Value, "path", _("Path")); + o.optional = false; + o.editable = true; + o.rmempty = false; + + return Promise.all([status.render(), m.render()]); + }, }); diff --git a/applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js b/applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js new file mode 100644 index 0000000000..536c3983c3 --- /dev/null +++ b/applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js @@ -0,0 +1,88 @@ +"require ui"; +"require rpc"; +"require form"; +"require baseclass"; + +var pkg = { + get Name() { + return "pbr"; + }, + get URL() { + return "https://docs.openwrt.melmac.net/" + pkg.Name + "/"; + }, +}; + +var getInitStatus = rpc.declare({ + object: "luci." + pkg.Name, + method: "getInitStatus", + params: ["name"], +}); + +return baseclass.extend({ + title: _("Policy Based Routing"), + + load: function () { + return Promise.all([getInitStatus(pkg.Name)]); + }, + + render: function (data) { + var reply; + if (data[0] && data[0][pkg.Name]) { + reply = data[0][pkg.Name]; + } else { + reply = { + enabled: null, + running: null, + running_iptables: null, + running_nft: null, + running_nft_file: null, + version: null, + gateways: null, + errors: [], + warnings: [], + }; + } + + var versionText, + statusText = "", + modeText = ""; + if (reply.version) { + versionText = reply.version; + if (reply.running) { + statusText = _("Active"); + if (reply.running_iptables) { + modeText = _("iptables mode"); + } else if (reply.running_nft_file) { + modeText = _("fw4 nft file mode"); + } else if (reply.running_nft) { + modeText = _("nft mode"); + } else { + modeText = _("unknown"); + } + } else { + if (reply.enabled) { + statusText = _("Inactive"); + } else { + statusText = _("Inactive (Disabled)"); + } + } + } else { + versionText = _("Not installed or not found"); + } + + var table = E("table", { class: "table", id: "pbr_status_table" }, [ + E("tr", { class: "tr table-titles" }, [ + E("th", { class: "th" }, _("Status")), + E("th", { class: "th" }, _("Version")), + E("th", { class: "th" }, _("Mode")), + ]), + E("tr", { class: "tr" }, [ + E("td", { class: "td" }, statusText), + E("td", { class: "td" }, versionText), + E("td", { class: "td" }, modeText), + ]), + ]); + + return table; + }, +}); |