mirror of
https://github.com/itdoginfo/podkop.git
synced 2026-02-01 07:10:46 +03:00
fix: run prettier for all js files
This commit is contained in:
@@ -1,13 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
'require baseclass';
|
"require baseclass";
|
||||||
'require form';
|
"require form";
|
||||||
'require ui';
|
"require ui";
|
||||||
'require uci';
|
"require uci";
|
||||||
'require fs';
|
"require fs";
|
||||||
'require view.podkop.main as main';
|
"require view.podkop.main as main";
|
||||||
|
|
||||||
function createDashboardContent(section) {
|
function createDashboardContent(section) {
|
||||||
const o = section.option(form.DummyValue, '_mount_node');
|
const o = section.option(form.DummyValue, "_mount_node");
|
||||||
o.rawhtml = true;
|
o.rawhtml = true;
|
||||||
o.cfgvalue = () => {
|
o.cfgvalue = () => {
|
||||||
main.DashboardTab.initController();
|
main.DashboardTab.initController();
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
'require baseclass';
|
"require baseclass";
|
||||||
'require form';
|
"require form";
|
||||||
'require ui';
|
"require ui";
|
||||||
'require uci';
|
"require uci";
|
||||||
'require fs';
|
"require fs";
|
||||||
'require view.podkop.main as main';
|
"require view.podkop.main as main";
|
||||||
|
|
||||||
function createDiagnosticContent(section) {
|
function createDiagnosticContent(section) {
|
||||||
const o = section.option(form.DummyValue, '_mount_node');
|
const o = section.option(form.DummyValue, "_mount_node");
|
||||||
o.rawhtml = true;
|
o.rawhtml = true;
|
||||||
o.cfgvalue = () => {
|
o.cfgvalue = () => {
|
||||||
main.DiagnosticTab.initController();
|
main.DiagnosticTab.initController();
|
||||||
|
|||||||
@@ -1,77 +1,98 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
'require view';
|
"require view";
|
||||||
'require form';
|
"require form";
|
||||||
'require baseclass';
|
"require baseclass";
|
||||||
'require network';
|
"require network";
|
||||||
'require view.podkop.main as main';
|
"require view.podkop.main as main";
|
||||||
|
|
||||||
// Settings content
|
// Settings content
|
||||||
'require view.podkop.settings as settings';
|
"require view.podkop.settings as settings";
|
||||||
|
|
||||||
// Sections content
|
// Sections content
|
||||||
'require view.podkop.section as section';
|
"require view.podkop.section as section";
|
||||||
|
|
||||||
// Dashboard content
|
// Dashboard content
|
||||||
'require view.podkop.dashboard as dashboard';
|
"require view.podkop.dashboard as dashboard";
|
||||||
|
|
||||||
// Diagnostic content
|
// Diagnostic content
|
||||||
'require view.podkop.diagnostic as diagnostic';
|
"require view.podkop.diagnostic as diagnostic";
|
||||||
|
|
||||||
|
|
||||||
const EntryPoint = {
|
const EntryPoint = {
|
||||||
async render() {
|
async render() {
|
||||||
main.injectGlobalStyles();
|
main.injectGlobalStyles();
|
||||||
|
|
||||||
const podkopMap = new form.Map('podkop', _('Podkop Settings'), _('Configuration for Podkop service'));
|
const podkopMap = new form.Map(
|
||||||
|
"podkop",
|
||||||
|
_("Podkop Settings"),
|
||||||
|
_("Configuration for Podkop service"),
|
||||||
|
);
|
||||||
// Enable tab views
|
// Enable tab views
|
||||||
podkopMap.tabbed = true;
|
podkopMap.tabbed = true;
|
||||||
|
|
||||||
// Sections tab
|
// Sections tab
|
||||||
const sectionsSection = podkopMap.section(form.TypedSection, 'section', _('Sections'));
|
const sectionsSection = podkopMap.section(
|
||||||
|
form.TypedSection,
|
||||||
|
"section",
|
||||||
|
_("Sections"),
|
||||||
|
);
|
||||||
sectionsSection.anonymous = false;
|
sectionsSection.anonymous = false;
|
||||||
sectionsSection.addremove = true;
|
sectionsSection.addremove = true;
|
||||||
sectionsSection.template = 'cbi/simpleform';
|
sectionsSection.template = "cbi/simpleform";
|
||||||
|
|
||||||
// Render section content
|
// Render section content
|
||||||
section.createSectionContent(sectionsSection);
|
section.createSectionContent(sectionsSection);
|
||||||
|
|
||||||
// Settings tab
|
// Settings tab
|
||||||
const settingsSection = podkopMap.section(form.TypedSection, 'settings', _('Settings'));
|
const settingsSection = podkopMap.section(
|
||||||
|
form.TypedSection,
|
||||||
|
"settings",
|
||||||
|
_("Settings"),
|
||||||
|
);
|
||||||
settingsSection.anonymous = true;
|
settingsSection.anonymous = true;
|
||||||
settingsSection.addremove = false;
|
settingsSection.addremove = false;
|
||||||
// Make it named [ config settings 'settings' ]
|
// Make it named [ config settings 'settings' ]
|
||||||
settingsSection.cfgsections = function () { return ['settings']; };
|
settingsSection.cfgsections = function () {
|
||||||
|
return ["settings"];
|
||||||
|
};
|
||||||
|
|
||||||
// Render settings content
|
// Render settings content
|
||||||
settings.createSettingsContent(settingsSection);
|
settings.createSettingsContent(settingsSection);
|
||||||
|
|
||||||
|
|
||||||
// Diagnostic tab
|
// Diagnostic tab
|
||||||
const diagnosticSection = podkopMap.section(form.TypedSection, 'diagnostic', _('Diagnostics'));
|
const diagnosticSection = podkopMap.section(
|
||||||
|
form.TypedSection,
|
||||||
|
"diagnostic",
|
||||||
|
_("Diagnostics"),
|
||||||
|
);
|
||||||
diagnosticSection.anonymous = true;
|
diagnosticSection.anonymous = true;
|
||||||
diagnosticSection.addremove = false;
|
diagnosticSection.addremove = false;
|
||||||
diagnosticSection.cfgsections = function () { return ['diagnostic']; };
|
diagnosticSection.cfgsections = function () {
|
||||||
|
return ["diagnostic"];
|
||||||
|
};
|
||||||
|
|
||||||
// Render diagnostic content
|
// Render diagnostic content
|
||||||
diagnostic.createDiagnosticContent(diagnosticSection);
|
diagnostic.createDiagnosticContent(diagnosticSection);
|
||||||
|
|
||||||
// Dashboard tab
|
// Dashboard tab
|
||||||
const dashboardSection = podkopMap.section(form.TypedSection, 'dashboard', _('Dashboard'));
|
const dashboardSection = podkopMap.section(
|
||||||
|
form.TypedSection,
|
||||||
|
"dashboard",
|
||||||
|
_("Dashboard"),
|
||||||
|
);
|
||||||
dashboardSection.anonymous = true;
|
dashboardSection.anonymous = true;
|
||||||
dashboardSection.addremove = false;
|
dashboardSection.addremove = false;
|
||||||
dashboardSection.cfgsections = function () { return ['dashboard']; };
|
dashboardSection.cfgsections = function () {
|
||||||
|
return ["dashboard"];
|
||||||
|
};
|
||||||
|
|
||||||
// Render dashboard content
|
// Render dashboard content
|
||||||
dashboard.createDashboardContent(dashboardSection);
|
dashboard.createDashboardContent(dashboardSection);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Inject core service
|
// Inject core service
|
||||||
main.coreService();
|
main.coreService();
|
||||||
|
|
||||||
return podkopMap.render();
|
return podkopMap.render();
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
return view.extend(EntryPoint);
|
return view.extend(EntryPoint);
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
'require form';
|
"require form";
|
||||||
'require baseclass';
|
"require baseclass";
|
||||||
'require ui';
|
"require ui";
|
||||||
'require tools.widgets as widgets';
|
"require tools.widgets as widgets";
|
||||||
'require view.podkop.main as main';
|
"require view.podkop.main as main";
|
||||||
|
|
||||||
function createSectionContent(section) {
|
function createSectionContent(section) {
|
||||||
let o = section.option(
|
let o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'connection_type',
|
"connection_type",
|
||||||
_('Connection Type'),
|
_("Connection Type"),
|
||||||
_('Select between VPN and Proxy connection methods for traffic routing'),
|
_("Select between VPN and Proxy connection methods for traffic routing"),
|
||||||
);
|
);
|
||||||
o.value('proxy', 'Proxy');
|
o.value("proxy", "Proxy");
|
||||||
o.value('vpn', 'VPN');
|
o.value("vpn", "VPN");
|
||||||
o.value('block', 'Block');
|
o.value("block", "Block");
|
||||||
|
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'proxy_config_type',
|
"proxy_config_type",
|
||||||
_('Configuration Type'),
|
_("Configuration Type"),
|
||||||
_('Select how to configure the proxy'),
|
_("Select how to configure the proxy"),
|
||||||
);
|
);
|
||||||
o.value('url', _('Connection URL'));
|
o.value("url", _("Connection URL"));
|
||||||
o.value('outbound', _('Outbound Config'));
|
o.value("outbound", _("Outbound Config"));
|
||||||
o.value('urltest', _('URLTest'));
|
o.value("urltest", _("URLTest"));
|
||||||
o.default = 'url';
|
o.default = "url";
|
||||||
o.depends('connection_type', 'proxy');
|
o.depends("connection_type", "proxy");
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.TextValue,
|
form.TextValue,
|
||||||
'proxy_string',
|
"proxy_string",
|
||||||
_('Proxy Configuration URL'),
|
_("Proxy Configuration URL"),
|
||||||
'',
|
"",
|
||||||
);
|
);
|
||||||
o.depends('proxy_config_type', 'url');
|
o.depends("proxy_config_type", "url");
|
||||||
o.rows = 5;
|
o.rows = 5;
|
||||||
// Enable soft wrapping for multi-line proxy URLs (e.g., for URLTest proxy links)
|
// Enable soft wrapping for multi-line proxy URLs (e.g., for URLTest proxy links)
|
||||||
o.wrap = 'soft';
|
o.wrap = "soft";
|
||||||
// Render as a textarea to allow multiple proxy URLs/configs
|
// Render as a textarea to allow multiple proxy URLs/configs
|
||||||
o.textarea = true;
|
o.textarea = true;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.sectionDescriptions = new Map();
|
o.sectionDescriptions = new Map();
|
||||||
o.placeholder = 'vless://uuid@server:port?type=tcp&security=tls#main\n// backup ss://method:pass@server:port\n// backup2 vless://uuid@server:port?type=grpc&security=reality#alt\n// backup3 trojan://04agAQapcl@127.0.0.1:33641?type=tcp&security=none#trojan-tcp-none \n// socks5://127.0.0.1:1080';
|
o.placeholder =
|
||||||
|
"vless://uuid@server:port?type=tcp&security=tls#main\n// backup ss://method:pass@server:port\n// backup2 vless://uuid@server:port?type=grpc&security=reality#alt\n// backup3 trojan://04agAQapcl@127.0.0.1:33641?type=tcp&security=none#trojan-tcp-none \n// socks5://127.0.0.1:1080";
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
if (!value || value.length === 0) {
|
if (!value || value.length === 0) {
|
||||||
@@ -54,11 +54,15 @@ function createSectionContent(section) {
|
|||||||
const activeConfigs = main.splitProxyString(value);
|
const activeConfigs = main.splitProxyString(value);
|
||||||
|
|
||||||
if (!activeConfigs.length) {
|
if (!activeConfigs.length) {
|
||||||
return _('No active configuration found. One configuration is required.');
|
return _(
|
||||||
|
"No active configuration found. One configuration is required.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeConfigs.length > 1) {
|
if (activeConfigs.length > 1) {
|
||||||
return _('Multiply active configurations found. Please leave one configuration.');
|
return _(
|
||||||
|
"Multiply active configurations found. Please leave one configuration.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const validation = main.validateProxyUrl(activeConfigs[0]);
|
const validation = main.validateProxyUrl(activeConfigs[0]);
|
||||||
@@ -69,17 +73,17 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
return validation.message;
|
return validation.message;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return `${_('Invalid URL format:')} ${e?.message}`;
|
return `${_("Invalid URL format:")} ${e?.message}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.TextValue,
|
form.TextValue,
|
||||||
'outbound_json',
|
"outbound_json",
|
||||||
_('Outbound Configuration'),
|
_("Outbound Configuration"),
|
||||||
_('Enter complete outbound configuration in JSON format'),
|
_("Enter complete outbound configuration in JSON format"),
|
||||||
);
|
);
|
||||||
o.depends('proxy_config_type', 'outbound');
|
o.depends("proxy_config_type", "outbound");
|
||||||
o.rows = 10;
|
o.rows = 10;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -98,11 +102,11 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'urltest_proxy_links',
|
"urltest_proxy_links",
|
||||||
_('URLTest Proxy Links'),
|
_("URLTest Proxy Links"),
|
||||||
);
|
);
|
||||||
o.depends('proxy_config_type', 'urltest');
|
o.depends("proxy_config_type", "urltest");
|
||||||
o.placeholder = 'vless://, ss://, trojan://, socks4/5:// links';
|
o.placeholder = "vless://, ss://, trojan://, socks4/5:// links";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -121,35 +125,35 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'enable_udp_over_tcp',
|
"enable_udp_over_tcp",
|
||||||
_('Shadowsocks/Socks UDP over TCP'),
|
_("Shadowsocks/Socks UDP over TCP"),
|
||||||
_('Apply for socks/Shadowsocks 2022'),
|
_("Apply for socks/Shadowsocks 2022"),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.depends('connection_type', 'proxy');
|
o.depends("connection_type", "proxy");
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
widgets.DeviceSelect,
|
widgets.DeviceSelect,
|
||||||
'interface',
|
"interface",
|
||||||
_('Network Interface'),
|
_("Network Interface"),
|
||||||
_('Select network interface for VPN connection'),
|
_("Select network interface for VPN connection"),
|
||||||
);
|
);
|
||||||
o.depends('connection_type', 'vpn');
|
o.depends("connection_type", "vpn");
|
||||||
o.noaliases = true;
|
o.noaliases = true;
|
||||||
o.nobridges = false;
|
o.nobridges = false;
|
||||||
o.noinactive = false;
|
o.noinactive = false;
|
||||||
o.filter = function (section_id, value) {
|
o.filter = function (section_id, value) {
|
||||||
// Blocked interface names that should never be selectable
|
// Blocked interface names that should never be selectable
|
||||||
const blockedInterfaces = [
|
const blockedInterfaces = [
|
||||||
'br-lan',
|
"br-lan",
|
||||||
'eth0',
|
"eth0",
|
||||||
'eth1',
|
"eth1",
|
||||||
'wan',
|
"wan",
|
||||||
'phy0-ap0',
|
"phy0-ap0",
|
||||||
'phy1-ap0',
|
"phy1-ap0",
|
||||||
'pppoe-wan',
|
"pppoe-wan",
|
||||||
'lan',
|
"lan",
|
||||||
];
|
];
|
||||||
|
|
||||||
// Reject immediately if the value matches any blocked interface
|
// Reject immediately if the value matches any blocked interface
|
||||||
@@ -170,46 +174,46 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
// Reject wireless-related devices
|
// Reject wireless-related devices
|
||||||
const isWireless =
|
const isWireless =
|
||||||
type === 'wifi' || type === 'wireless' || type.includes('wlan');
|
type === "wifi" || type === "wireless" || type.includes("wlan");
|
||||||
|
|
||||||
return !isWireless;
|
return !isWireless;
|
||||||
};
|
};
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'domain_resolver_enabled',
|
"domain_resolver_enabled",
|
||||||
_('Domain Resolver'),
|
_("Domain Resolver"),
|
||||||
_('Enable built-in DNS resolver for domains handled by this section'),
|
_("Enable built-in DNS resolver for domains handled by this section"),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.depends('connection_type', 'vpn');
|
o.depends("connection_type", "vpn");
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'domain_resolver_dns_type',
|
"domain_resolver_dns_type",
|
||||||
_('DNS Protocol Type'),
|
_("DNS Protocol Type"),
|
||||||
_('Select the DNS protocol type for the domain resolver'),
|
_("Select the DNS protocol type for the domain resolver"),
|
||||||
);
|
);
|
||||||
o.value('doh', _('DNS over HTTPS (DoH)'));
|
o.value("doh", _("DNS over HTTPS (DoH)"));
|
||||||
o.value('dot', _('DNS over TLS (DoT)'));
|
o.value("dot", _("DNS over TLS (DoT)"));
|
||||||
o.value('udp', _('UDP (Unprotected DNS)'));
|
o.value("udp", _("UDP (Unprotected DNS)"));
|
||||||
o.default = 'udp';
|
o.default = "udp";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.depends('domain_resolver_enabled', '1');
|
o.depends("domain_resolver_enabled", "1");
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'domain_resolver_dns_server',
|
"domain_resolver_dns_server",
|
||||||
_('DNS Server'),
|
_("DNS Server"),
|
||||||
_('Select or enter DNS server address'),
|
_("Select or enter DNS server address"),
|
||||||
);
|
);
|
||||||
Object.entries(main.DNS_SERVER_OPTIONS).forEach(([key, label]) => {
|
Object.entries(main.DNS_SERVER_OPTIONS).forEach(([key, label]) => {
|
||||||
o.value(key, _(label));
|
o.value(key, _(label));
|
||||||
});
|
});
|
||||||
o.default = '8.8.8.8';
|
o.default = "8.8.8.8";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.depends('domain_resolver_enabled', '1');
|
o.depends("domain_resolver_enabled", "1");
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
const validation = main.validateDNS(value);
|
const validation = main.validateDNS(value);
|
||||||
|
|
||||||
@@ -222,12 +226,12 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'community_lists',
|
"community_lists",
|
||||||
_('Community Lists'),
|
_("Community Lists"),
|
||||||
_('Select a predefined list for routing') +
|
_("Select a predefined list for routing") +
|
||||||
' <a href="https://github.com/itdoginfo/allow-domains" target="_blank">github.com/itdoginfo/allow-domains</a>',
|
' <a href="https://github.com/itdoginfo/allow-domains" target="_blank">github.com/itdoginfo/allow-domains</a>',
|
||||||
);
|
);
|
||||||
o.placeholder = 'Service list';
|
o.placeholder = "Service list";
|
||||||
Object.entries(main.DOMAIN_LIST_OPTIONS).forEach(([key, label]) => {
|
Object.entries(main.DOMAIN_LIST_OPTIONS).forEach(([key, label]) => {
|
||||||
o.value(key, _(label));
|
o.value(key, _(label));
|
||||||
});
|
});
|
||||||
@@ -256,17 +260,17 @@ function createSectionContent(section) {
|
|||||||
(v) => v === lastSelected || !main.REGIONAL_OPTIONS.includes(v),
|
(v) => v === lastSelected || !main.REGIONAL_OPTIONS.includes(v),
|
||||||
);
|
);
|
||||||
notifications.push(
|
notifications.push(
|
||||||
E('p', { class: 'alert-message warning' }, [
|
E("p", { class: "alert-message warning" }, [
|
||||||
E('strong', {}, _('Regional options cannot be used together')),
|
E("strong", {}, _("Regional options cannot be used together")),
|
||||||
E('br'),
|
E("br"),
|
||||||
_(
|
_(
|
||||||
'Warning: %s cannot be used together with %s. Previous selections have been removed.',
|
"Warning: %s cannot be used together with %s. Previous selections have been removed.",
|
||||||
).format(removedRegions.join(', '), lastSelected),
|
).format(removedRegions.join(", "), lastSelected),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValues.includes('russia_inside')) {
|
if (newValues.includes("russia_inside")) {
|
||||||
const removedServices = newValues.filter(
|
const removedServices = newValues.filter(
|
||||||
(v) => !main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v),
|
(v) => !main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v),
|
||||||
);
|
);
|
||||||
@@ -275,18 +279,18 @@ function createSectionContent(section) {
|
|||||||
main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v),
|
main.ALLOWED_WITH_RUSSIA_INSIDE.includes(v),
|
||||||
);
|
);
|
||||||
notifications.push(
|
notifications.push(
|
||||||
E('p', { class: 'alert-message warning' }, [
|
E("p", { class: "alert-message warning" }, [
|
||||||
E('strong', {}, _('Russia inside restrictions')),
|
E("strong", {}, _("Russia inside restrictions")),
|
||||||
E('br'),
|
E("br"),
|
||||||
_(
|
_(
|
||||||
'Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection.',
|
"Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection.",
|
||||||
).format(
|
).format(
|
||||||
main.ALLOWED_WITH_RUSSIA_INSIDE.map(
|
main.ALLOWED_WITH_RUSSIA_INSIDE.map(
|
||||||
(key) => main.DOMAIN_LIST_OPTIONS[key],
|
(key) => main.DOMAIN_LIST_OPTIONS[key],
|
||||||
)
|
)
|
||||||
.filter((label) => label !== 'Russia inside')
|
.filter((label) => label !== "Russia inside")
|
||||||
.join(', '),
|
.join(", "),
|
||||||
removedServices.join(', '),
|
removedServices.join(", "),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
@@ -302,7 +306,7 @@ function createSectionContent(section) {
|
|||||||
);
|
);
|
||||||
lastValues = newValues;
|
lastValues = newValues;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error in onchange handler:', e);
|
console.error("Error in onchange handler:", e);
|
||||||
} finally {
|
} finally {
|
||||||
isProcessing = false;
|
isProcessing = false;
|
||||||
}
|
}
|
||||||
@@ -310,24 +314,26 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'user_domain_list_type',
|
"user_domain_list_type",
|
||||||
_('User Domain List Type'),
|
_("User Domain List Type"),
|
||||||
_('Select the list type for adding custom domains'),
|
_("Select the list type for adding custom domains"),
|
||||||
);
|
);
|
||||||
o.value('disabled', _('Disabled'));
|
o.value("disabled", _("Disabled"));
|
||||||
o.value('dynamic', _('Dynamic List'));
|
o.value("dynamic", _("Dynamic List"));
|
||||||
o.value('text', _('Text List'));
|
o.value("text", _("Text List"));
|
||||||
o.default = 'disabled';
|
o.default = "disabled";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'user_domains',
|
"user_domains",
|
||||||
_('User Domains'),
|
_("User Domains"),
|
||||||
_('Enter domain names without protocols, e.g. example.com or sub.example.com'),
|
_(
|
||||||
|
"Enter domain names without protocols, e.g. example.com or sub.example.com",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
o.placeholder = 'Domains list';
|
o.placeholder = "Domains list";
|
||||||
o.depends('user_domain_list_type', 'dynamic');
|
o.depends("user_domain_list_type", "dynamic");
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -346,12 +352,15 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.TextValue,
|
form.TextValue,
|
||||||
'user_domains_text',
|
"user_domains_text",
|
||||||
_('User Domains List'),
|
_("User Domains List"),
|
||||||
_('Enter domain names separated by commas, spaces, or newlines. You can add comments using //'),
|
_(
|
||||||
|
"Enter domain names separated by commas, spaces, or newlines. You can add comments using //",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
o.placeholder = 'example.com, sub.example.com\n// Social networks\ndomain.com test.com // personal domains';
|
o.placeholder =
|
||||||
o.depends('user_domain_list_type', 'text');
|
"example.com, sub.example.com\n// Social networks\ndomain.com test.com // personal domains";
|
||||||
|
o.depends("user_domain_list_type", "text");
|
||||||
o.rows = 8;
|
o.rows = 8;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
@@ -363,17 +372,21 @@ function createSectionContent(section) {
|
|||||||
const domains = main.parseValueList(value);
|
const domains = main.parseValueList(value);
|
||||||
|
|
||||||
if (!domains.length) {
|
if (!domains.length) {
|
||||||
return _('At least one valid domain must be specified. Comments-only content is not allowed.');
|
return _(
|
||||||
|
"At least one valid domain must be specified. Comments-only content is not allowed.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {valid, results} = main.bulkValidate(domains, row => main.validateDomain(row, true));
|
const { valid, results } = main.bulkValidate(domains, (row) =>
|
||||||
|
main.validateDomain(row, true),
|
||||||
|
);
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
const errors = results
|
const errors = results
|
||||||
.filter((validation) => !validation.valid) // Leave only failed validations
|
.filter((validation) => !validation.valid) // Leave only failed validations
|
||||||
.map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors
|
.map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors
|
||||||
|
|
||||||
return [_('Validation errors:'), ...errors].join('\n');
|
return [_("Validation errors:"), ...errors].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -381,24 +394,26 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'user_subnet_list_type',
|
"user_subnet_list_type",
|
||||||
_('User Subnet List Type'),
|
_("User Subnet List Type"),
|
||||||
_('Select the list type for adding custom subnets'),
|
_("Select the list type for adding custom subnets"),
|
||||||
);
|
);
|
||||||
o.value('disabled', _('Disabled'));
|
o.value("disabled", _("Disabled"));
|
||||||
o.value('dynamic', _('Dynamic List'));
|
o.value("dynamic", _("Dynamic List"));
|
||||||
o.value('text', _('Text List (comma/space/newline separated)'));
|
o.value("text", _("Text List (comma/space/newline separated)"));
|
||||||
o.default = 'disabled';
|
o.default = "disabled";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'user_subnets',
|
"user_subnets",
|
||||||
_('User Subnets'),
|
_("User Subnets"),
|
||||||
_('Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses'),
|
_(
|
||||||
|
"Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
o.placeholder = 'IP or subnet';
|
o.placeholder = "IP or subnet";
|
||||||
o.depends('user_subnet_list_type', 'dynamic');
|
o.depends("user_subnet_list_type", "dynamic");
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -417,16 +432,16 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.TextValue,
|
form.TextValue,
|
||||||
'user_subnets_text',
|
"user_subnets_text",
|
||||||
_('User Subnets List'),
|
_("User Subnets List"),
|
||||||
_(
|
_(
|
||||||
'Enter subnets in CIDR notation or single IP addresses, separated by commas, spaces, or newlines. ' +
|
"Enter subnets in CIDR notation or single IP addresses, separated by commas, spaces, or newlines. " +
|
||||||
'You can add comments using //'
|
"You can add comments using //",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.placeholder =
|
o.placeholder =
|
||||||
'103.21.244.0/22\n// Google DNS\n8.8.8.8\n1.1.1.1/32, 9.9.9.9 // Cloudflare and Quad9';
|
"103.21.244.0/22\n// Google DNS\n8.8.8.8\n1.1.1.1/32, 9.9.9.9 // Cloudflare and Quad9";
|
||||||
o.depends('user_subnet_list_type', 'text');
|
o.depends("user_subnet_list_type", "text");
|
||||||
o.rows = 10;
|
o.rows = 10;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
@@ -438,7 +453,9 @@ function createSectionContent(section) {
|
|||||||
const subnets = main.parseValueList(value);
|
const subnets = main.parseValueList(value);
|
||||||
|
|
||||||
if (!subnets.length) {
|
if (!subnets.length) {
|
||||||
return _('At least one valid subnet or IP must be specified. Comments-only content is not allowed.');
|
return _(
|
||||||
|
"At least one valid subnet or IP must be specified. Comments-only content is not allowed.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { valid, results } = main.bulkValidate(subnets, main.validateSubnet);
|
const { valid, results } = main.bulkValidate(subnets, main.validateSubnet);
|
||||||
@@ -448,7 +465,7 @@ function createSectionContent(section) {
|
|||||||
.filter((validation) => !validation.valid) // Leave only failed validations
|
.filter((validation) => !validation.valid) // Leave only failed validations
|
||||||
.map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors
|
.map((validation) => _(`${validation.value}: ${validation.message}`)); // Collect validation errors
|
||||||
|
|
||||||
return [_('Validation errors:'), ...errors].join('\n');
|
return [_("Validation errors:"), ...errors].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -456,11 +473,11 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'local_domain_lists',
|
"local_domain_lists",
|
||||||
_('Local Domain Lists'),
|
_("Local Domain Lists"),
|
||||||
_('Specify the path to the list file located on the router filesystem'),
|
_("Specify the path to the list file located on the router filesystem"),
|
||||||
);
|
);
|
||||||
o.placeholder = '/path/file.lst';
|
o.placeholder = "/path/file.lst";
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -479,11 +496,11 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'local_subnet_lists',
|
"local_subnet_lists",
|
||||||
_('Local Subnet Lists'),
|
_("Local Subnet Lists"),
|
||||||
_('Specify the path to the list file located on the router filesystem'),
|
_("Specify the path to the list file located on the router filesystem"),
|
||||||
);
|
);
|
||||||
o.placeholder = '/path/file.lst';
|
o.placeholder = "/path/file.lst";
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -502,11 +519,11 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'remote_domain_lists',
|
"remote_domain_lists",
|
||||||
_('Remote Domain Lists'),
|
_("Remote Domain Lists"),
|
||||||
_('Specify remote URLs to download and use domain lists'),
|
_("Specify remote URLs to download and use domain lists"),
|
||||||
);
|
);
|
||||||
o.placeholder = 'https://example.com/domains.srs';
|
o.placeholder = "https://example.com/domains.srs";
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -525,11 +542,11 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'remote_subnet_lists',
|
"remote_subnet_lists",
|
||||||
_('Remote Subnet Lists'),
|
_("Remote Subnet Lists"),
|
||||||
_('Specify remote URLs to download and use subnet lists'),
|
_("Specify remote URLs to download and use subnet lists"),
|
||||||
);
|
);
|
||||||
o.placeholder = 'https://example.com/subnets.srs';
|
o.placeholder = "https://example.com/subnets.srs";
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -548,11 +565,13 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'fully_routed_ips',
|
"fully_routed_ips",
|
||||||
_('Fully Routed IPs'),
|
_("Fully Routed IPs"),
|
||||||
_('Specify local IP addresses or subnets whose traffic will always be routed through the configured route'),
|
_(
|
||||||
|
"Specify local IP addresses or subnets whose traffic will always be routed through the configured route",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
o.placeholder = '192.168.1.2 or 192.168.1.0/24';
|
o.placeholder = "192.168.1.2 or 192.168.1.0/24";
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -571,28 +590,30 @@ function createSectionContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'mixed_proxy_enabled',
|
"mixed_proxy_enabled",
|
||||||
_('Enable Mixed Proxy'),
|
_("Enable Mixed Proxy"),
|
||||||
_('Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies'),
|
_(
|
||||||
|
"Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'mixed_proxy_port',
|
"mixed_proxy_port",
|
||||||
_('Mixed Proxy Port'),
|
_("Mixed Proxy Port"),
|
||||||
_(
|
_(
|
||||||
'Specify the port number on which the mixed proxy will run for this section. ' +
|
"Specify the port number on which the mixed proxy will run for this section. " +
|
||||||
'Make sure the selected port is not used by another service'
|
"Make sure the selected port is not used by another service",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.depends('mixed_proxy_enabled', '1');
|
o.depends("mixed_proxy_enabled", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
const EntryPoint = {
|
const EntryPoint = {
|
||||||
createSectionContent,
|
createSectionContent,
|
||||||
}
|
};
|
||||||
|
|
||||||
return baseclass.extend(EntryPoint);
|
return baseclass.extend(EntryPoint);
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
'use strict';
|
"use strict";
|
||||||
'require form';
|
"require form";
|
||||||
'require uci';
|
"require uci";
|
||||||
'require baseclass';
|
"require baseclass";
|
||||||
'require tools.widgets as widgets';
|
"require tools.widgets as widgets";
|
||||||
'require view.podkop.main as main';
|
"require view.podkop.main as main";
|
||||||
|
|
||||||
function createSettingsContent(section) {
|
function createSettingsContent(section) {
|
||||||
let o = section.option(
|
let o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'dns_type',
|
"dns_type",
|
||||||
_('DNS Protocol Type'),
|
_("DNS Protocol Type"),
|
||||||
_('Select DNS protocol to use'),
|
_("Select DNS protocol to use"),
|
||||||
);
|
);
|
||||||
o.value('doh', _('DNS over HTTPS (DoH)'));
|
o.value("doh", _("DNS over HTTPS (DoH)"));
|
||||||
o.value('dot', _('DNS over TLS (DoT)'));
|
o.value("dot", _("DNS over TLS (DoT)"));
|
||||||
o.value('udp', _('UDP (Unprotected DNS)'));
|
o.value("udp", _("UDP (Unprotected DNS)"));
|
||||||
o.default = 'udp';
|
o.default = "udp";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'dns_server',
|
"dns_server",
|
||||||
_('DNS Server'),
|
_("DNS Server"),
|
||||||
_('Select or enter DNS server address'),
|
_("Select or enter DNS server address"),
|
||||||
);
|
);
|
||||||
Object.entries(main.DNS_SERVER_OPTIONS).forEach(([key, label]) => {
|
Object.entries(main.DNS_SERVER_OPTIONS).forEach(([key, label]) => {
|
||||||
o.value(key, _(label));
|
o.value(key, _(label));
|
||||||
});
|
});
|
||||||
o.default = '8.8.8.8';
|
o.default = "8.8.8.8";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
const validation = main.validateDNS(value);
|
const validation = main.validateDNS(value);
|
||||||
@@ -41,16 +41,16 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'bootstrap_dns_server',
|
"bootstrap_dns_server",
|
||||||
_('Bootstrap DNS server'),
|
_("Bootstrap DNS server"),
|
||||||
_(
|
_(
|
||||||
'The DNS server used to look up the IP address of an upstream DNS server',
|
"The DNS server used to look up the IP address of an upstream DNS server",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
Object.entries(main.BOOTSTRAP_DNS_SERVER_OPTIONS).forEach(([key, label]) => {
|
Object.entries(main.BOOTSTRAP_DNS_SERVER_OPTIONS).forEach(([key, label]) => {
|
||||||
o.value(key, _(label));
|
o.value(key, _(label));
|
||||||
});
|
});
|
||||||
o.default = '77.88.8.8';
|
o.default = "77.88.8.8";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
const validation = main.validateDNS(value);
|
const validation = main.validateDNS(value);
|
||||||
@@ -64,20 +64,20 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'dns_rewrite_ttl',
|
"dns_rewrite_ttl",
|
||||||
_('DNS Rewrite TTL'),
|
_("DNS Rewrite TTL"),
|
||||||
_('Time in seconds for DNS record caching (default: 60)'),
|
_("Time in seconds for DNS record caching (default: 60)"),
|
||||||
);
|
);
|
||||||
o.default = '60';
|
o.default = "60";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return _('TTL value cannot be empty');
|
return _("TTL value cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
const ttl = parseInt(value);
|
const ttl = parseInt(value);
|
||||||
if (isNaN(ttl) || ttl < 0) {
|
if (isNaN(ttl) || ttl < 0) {
|
||||||
return _('TTL must be a positive number');
|
return _("TTL must be a positive number");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -85,25 +85,25 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'enable_output_network_interface',
|
"enable_output_network_interface",
|
||||||
_('Enable Output Network Interface'),
|
_("Enable Output Network Interface"),
|
||||||
_('You can select Output Network Interface, by default autodetect'),
|
_("You can select Output Network Interface, by default autodetect"),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
widgets.DeviceSelect,
|
widgets.DeviceSelect,
|
||||||
'output_network_interface',
|
"output_network_interface",
|
||||||
_('Output Network Interface'),
|
_("Output Network Interface"),
|
||||||
_('Select the network interface to which the traffic will originate'),
|
_("Select the network interface to which the traffic will originate"),
|
||||||
);
|
);
|
||||||
o.noaliases = true;
|
o.noaliases = true;
|
||||||
o.multiple = false;
|
o.multiple = false;
|
||||||
o.depends('enable_output_network_interface', '1');
|
o.depends("enable_output_network_interface", "1");
|
||||||
o.filter = function (section_id, value) {
|
o.filter = function (section_id, value) {
|
||||||
// Blocked interface names that should never be selectable
|
// Blocked interface names that should never be selectable
|
||||||
const blockedInterfaces = ['br-lan'];
|
const blockedInterfaces = ["br-lan"];
|
||||||
|
|
||||||
// Reject immediately if the value matches any blocked interface
|
// Reject immediately if the value matches any blocked interface
|
||||||
if (blockedInterfaces.includes(value)) {
|
if (blockedInterfaces.includes(value)) {
|
||||||
@@ -112,11 +112,11 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
// Reject tun*, wg*, vpn*, awg*, oc*
|
// Reject tun*, wg*, vpn*, awg*, oc*
|
||||||
if (
|
if (
|
||||||
value.startsWith('tun') ||
|
value.startsWith("tun") ||
|
||||||
value.startsWith('wg') ||
|
value.startsWith("wg") ||
|
||||||
value.startsWith('vpn') ||
|
value.startsWith("vpn") ||
|
||||||
value.startsWith('awg') ||
|
value.startsWith("awg") ||
|
||||||
value.startsWith('oc')
|
value.startsWith("oc")
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -134,25 +134,25 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
// Reject wireless-related devices
|
// Reject wireless-related devices
|
||||||
const isWireless =
|
const isWireless =
|
||||||
type === 'wifi' || type === 'wireless' || type.includes('wlan');
|
type === "wifi" || type === "wireless" || type.includes("wlan");
|
||||||
|
|
||||||
return !isWireless;
|
return !isWireless;
|
||||||
};
|
};
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
widgets.DeviceSelect,
|
widgets.DeviceSelect,
|
||||||
'source_network_interfaces',
|
"source_network_interfaces",
|
||||||
_('Source Network Interface'),
|
_("Source Network Interface"),
|
||||||
_('Select the network interface from which the traffic will originate'),
|
_("Select the network interface from which the traffic will originate"),
|
||||||
);
|
);
|
||||||
o.default = 'br-lan';
|
o.default = "br-lan";
|
||||||
o.noaliases = true;
|
o.noaliases = true;
|
||||||
o.nobridges = false;
|
o.nobridges = false;
|
||||||
o.noinactive = false;
|
o.noinactive = false;
|
||||||
o.multiple = true;
|
o.multiple = true;
|
||||||
o.filter = function (section_id, value) {
|
o.filter = function (section_id, value) {
|
||||||
// Block specific interface names from being selectable
|
// Block specific interface names from being selectable
|
||||||
const blocked = ['wan', 'phy0-ap0', 'phy1-ap0', 'pppoe-wan'];
|
const blocked = ["wan", "phy0-ap0", "phy1-ap0", "pppoe-wan"];
|
||||||
if (blocked.includes(value)) {
|
if (blocked.includes(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
// Consider any Wi-Fi / wireless / wlan device as invalid
|
// Consider any Wi-Fi / wireless / wlan device as invalid
|
||||||
const isWireless =
|
const isWireless =
|
||||||
type === 'wifi' || type === 'wireless' || type.includes('wlan');
|
type === "wifi" || type === "wireless" || type.includes("wlan");
|
||||||
|
|
||||||
// Allow only non-wireless devices
|
// Allow only non-wireless devices
|
||||||
return !isWireless;
|
return !isWireless;
|
||||||
@@ -178,29 +178,29 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'enable_badwan_interface_monitoring',
|
"enable_badwan_interface_monitoring",
|
||||||
_('Interface Monitoring'),
|
_("Interface Monitoring"),
|
||||||
_('Interface monitoring for Bad WAN'),
|
_("Interface monitoring for Bad WAN"),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
widgets.NetworkSelect,
|
widgets.NetworkSelect,
|
||||||
'badwan_monitored_interfaces',
|
"badwan_monitored_interfaces",
|
||||||
_('Monitored Interfaces'),
|
_("Monitored Interfaces"),
|
||||||
_('Select the WAN interfaces to be monitored'),
|
_("Select the WAN interfaces to be monitored"),
|
||||||
);
|
);
|
||||||
o.depends('enable_badwan_interface_monitoring', '1');
|
o.depends("enable_badwan_interface_monitoring", "1");
|
||||||
o.multiple = true;
|
o.multiple = true;
|
||||||
o.filter = function (section_id, value) {
|
o.filter = function (section_id, value) {
|
||||||
// Reject if the value is in the blocked list ['lan', 'loopback']
|
// Reject if the value is in the blocked list ['lan', 'loopback']
|
||||||
if (['lan', 'loopback'].includes(value)) {
|
if (["lan", "loopback"].includes(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject if the value starts with '@' (means it's an alias/reference)
|
// Reject if the value starts with '@' (means it's an alias/reference)
|
||||||
if (value.startsWith('@')) {
|
if (value.startsWith("@")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,72 +210,72 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'badwan_reload_delay',
|
"badwan_reload_delay",
|
||||||
_('Interface Monitoring Delay'),
|
_("Interface Monitoring Delay"),
|
||||||
_('Delay in milliseconds before reloading podkop after interface UP'),
|
_("Delay in milliseconds before reloading podkop after interface UP"),
|
||||||
);
|
);
|
||||||
o.depends('enable_badwan_interface_monitoring', '1');
|
o.depends("enable_badwan_interface_monitoring", "1");
|
||||||
o.default = '2000';
|
o.default = "2000";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return _('Delay value cannot be empty');
|
return _("Delay value cannot be empty");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'enable_yacd',
|
"enable_yacd",
|
||||||
_('Enable YACD'),
|
_("Enable YACD"),
|
||||||
`<a href="${main.getClashUIUrl()}" target="_blank">${main.getClashUIUrl()}</a>`,
|
`<a href="${main.getClashUIUrl()}" target="_blank">${main.getClashUIUrl()}</a>`,
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'disable_quic',
|
"disable_quic",
|
||||||
_('Disable QUIC'),
|
_("Disable QUIC"),
|
||||||
_(
|
_(
|
||||||
'Disable the QUIC protocol to improve compatibility or fix issues with video streaming',
|
"Disable the QUIC protocol to improve compatibility or fix issues with video streaming",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'update_interval',
|
"update_interval",
|
||||||
_('List Update Frequency'),
|
_("List Update Frequency"),
|
||||||
_('Select how often the domain or subnet lists are updated automatically'),
|
_("Select how often the domain or subnet lists are updated automatically"),
|
||||||
);
|
);
|
||||||
Object.entries(main.UPDATE_INTERVAL_OPTIONS).forEach(([key, label]) => {
|
Object.entries(main.UPDATE_INTERVAL_OPTIONS).forEach(([key, label]) => {
|
||||||
o.value(key, _(label));
|
o.value(key, _(label));
|
||||||
});
|
});
|
||||||
o.default = '1d';
|
o.default = "1d";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'download_lists_via_proxy',
|
"download_lists_via_proxy",
|
||||||
_('Download Lists via Proxy/VPN'),
|
_("Download Lists via Proxy/VPN"),
|
||||||
_('Downloading all lists via main Proxy/VPN'),
|
_("Downloading all lists via main Proxy/VPN"),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'download_lists_via_proxy_section',
|
"download_lists_via_proxy_section",
|
||||||
_('Download Lists via specific proxy section'),
|
_("Download Lists via specific proxy section"),
|
||||||
_('Downloading all lists via specific Proxy/VPN'),
|
_("Downloading all lists via specific Proxy/VPN"),
|
||||||
);
|
);
|
||||||
|
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.depends('download_lists_via_proxy', '1');
|
o.depends("download_lists_via_proxy", "1");
|
||||||
o.cfgvalue = function (section_id) {
|
o.cfgvalue = function (section_id) {
|
||||||
return uci.get('podkop', section_id, 'download_lists_via_proxy_section');
|
return uci.get("podkop", section_id, "download_lists_via_proxy_section");
|
||||||
};
|
};
|
||||||
o.load = function () {
|
o.load = function () {
|
||||||
const sections = this.map?.data?.state?.values?.podkop ?? {};
|
const sections = this.map?.data?.state?.values?.podkop ?? {};
|
||||||
@@ -285,7 +285,7 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
for (const secName in sections) {
|
for (const secName in sections) {
|
||||||
const sec = sections[secName];
|
const sec = sections[secName];
|
||||||
if (sec['.type'] === 'section') {
|
if (sec[".type"] === "section") {
|
||||||
this.keylist.push(secName);
|
this.keylist.push(secName);
|
||||||
this.vallist.push(secName);
|
this.vallist.push(secName);
|
||||||
}
|
}
|
||||||
@@ -296,57 +296,57 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'dont_touch_dhcp',
|
"dont_touch_dhcp",
|
||||||
_('Dont Touch My DHCP!'),
|
_("Dont Touch My DHCP!"),
|
||||||
_('Podkop will not modify your DHCP configuration'),
|
_("Podkop will not modify your DHCP configuration"),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.ListValue,
|
form.ListValue,
|
||||||
'config_path',
|
"config_path",
|
||||||
_('Config File Path'),
|
_("Config File Path"),
|
||||||
_(
|
_(
|
||||||
'Select path for sing-box config file. Change this ONLY if you know what you are doing',
|
"Select path for sing-box config file. Change this ONLY if you know what you are doing",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.value('/etc/sing-box/config.json', 'Flash (/etc/sing-box/config.json)');
|
o.value("/etc/sing-box/config.json", "Flash (/etc/sing-box/config.json)");
|
||||||
o.value('/tmp/sing-box/config.json', 'RAM (/tmp/sing-box/config.json)');
|
o.value("/tmp/sing-box/config.json", "RAM (/tmp/sing-box/config.json)");
|
||||||
o.default = '/etc/sing-box/config.json';
|
o.default = "/etc/sing-box/config.json";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Value,
|
form.Value,
|
||||||
'cache_path',
|
"cache_path",
|
||||||
_('Cache File Path'),
|
_("Cache File Path"),
|
||||||
_(
|
_(
|
||||||
'Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing',
|
"Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.value('/tmp/sing-box/cache.db', 'RAM (/tmp/sing-box/cache.db)');
|
o.value("/tmp/sing-box/cache.db", "RAM (/tmp/sing-box/cache.db)");
|
||||||
o.value(
|
o.value(
|
||||||
'/usr/share/sing-box/cache.db',
|
"/usr/share/sing-box/cache.db",
|
||||||
'Flash (/usr/share/sing-box/cache.db)',
|
"Flash (/usr/share/sing-box/cache.db)",
|
||||||
);
|
);
|
||||||
o.default = '/tmp/sing-box/cache.db';
|
o.default = "/tmp/sing-box/cache.db";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return _('Cache file path cannot be empty');
|
return _("Cache file path cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value.startsWith('/')) {
|
if (!value.startsWith("/")) {
|
||||||
return _('Path must be absolute (start with /)');
|
return _("Path must be absolute (start with /)");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value.endsWith('cache.db')) {
|
if (!value.endsWith("cache.db")) {
|
||||||
return _('Path must end with cache.db');
|
return _("Path must end with cache.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts = value.split('/').filter(Boolean);
|
const parts = value.split("/").filter(Boolean);
|
||||||
if (parts.length < 2) {
|
if (parts.length < 2) {
|
||||||
return _('Path must contain at least one directory (like /tmp/cache.db)');
|
return _("Path must contain at least one directory (like /tmp/cache.db)");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -354,22 +354,22 @@ function createSettingsContent(section) {
|
|||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
'exclude_ntp',
|
"exclude_ntp",
|
||||||
_('Exclude NTP'),
|
_("Exclude NTP"),
|
||||||
_(
|
_(
|
||||||
'Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN',
|
"Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
o.default = '0';
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
'routing_excluded_ips',
|
"routing_excluded_ips",
|
||||||
_('Routing Excluded IPs'),
|
_("Routing Excluded IPs"),
|
||||||
_('Specify a local IP address to be excluded from routing'),
|
_("Specify a local IP address to be excluded from routing"),
|
||||||
);
|
);
|
||||||
o.placeholder = 'IP';
|
o.placeholder = "IP";
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
|
|||||||
Reference in New Issue
Block a user