From b78682919a9fcab60f7337ac11b7f518c79cb7a1 Mon Sep 17 00:00:00 2001 From: divocat Date: Tue, 21 Oct 2025 11:32:29 +0300 Subject: [PATCH] chore: remove comments support for proxy url --- .../luci-static/resources/view/podkop/main.js | 1560 +++++++++-------- .../resources/view/podkop/section.js | 31 +- .../resources/view/podkop/settings.js | 74 +- 3 files changed, 874 insertions(+), 791 deletions(-) diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js index 9f60cd7..81d7460 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js @@ -1,4 +1,4 @@ -// This file is autogenerated, please don't change manually +// This file is autogenerated, please don't change manually "use strict"; "require baseclass"; "require fs"; @@ -7,7 +7,8 @@ // src/validators/validateIp.ts function validateIPV4(ip) { - const ipRegex = /^(?:(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/; + const ipRegex = + /^(?:(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/; if (ipRegex.test(ip)) { return { valid: true, message: _("Valid") }; } @@ -16,7 +17,8 @@ function validateIPV4(ip) { // src/validators/validateDomain.ts function validateDomain(domain, allowDotTLD = false) { - const domainRegex = /^(?=.{1,253}(?:\/|$))(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)\.)+(?:[a-zA-Z]{2,}|xn--[a-zA-Z0-9-]{1,59}[a-zA-Z0-9])(?:\/[^\s]*)?$/; + const domainRegex = + /^(?=.{1,253}(?:\/|$))(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)\.)+(?:[a-zA-Z]{2,}|xn--[a-zA-Z0-9-]{1,59}[a-zA-Z0-9])(?:\/[^\s]*)?$/; if (allowDotTLD) { const dotTLD = /^\.[a-zA-Z]{2,}$/; if (dotTLD.test(domain)) { @@ -49,8 +51,8 @@ function validateDNS(value) { return { valid: false, message: _( - "Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH" - ) + "Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH", + ), }; } @@ -61,7 +63,7 @@ function validateUrl(url, protocols = ["http:", "https:"]) { if (!protocols.includes(parsedUrl.protocol)) { return { valid: false, - message: `${_("URL must use one of the following protocols:")} ${protocols.join(", ")}` + message: `${_("URL must use one of the following protocols:")} ${protocols.join(", ")}`, }; } return { valid: true, message: _("Valid") }; @@ -75,21 +77,21 @@ function validatePath(value) { if (!value) { return { valid: false, - message: _("Path cannot be empty") + message: _("Path cannot be empty"), }; } const pathRegex = /^\/[a-zA-Z0-9_\-/.]+$/; if (pathRegex.test(value)) { return { valid: true, - message: _("Valid") + message: _("Valid"), }; } return { valid: false, message: _( - 'Invalid path format. Path must start with "/" and contain valid characters' - ) + 'Invalid path format. Path must start with "/" and contain valid characters', + ), }; } @@ -99,7 +101,7 @@ function validateSubnet(value) { if (!subnetRegex.test(value)) { return { valid: false, - message: _("Invalid format. Use X.X.X.X or X.X.X.X/Y") + message: _("Invalid format. Use X.X.X.X or X.X.X.X/Y"), }; } const [ip, cidr] = value.split("/"); @@ -115,7 +117,7 @@ function validateSubnet(value) { if (cidrNum < 0 || cidrNum > 32) { return { valid: false, - message: _("CIDR must be between 0 and 32") + message: _("CIDR must be between 0 and 32"), }; } } @@ -127,7 +129,7 @@ function bulkValidate(values, validate) { const results = values.map((value) => ({ ...validate(value), value })); return { valid: results.every((r) => r.valid), - results + results, }; } @@ -136,14 +138,14 @@ function validateShadowsocksUrl(url) { if (!url.startsWith("ss://")) { return { valid: false, - message: _("Invalid Shadowsocks URL: must start with ss://") + message: _("Invalid Shadowsocks URL: must start with ss://"), }; } try { if (!url || /\s/.test(url)) { return { valid: false, - message: _("Invalid Shadowsocks URL: must not contain spaces") + message: _("Invalid Shadowsocks URL: must not contain spaces"), }; } const mainPart = url.includes("?") ? url.split("?")[0] : url.split("#")[0]; @@ -151,7 +153,7 @@ function validateShadowsocksUrl(url) { if (!encryptedPart) { return { valid: false, - message: _("Invalid Shadowsocks URL: missing credentials") + message: _("Invalid Shadowsocks URL: missing credentials"), }; } try { @@ -160,8 +162,8 @@ function validateShadowsocksUrl(url) { return { valid: false, message: _( - "Invalid Shadowsocks URL: decoded credentials must contain method:password" - ) + "Invalid Shadowsocks URL: decoded credentials must contain method:password", + ), }; } } catch (_e) { @@ -169,8 +171,8 @@ function validateShadowsocksUrl(url) { return { valid: false, message: _( - 'Invalid Shadowsocks URL: missing method and password separator ":"' - ) + 'Invalid Shadowsocks URL: missing method and password separator ":"', + ), }; } } @@ -178,34 +180,34 @@ function validateShadowsocksUrl(url) { if (!serverPart) { return { valid: false, - message: _("Invalid Shadowsocks URL: missing server address") + message: _("Invalid Shadowsocks URL: missing server address"), }; } const [server, portAndRest] = serverPart.split(":"); if (!server) { return { valid: false, - message: _("Invalid Shadowsocks URL: missing server") + message: _("Invalid Shadowsocks URL: missing server"), }; } const port = portAndRest ? portAndRest.split(/[?#]/)[0] : null; if (!port) { return { valid: false, - message: _("Invalid Shadowsocks URL: missing port") + message: _("Invalid Shadowsocks URL: missing port"), }; } const portNum = parseInt(port, 10); if (isNaN(portNum) || portNum < 1 || portNum > 65535) { return { valid: false, - message: _("Invalid port number. Must be between 1 and 65535") + message: _("Invalid port number. Must be between 1 and 65535"), }; } } catch (_e) { return { valid: false, - message: _("Invalid Shadowsocks URL: parsing failed") + message: _("Invalid Shadowsocks URL: parsing failed"), }; } return { valid: true, message: _("Valid") }; @@ -214,8 +216,10 @@ function validateShadowsocksUrl(url) { // src/helpers/parseQueryString.ts function parseQueryString(query) { const clean = query.startsWith("?") ? query.slice(1) : query; - return clean.split("&").filter(Boolean).reduce( - (acc, pair) => { + return clean + .split("&") + .filter(Boolean) + .reduce((acc, pair) => { const [rawKey, rawValue = ""] = pair.split("="); if (!rawKey) { return acc; @@ -223,9 +227,7 @@ function parseQueryString(query) { const key = decodeURIComponent(rawKey); const value = decodeURIComponent(rawValue); return { ...acc, [key]: value }; - }, - {} - ); + }, {}); } // src/validators/validateVlessUrl.ts @@ -234,12 +236,12 @@ function validateVlessUrl(url) { if (!url.startsWith("vless://")) return { valid: false, - message: "Invalid VLESS URL: must start with vless://" + message: "Invalid VLESS URL: must start with vless://", }; if (/\s/.test(url)) return { valid: false, - message: "Invalid VLESS URL: must not contain spaces" + message: "Invalid VLESS URL: must not contain spaces", }; const body = url.slice("vless://".length); const [mainPart] = body.split("#"); @@ -247,7 +249,7 @@ function validateVlessUrl(url) { if (!userHostPort) return { valid: false, - message: "Invalid VLESS URL: missing host and UUID" + message: "Invalid VLESS URL: missing host and UUID", }; const [userPart, hostPortPart] = userHostPort.split("@"); if (!userPart) @@ -263,12 +265,12 @@ function validateVlessUrl(url) { if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) return { valid: false, - message: "Invalid VLESS URL: invalid port number" + message: "Invalid VLESS URL: invalid port number", }; if (!queryString) return { valid: false, - message: "Invalid VLESS URL: missing query parameters" + message: "Invalid VLESS URL: missing query parameters", }; const params = parseQueryString(queryString); const validTypes = [ @@ -280,35 +282,36 @@ function validateVlessUrl(url) { "httpupgrade", "xhttp", "ws", - "kcp" + "kcp", ]; const validSecurities = ["tls", "reality", "none"]; if (!params.type || !validTypes.includes(params.type)) return { valid: false, - message: "Invalid VLESS URL: unsupported or missing type" + message: "Invalid VLESS URL: unsupported or missing type", }; if (!params.security || !validSecurities.includes(params.security)) return { valid: false, - message: "Invalid VLESS URL: unsupported or missing security" + message: "Invalid VLESS URL: unsupported or missing security", }; if (params.security === "reality") { if (!params.pbk) return { valid: false, - message: "Invalid VLESS URL: missing pbk for reality" + message: "Invalid VLESS URL: missing pbk for reality", }; if (!params.fp) return { valid: false, - message: "Invalid VLESS URL: missing fp for reality" + message: "Invalid VLESS URL: missing fp for reality", }; } if (params.flow === "xtls-rprx-vision-udp443") { return { valid: false, - message: "Invalid VLESS URL: flow xtls-rprx-vision-udp443 does not supported" + message: + "Invalid VLESS URL: flow xtls-rprx-vision-udp443 does not supported", }; } return { valid: true, message: _("Valid") }; @@ -325,8 +328,8 @@ function validateOutboundJson(value) { return { valid: false, message: _( - 'Outbound JSON must contain at least "type", "server" and "server_port" fields' - ) + 'Outbound JSON must contain at least "type", "server" and "server_port" fields', + ), }; } return { valid: true, message: _("Valid") }; @@ -341,13 +344,13 @@ function validateTrojanUrl(url) { if (!url.startsWith("trojan://")) { return { valid: false, - message: _("Invalid Trojan URL: must start with trojan://") + message: _("Invalid Trojan URL: must start with trojan://"), }; } if (!url || /\s/.test(url)) { return { valid: false, - message: _("Invalid Trojan URL: must not contain spaces") + message: _("Invalid Trojan URL: must not contain spaces"), }; } const body = url.slice("trojan://".length); @@ -357,14 +360,14 @@ function validateTrojanUrl(url) { if (!userHostPort) return { valid: false, - message: "Invalid Trojan URL: missing credentials and host" + message: "Invalid Trojan URL: missing credentials and host", }; if (!userPart) return { valid: false, message: "Invalid Trojan URL: missing password" }; if (!hostPortPart) return { valid: false, - message: "Invalid Trojan URL: missing hostname and port" + message: "Invalid Trojan URL: missing hostname and port", }; const [host, port] = hostPortPart.split(":"); if (!host) @@ -375,7 +378,7 @@ function validateTrojanUrl(url) { if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) return { valid: false, - message: "Invalid Trojan URL: invalid port number" + message: "Invalid Trojan URL: invalid port number", }; } catch (_e) { return { valid: false, message: _("Invalid Trojan URL: parsing failed") }; @@ -390,39 +393,41 @@ function validateSocksUrl(url) { return { valid: false, message: _( - "Invalid SOCKS URL: must start with socks4://, socks4a://, or socks5://" - ) + "Invalid SOCKS URL: must start with socks4://, socks4a://, or socks5://", + ), }; } if (!url || /\s/.test(url)) { return { valid: false, - message: _("Invalid SOCKS URL: must not contain spaces") + message: _("Invalid SOCKS URL: must not contain spaces"), }; } const body = url.replace(/^socks(4|4a|5):\/\//, ""); const [authAndHost] = body.split("#"); - const [credentials, hostPortPart] = authAndHost.includes("@") ? authAndHost.split("@") : [null, authAndHost]; + const [credentials, hostPortPart] = authAndHost.includes("@") + ? authAndHost.split("@") + : [null, authAndHost]; if (credentials) { const [username, _password] = credentials.split(":"); if (!username) { return { valid: false, - message: _("Invalid SOCKS URL: missing username") + message: _("Invalid SOCKS URL: missing username"), }; } } if (!hostPortPart) { return { valid: false, - message: _("Invalid SOCKS URL: missing host and port") + message: _("Invalid SOCKS URL: missing host and port"), }; } const [host, port] = hostPortPart.split(":"); if (!host) { return { valid: false, - message: _("Invalid SOCKS URL: missing hostname or IP") + message: _("Invalid SOCKS URL: missing hostname or IP"), }; } if (!port) { @@ -432,7 +437,7 @@ function validateSocksUrl(url) { if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) { return { valid: false, - message: _("Invalid SOCKS URL: invalid port number") + message: _("Invalid SOCKS URL: invalid port number"), }; } const ipv4Result = validateIPV4(host); @@ -440,7 +445,7 @@ function validateSocksUrl(url) { if (!ipv4Result.valid && !domainResult.valid) { return { valid: false, - message: _("Invalid SOCKS URL: invalid host format") + message: _("Invalid SOCKS URL: invalid host format"), }; } } catch (_e) { @@ -466,14 +471,20 @@ function validateProxyUrl(url) { return { valid: false, message: _( - "URL must start with vless://, ss://, trojan://, or socks4/5://" - ) + "URL must start with vless://, ss://, trojan://, or socks4/5://", + ), }; } // src/helpers/parseValueList.ts function parseValueList(value) { - return value.split(/\n/).map((line) => line.split("//")[0]).join(" ").split(/[,\s]+/).map((s) => s.trim()).filter(Boolean); + return value + .split(/\n/) + .map((line) => line.split("//")[0]) + .join(" ") + .split(/[,\s]+/) + .map((s) => s.trim()) + .filter(Boolean); } // src/podkop/methods/custom/getConfigSections.ts @@ -486,24 +497,24 @@ async function callBaseMethod(method, args = [], command = "/usr/bin/podkop") { const response = await executeShellCommand({ command, args: [method, ...args], - timeout: 1e4 + timeout: 1e4, }); if (response.stdout) { try { return { success: true, - data: JSON.parse(response.stdout) + data: JSON.parse(response.stdout), }; } catch (_e) { return { success: true, - data: response.stdout + data: response.stdout, }; } } return { success: false, - error: "" + error: "", }; } @@ -528,81 +539,71 @@ var Podkop; AvailableMethods2["SHOW_SING_BOX_CONFIG"] = "show_sing_box_config"; AvailableMethods2["CHECK_LOGS"] = "check_logs"; AvailableMethods2["GET_SYSTEM_INFO"] = "get_system_info"; - })(AvailableMethods = Podkop2.AvailableMethods || (Podkop2.AvailableMethods = {})); + })( + (AvailableMethods = + Podkop2.AvailableMethods || (Podkop2.AvailableMethods = {})), + ); let AvailableClashAPIMethods; ((AvailableClashAPIMethods2) => { AvailableClashAPIMethods2["GET_PROXIES"] = "get_proxies"; AvailableClashAPIMethods2["GET_PROXY_LATENCY"] = "get_proxy_latency"; AvailableClashAPIMethods2["GET_GROUP_LATENCY"] = "get_group_latency"; AvailableClashAPIMethods2["SET_GROUP_PROXY"] = "set_group_proxy"; - })(AvailableClashAPIMethods = Podkop2.AvailableClashAPIMethods || (Podkop2.AvailableClashAPIMethods = {})); + })( + (AvailableClashAPIMethods = + Podkop2.AvailableClashAPIMethods || + (Podkop2.AvailableClashAPIMethods = {})), + ); })(Podkop || (Podkop = {})); // src/podkop/methods/shell/index.ts var PodkopShellMethods = { - checkDNSAvailable: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_DNS_AVAILABLE - ), - checkFakeIP: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_FAKEIP - ), - checkNftRules: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_NFT_RULES - ), + checkDNSAvailable: async () => + callBaseMethod(Podkop.AvailableMethods.CHECK_DNS_AVAILABLE), + checkFakeIP: async () => callBaseMethod(Podkop.AvailableMethods.CHECK_FAKEIP), + checkNftRules: async () => + callBaseMethod(Podkop.AvailableMethods.CHECK_NFT_RULES), getStatus: async () => callBaseMethod(Podkop.AvailableMethods.GET_STATUS), - checkSingBox: async () => callBaseMethod( - Podkop.AvailableMethods.CHECK_SING_BOX - ), - getSingBoxStatus: async () => callBaseMethod( - Podkop.AvailableMethods.GET_SING_BOX_STATUS - ), - getClashApiProxies: async () => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ - Podkop.AvailableClashAPIMethods.GET_PROXIES - ]), - getClashApiProxyLatency: async (tag) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ - Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, - tag - ]), - getClashApiGroupLatency: async (tag) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ - Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, - tag - ]), - setClashApiGroupProxy: async (group, proxy) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ - Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY, - group, - proxy - ]), - restart: async () => callBaseMethod( - Podkop.AvailableMethods.RESTART, - [], - "/etc/init.d/podkop" - ), - start: async () => callBaseMethod( - Podkop.AvailableMethods.START, - [], - "/etc/init.d/podkop" - ), - stop: async () => callBaseMethod( - Podkop.AvailableMethods.STOP, - [], - "/etc/init.d/podkop" - ), - enable: async () => callBaseMethod( - Podkop.AvailableMethods.ENABLE, - [], - "/etc/init.d/podkop" - ), - disable: async () => callBaseMethod( - Podkop.AvailableMethods.DISABLE, - [], - "/etc/init.d/podkop" - ), + checkSingBox: async () => + callBaseMethod(Podkop.AvailableMethods.CHECK_SING_BOX), + getSingBoxStatus: async () => + callBaseMethod(Podkop.AvailableMethods.GET_SING_BOX_STATUS), + getClashApiProxies: async () => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_PROXIES, + ]), + getClashApiProxyLatency: async (tag) => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, + tag, + ]), + getClashApiGroupLatency: async (tag) => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, + tag, + ]), + setClashApiGroupProxy: async (group, proxy) => + callBaseMethod(Podkop.AvailableMethods.CLASH_API, [ + Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY, + group, + proxy, + ]), + restart: async () => + callBaseMethod(Podkop.AvailableMethods.RESTART, [], "/etc/init.d/podkop"), + start: async () => + callBaseMethod(Podkop.AvailableMethods.START, [], "/etc/init.d/podkop"), + stop: async () => + callBaseMethod(Podkop.AvailableMethods.STOP, [], "/etc/init.d/podkop"), + enable: async () => + callBaseMethod(Podkop.AvailableMethods.ENABLE, [], "/etc/init.d/podkop"), + disable: async () => + callBaseMethod(Podkop.AvailableMethods.DISABLE, [], "/etc/init.d/podkop"), globalCheck: async () => callBaseMethod(Podkop.AvailableMethods.GLOBAL_CHECK), - showSingBoxConfig: async () => callBaseMethod(Podkop.AvailableMethods.SHOW_SING_BOX_CONFIG), + showSingBoxConfig: async () => + callBaseMethod(Podkop.AvailableMethods.SHOW_SING_BOX_CONFIG), checkLogs: async () => callBaseMethod(Podkop.AvailableMethods.CHECK_LOGS), - getSystemInfo: async () => callBaseMethod( - Podkop.AvailableMethods.GET_SYSTEM_INFO - ) + getSystemInfo: async () => + callBaseMethod(Podkop.AvailableMethods.GET_SYSTEM_INFO), }; // src/podkop/methods/custom/getDashboardSections.ts @@ -612,25 +613,108 @@ async function getDashboardSections() { if (!clashProxies.success) { return { success: false, - data: [] + data: [], }; } const proxies = Object.entries(clashProxies.data.proxies).map( ([key, value]) => ({ code: key, - value - }) + value, + }), ); - const data = configSections.filter( - (section) => section.connection_type !== "block" && section[".type"] !== "settings" - ).map((section) => { - if (section.connection_type === "proxy") { - if (section.proxy_config_type === "url") { + const data = configSections + .filter( + (section) => + section.connection_type !== "block" && section[".type"] !== "settings", + ) + .map((section) => { + if (section.connection_type === "proxy") { + if (section.proxy_config_type === "url") { + const outbound = proxies.find( + (proxy) => proxy.code === `${section[".name"]}-out`, + ); + const activeConfigs = splitProxyString(section.proxy_string); + const proxyDisplayName = + getProxyUrlName(activeConfigs?.[0]) || outbound?.value?.name || ""; + return { + withTagSelect: false, + code: outbound?.code || section[".name"], + displayName: section[".name"], + outbounds: [ + { + code: outbound?.code || section[".name"], + displayName: proxyDisplayName, + latency: outbound?.value?.history?.[0]?.delay || 0, + type: outbound?.value?.type || "", + selected: true, + }, + ], + }; + } + if (section.proxy_config_type === "outbound") { + const outbound = proxies.find( + (proxy) => proxy.code === `${section[".name"]}-out`, + ); + const parsedOutbound = JSON.parse(section.outbound_json); + const parsedTag = parsedOutbound?.tag + ? decodeURIComponent(parsedOutbound?.tag) + : void 0; + const proxyDisplayName = parsedTag || outbound?.value?.name || ""; + return { + withTagSelect: false, + code: outbound?.code || section[".name"], + displayName: section[".name"], + outbounds: [ + { + code: outbound?.code || section[".name"], + displayName: proxyDisplayName, + latency: outbound?.value?.history?.[0]?.delay || 0, + type: outbound?.value?.type || "", + selected: true, + }, + ], + }; + } + if (section.proxy_config_type === "urltest") { + const selector = proxies.find( + (proxy) => proxy.code === `${section[".name"]}-out`, + ); + const outbound = proxies.find( + (proxy) => proxy.code === `${section[".name"]}-urltest-out`, + ); + const outbounds = (outbound?.value?.all ?? []) + .map((code) => proxies.find((item) => item.code === code)) + .map((item, index) => ({ + code: item?.code || "", + displayName: + getProxyUrlName(section.urltest_proxy_links?.[index]) || + item?.value?.name || + "", + latency: item?.value?.history?.[0]?.delay || 0, + type: item?.value?.type || "", + selected: selector?.value?.now === item?.code, + })); + return { + withTagSelect: true, + code: selector?.code || section[".name"], + displayName: section[".name"], + outbounds: [ + { + code: outbound?.code || "", + displayName: _("Fastest"), + latency: outbound?.value?.history?.[0]?.delay || 0, + type: outbound?.value?.type || "", + selected: selector?.value?.now === outbound?.code, + }, + ...outbounds, + ], + }; + } + } + if (section.connection_type === "vpn") { const outbound = proxies.find( - (proxy) => proxy.code === `${section[".name"]}-out` + (proxy) => proxy.code === `${section[".name"]}-out`, ); - const activeConfigs = splitProxyString(section.proxy_string); - const proxyDisplayName = getProxyUrlName(activeConfigs?.[0]) || outbound?.value?.name || ""; return { withTagSelect: false, code: outbound?.code || section[".name"], @@ -638,119 +722,43 @@ async function getDashboardSections() { outbounds: [ { code: outbound?.code || section[".name"], - displayName: proxyDisplayName, + displayName: section.interface || outbound?.value?.name || "", latency: outbound?.value?.history?.[0]?.delay || 0, type: outbound?.value?.type || "", - selected: true - } - ] - }; - } - if (section.proxy_config_type === "outbound") { - const outbound = proxies.find( - (proxy) => proxy.code === `${section[".name"]}-out` - ); - const parsedOutbound = JSON.parse(section.outbound_json); - const parsedTag = parsedOutbound?.tag ? decodeURIComponent(parsedOutbound?.tag) : void 0; - const proxyDisplayName = parsedTag || outbound?.value?.name || ""; - return { - withTagSelect: false, - code: outbound?.code || section[".name"], - displayName: section[".name"], - outbounds: [ - { - code: outbound?.code || section[".name"], - displayName: proxyDisplayName, - latency: outbound?.value?.history?.[0]?.delay || 0, - type: outbound?.value?.type || "", - selected: true - } - ] - }; - } - if (section.proxy_config_type === "urltest") { - const selector = proxies.find( - (proxy) => proxy.code === `${section[".name"]}-out` - ); - const outbound = proxies.find( - (proxy) => proxy.code === `${section[".name"]}-urltest-out` - ); - const outbounds = (outbound?.value?.all ?? []).map((code) => proxies.find((item) => item.code === code)).map((item, index) => ({ - code: item?.code || "", - displayName: getProxyUrlName(section.urltest_proxy_links?.[index]) || item?.value?.name || "", - latency: item?.value?.history?.[0]?.delay || 0, - type: item?.value?.type || "", - selected: selector?.value?.now === item?.code - })); - return { - withTagSelect: true, - code: selector?.code || section[".name"], - displayName: section[".name"], - outbounds: [ - { - code: outbound?.code || "", - displayName: _("Fastest"), - latency: outbound?.value?.history?.[0]?.delay || 0, - type: outbound?.value?.type || "", - selected: selector?.value?.now === outbound?.code + selected: true, }, - ...outbounds - ] + ], }; } - } - if (section.connection_type === "vpn") { - const outbound = proxies.find( - (proxy) => proxy.code === `${section[".name"]}-out` - ); return { withTagSelect: false, - code: outbound?.code || section[".name"], + code: section[".name"], displayName: section[".name"], - outbounds: [ - { - code: outbound?.code || section[".name"], - displayName: section.interface || outbound?.value?.name || "", - latency: outbound?.value?.history?.[0]?.delay || 0, - type: outbound?.value?.type || "", - selected: true - } - ] + outbounds: [], }; - } - return { - withTagSelect: false, - code: section[".name"], - displayName: section[".name"], - outbounds: [] - }; - }); + }); return { success: true, - data + data, }; } // src/podkop/methods/custom/index.ts var CustomPodkopMethods = { getConfigSections, - getDashboardSections + getDashboardSections, }; // src/constants.ts var STATUS_COLORS = { SUCCESS: "#4caf50", ERROR: "#f44336", - WARNING: "#ff9800" + WARNING: "#ff9800", }; var PODKOP_LUCI_APP_VERSION = "__COMPILED_VERSION_VARIABLE__"; var FAKEIP_CHECK_DOMAIN = "fakeip.podkop.fyi"; var IP_CHECK_DOMAIN = "ip.podkop.fyi"; -var REGIONAL_OPTIONS = [ - "russia_inside", - "russia_outside", - "ukraine_inside" -]; +var REGIONAL_OPTIONS = ["russia_inside", "russia_outside", "ukraine_inside"]; var ALLOWED_WITH_RUSSIA_INSIDE = [ "russia_inside", "meta", @@ -764,7 +772,7 @@ var ALLOWED_WITH_RUSSIA_INSIDE = [ "ovh", "hodca", "digitalocean", - "cloudfront" + "cloudfront", ]; var DOMAIN_LIST_OPTIONS = { russia_inside: "Russia inside", @@ -789,22 +797,23 @@ var DOMAIN_LIST_OPTIONS = { hetzner: "Hetzner ASN", ovh: "OVH ASN", digitalocean: "Digital Ocean ASN", - cloudfront: "CloudFront ASN" + cloudfront: "CloudFront ASN", }; var UPDATE_INTERVAL_OPTIONS = { "1h": "Every hour", "3h": "Every 3 hours", "12h": "Every 12 hours", "1d": "Every day", - "3d": "Every 3 days" + "3d": "Every 3 days", }; var DNS_SERVER_OPTIONS = { "1.1.1.1": "1.1.1.1 (Cloudflare)", "8.8.8.8": "8.8.8.8 (Google)", "9.9.9.9": "9.9.9.9 (Quad9)", "dns.adguard-dns.com": "dns.adguard-dns.com (AdGuard Default)", - "unfiltered.adguard-dns.com": "unfiltered.adguard-dns.com (AdGuard Unfiltered)", - "family.adguard-dns.com": "family.adguard-dns.com (AdGuard Family)" + "unfiltered.adguard-dns.com": + "unfiltered.adguard-dns.com (AdGuard Unfiltered)", + "family.adguard-dns.com": "family.adguard-dns.com (AdGuard Family)", }; var BOOTSTRAP_DNS_SERVER_OPTIONS = { "77.88.8.8": "77.88.8.8 (Yandex DNS)", @@ -814,7 +823,7 @@ var BOOTSTRAP_DNS_SERVER_OPTIONS = { "8.8.8.8": "8.8.8.8 (Google DNS)", "8.8.4.4": "8.8.4.4 (Google DNS)", "9.9.9.9": "9.9.9.9 (Quad9 DNS)", - "9.9.9.11": "9.9.9.11 (Quad9 DNS)" + "9.9.9.11": "9.9.9.11 (Quad9 DNS)", }; var DIAGNOSTICS_UPDATE_INTERVAL = 1e4; var CACHE_TIMEOUT = DIAGNOSTICS_UPDATE_INTERVAL - 1e3; @@ -844,35 +853,38 @@ var COMMAND_SCHEDULING = { // Background execution P9_PRIORITY: 1700, // Idle mode execution - P10_PRIORITY: 1900 + P10_PRIORITY: 1900, // Lowest priority }; // src/podkop/api.ts async function createBaseApiRequest(fetchFn, options) { - const wrappedFn = () => options?.timeoutMs && options?.operationName ? withTimeout( - fetchFn(), - options.timeoutMs, - options.operationName, - options.timeoutMessage - ) : fetchFn(); + const wrappedFn = () => + options?.timeoutMs && options?.operationName + ? withTimeout( + fetchFn(), + options.timeoutMs, + options.operationName, + options.timeoutMessage, + ) + : fetchFn(); try { const response = await wrappedFn(); if (!response.ok) { return { success: false, - message: `${_("HTTP error")} ${response.status}: ${response.statusText}` + message: `${_("HTTP error")} ${response.status}: ${response.statusText}`, }; } const data = await response.json(); return { success: true, - data + data, }; } catch (e) { return { success: false, - message: e instanceof Error ? e.message : _("Unknown error") + message: e instanceof Error ? e.message : _("Unknown error"), }; } } @@ -880,35 +892,37 @@ async function createBaseApiRequest(fetchFn, options) { // src/podkop/methods/fakeip/getFakeIpCheck.ts async function getFakeIpCheck() { return createBaseApiRequest( - () => fetch(`https://${FAKEIP_CHECK_DOMAIN}/check`, { - method: "GET", - headers: { "Content-Type": "application/json" } - }), + () => + fetch(`https://${FAKEIP_CHECK_DOMAIN}/check`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }), { operationName: "getFakeIpCheck", - timeoutMs: 5e3 - } + timeoutMs: 5e3, + }, ); } // src/podkop/methods/fakeip/getIpCheck.ts async function getIpCheck() { return createBaseApiRequest( - () => fetch(`https://${IP_CHECK_DOMAIN}/check`, { - method: "GET", - headers: { "Content-Type": "application/json" } - }), + () => + fetch(`https://${IP_CHECK_DOMAIN}/check`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }), { operationName: "getIpCheck", - timeoutMs: 5e3 - } + timeoutMs: 5e3, + }, ); } // src/podkop/methods/fakeip/index.ts var RemoteFakeIPMethods = { getFakeIpCheck, - getIpCheck + getIpCheck, }; // src/podkop/services/tab.service.ts @@ -930,7 +944,7 @@ var TabService = class _TabService { subtree: true, childList: true, attributes: true, - attributeFilter: ["class"] + attributeFilter: ["class"], }); this.notify(); } @@ -939,18 +953,18 @@ var TabService = class _TabService { } getTabsInfo() { const tabs = Array.from( - document.querySelectorAll(".cbi-tab, .cbi-tab-disabled") + document.querySelectorAll(".cbi-tab, .cbi-tab-disabled"), ); return tabs.map((el) => ({ el, id: el.dataset.tab || "", - active: el.classList.contains("cbi-tab") && !el.classList.contains("cbi-tab-disabled") + active: + el.classList.contains("cbi-tab") && + !el.classList.contains("cbi-tab-disabled"), })); } getActiveTabId() { - const active = document.querySelector( - ".cbi-tab:not(.cbi-tab-disabled)" - ); + const active = document.querySelector(".cbi-tab:not(.cbi-tab-disabled)"); return active?.dataset.tab || null; } notify() { @@ -983,23 +997,23 @@ var DIAGNOSTICS_CHECKS_MAP = { ["DNS" /* DNS */]: { order: 1, title: _("DNS checks"), - code: "DNS" /* DNS */ + code: "DNS" /* DNS */, }, ["SINGBOX" /* SINGBOX */]: { order: 2, title: _("Sing-box checks"), - code: "SINGBOX" /* SINGBOX */ + code: "SINGBOX" /* SINGBOX */, }, ["NFT" /* NFT */]: { order: 3, title: _("Nftables checks"), - code: "NFT" /* NFT */ + code: "NFT" /* NFT */, }, ["FAKEIP" /* FAKEIP */]: { order: 4, title: _("FakeIP checks"), - code: "FAKEIP" /* FAKEIP */ - } + code: "FAKEIP" /* FAKEIP */, + }, }; // src/podkop/tabs/diagnostic/diagnostic.store.ts @@ -1011,33 +1025,33 @@ var initialDiagnosticStore = { luci_app_version: "loading", sing_box_version: "loading", openwrt_version: "loading", - device_model: "loading" + device_model: "loading", }, diagnosticsActions: { restart: { - loading: false + loading: false, }, start: { - loading: false + loading: false, }, stop: { - loading: false + loading: false, }, enable: { - loading: false + loading: false, }, disable: { - loading: false + loading: false, }, globalCheck: { - loading: false + loading: false, }, viewLogs: { - loading: false + loading: false, }, showSingBoxConfig: { - loading: false - } + loading: false, + }, }, diagnosticsRunAction: { loading: false }, diagnosticsChecks: [ @@ -1047,7 +1061,7 @@ var initialDiagnosticStore = { order: DIAGNOSTICS_CHECKS_MAP.DNS.order, description: _("Not running"), items: [], - state: "skipped" + state: "skipped", }, { code: "SINGBOX" /* SINGBOX */, @@ -1055,7 +1069,7 @@ var initialDiagnosticStore = { order: DIAGNOSTICS_CHECKS_MAP.SINGBOX.order, description: _("Not running"), items: [], - state: "skipped" + state: "skipped", }, { code: "NFT" /* NFT */, @@ -1063,7 +1077,7 @@ var initialDiagnosticStore = { order: DIAGNOSTICS_CHECKS_MAP.NFT.order, description: _("Not running"), items: [], - state: "skipped" + state: "skipped", }, { code: "FAKEIP" /* FAKEIP */, @@ -1071,9 +1085,9 @@ var initialDiagnosticStore = { order: DIAGNOSTICS_CHECKS_MAP.FAKEIP.order, description: _("Not running"), items: [], - state: "skipped" - } - ] + state: "skipped", + }, + ], }; var loadingDiagnosticsChecksStore = { diagnosticsChecks: [ @@ -1083,7 +1097,7 @@ var loadingDiagnosticsChecksStore = { order: DIAGNOSTICS_CHECKS_MAP.DNS.order, description: _("Queued"), items: [], - state: "skipped" + state: "skipped", }, { code: "SINGBOX" /* SINGBOX */, @@ -1091,7 +1105,7 @@ var loadingDiagnosticsChecksStore = { order: DIAGNOSTICS_CHECKS_MAP.SINGBOX.order, description: _("Queued"), items: [], - state: "skipped" + state: "skipped", }, { code: "NFT" /* NFT */, @@ -1099,7 +1113,7 @@ var loadingDiagnosticsChecksStore = { order: DIAGNOSTICS_CHECKS_MAP.NFT.order, description: _("Queued"), items: [], - state: "skipped" + state: "skipped", }, { code: "FAKEIP" /* FAKEIP */, @@ -1107,22 +1121,21 @@ var loadingDiagnosticsChecksStore = { order: DIAGNOSTICS_CHECKS_MAP.FAKEIP.order, description: _("Queued"), items: [], - state: "skipped" - } - ] + state: "skipped", + }, + ], }; // src/podkop/services/store.service.ts function jsonStableStringify(obj) { return JSON.stringify(obj, (_2, value) => { if (value && typeof value === "object" && !Array.isArray(value)) { - return Object.keys(value).sort().reduce( - (acc, key) => { + return Object.keys(value) + .sort() + .reduce((acc, key) => { acc[key] = value[key]; return acc; - }, - {} - ); + }, {}); } return value; }); @@ -1205,35 +1218,35 @@ var StoreService = class { var initialStore = { tabService: { current: "", - all: [] + all: [], }, bandwidthWidget: { loading: true, failed: false, - data: { up: 0, down: 0 } + data: { up: 0, down: 0 }, }, trafficTotalWidget: { loading: true, failed: false, - data: { downloadTotal: 0, uploadTotal: 0 } + data: { downloadTotal: 0, uploadTotal: 0 }, }, systemInfoWidget: { loading: true, failed: false, - data: { connections: 0, memory: 0 } + data: { connections: 0, memory: 0 }, }, servicesInfoWidget: { loading: true, failed: false, - data: { singbox: 0, podkop: 0 } + data: { singbox: 0, podkop: 0 }, }, sectionsWidget: { loading: true, failed: false, latencyFetching: false, - data: [] + data: [], }, - ...initialDiagnosticStore + ...initialDiagnosticStore, }; var store = new StoreService(initialStore); @@ -1297,7 +1310,9 @@ var Logger = class { } download(filename = "logs.txt") { if (typeof document === "undefined") { - console.warn("Logger.download() \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435"); + console.warn( + "Logger.download() \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435", + ); return; } downloadAsTxt(this.getLogs(), filename); @@ -1331,7 +1346,7 @@ var PodkopLogWatcher = class _PodkopLogWatcher { this.intervalMs = options?.intervalMs ?? 5e3; logger.info( "[PodkopLogWatcher]", - `initialized (interval: ${this.intervalMs}ms)` + `initialized (interval: ${this.intervalMs}ms)`, ); } async checkOnce() { @@ -1340,7 +1355,10 @@ var PodkopLogWatcher = class _PodkopLogWatcher { return; } if (this.paused) { - logger.debug("[PodkopLogWatcher]", "skipped check \u2014 tab not visible"); + logger.debug( + "[PodkopLogWatcher]", + "skipped check \u2014 tab not visible", + ); return; } try { @@ -1370,7 +1388,7 @@ var PodkopLogWatcher = class _PodkopLogWatcher { this.timer = setInterval(() => this.checkOnce(), this.intervalMs); logger.info( "[PodkopLogWatcher]", - `started (interval: ${this.intervalMs}ms)` + `started (interval: ${this.intervalMs}ms)`, ); } stop() { @@ -1403,8 +1421,8 @@ function coreService() { store.set({ tabService: { current: activeId || "", - all: tabs.map((tab) => tab.id) - } + all: tabs.map((tab) => tab.id), + }, }); }); const watcher = PodkopLogWatcher.getInstance(); @@ -1419,11 +1437,14 @@ function coreService() { { intervalMs: 3e3, onNewLog: (line) => { - if (line.toLowerCase().includes("[error]") || line.toLowerCase().includes("[fatal]")) { + if ( + line.toLowerCase().includes("[error]") || + line.toLowerCase().includes("[fatal]") + ) { ui.addNotification("Podkop Error", E("div", {}, line), "error"); } - } - } + }, + }, ); watcher.start(); } @@ -1445,14 +1466,17 @@ var SocketManager = class _SocketManager { resetAll() { for (const [url, ws] of this.sockets.entries()) { try { - if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) { + if ( + ws.readyState === WebSocket.OPEN || + ws.readyState === WebSocket.CONNECTING + ) { ws.close(); } } catch (err) { logger.error( "[SOCKET]", `resetAll: failed to close socket ${url}`, - err + err, ); } } @@ -1471,7 +1495,7 @@ var SocketManager = class _SocketManager { logger.error( "[SOCKET]", `failed to construct WebSocket for ${url}:`, - err + err, ); this.triggerError(url, err instanceof Event ? err : String(err)); return; @@ -1573,23 +1597,23 @@ function renderFailedState() { "div", { class: "pdk_dashboard-page__outbound-section centered", - style: "height: 127px" + style: "height: 127px", }, - E("span", {}, [E("span", {}, _("Dashboard currently unavailable"))]) + E("span", {}, [E("span", {}, _("Dashboard currently unavailable"))]), ); } function renderLoadingState() { return E("div", { id: "dashboard-sections-grid-skeleton", class: "pdk_dashboard-page__outbound-section skeleton", - style: "height: 127px" + style: "height: 127px", }); } function renderDefaultState({ section, onChooseOutbound, onTestLatency, - latencyFetching + latencyFetching, }) { function testLatency() { if (section.withTagSelect) { @@ -1616,7 +1640,9 @@ function renderDefaultState({ "div", { class: `pdk_dashboard-page__outbound-grid__item ${outbound.selected ? "pdk_dashboard-page__outbound-grid__item--active" : ""} ${section.withTagSelect ? "pdk_dashboard-page__outbound-grid__item--selectable" : ""}`, - click: () => section.withTagSelect && onChooseOutbound(section.code, outbound.code) + click: () => + section.withTagSelect && + onChooseOutbound(section.code, outbound.code), }, [ E("b", {}, outbound.displayName), @@ -1624,15 +1650,15 @@ function renderDefaultState({ E( "div", { class: "pdk_dashboard-page__outbound-grid__item__type" }, - outbound.type + outbound.type, ), E( "div", { class: getLatencyClass() }, - outbound.latency ? `${outbound.latency}ms` : "N/A" - ) - ]) - ] + outbound.latency ? `${outbound.latency}ms` : "N/A", + ), + ]), + ], ); } return E("div", { class: "pdk_dashboard-page__outbound-section" }, [ @@ -1641,24 +1667,26 @@ function renderDefaultState({ E( "div", { - class: "pdk_dashboard-page__outbound-section__title-section__title" + class: "pdk_dashboard-page__outbound-section__title-section__title", }, - section.displayName + section.displayName, ), - latencyFetching ? E("div", { class: "skeleton", style: "width: 99px; height: 28px" }) : E( - "button", - { - class: "btn dashboard-sections-grid-item-test-latency", - click: () => testLatency() - }, - _("Test latency") - ) + latencyFetching + ? E("div", { class: "skeleton", style: "width: 99px; height: 28px" }) + : E( + "button", + { + class: "btn dashboard-sections-grid-item-test-latency", + click: () => testLatency(), + }, + _("Test latency"), + ), ]), E( "div", { class: "pdk_dashboard-page__outbound-grid" }, - section.outbounds.map((outbound) => renderOutbound(outbound)) - ) + section.outbounds.map((outbound) => renderOutbound(outbound)), + ), ]); } function renderSections(props) { @@ -1678,9 +1706,9 @@ function renderFailedState2() { { id: "", style: "height: 78px", - class: "pdk_dashboard-page__widgets-section__item centered" + class: "pdk_dashboard-page__widgets-section__item centered", }, - _("Currently unavailable") + _("Currently unavailable"), ); } function renderLoadingState2() { @@ -1689,9 +1717,9 @@ function renderLoadingState2() { { id: "", style: "height: 78px", - class: "pdk_dashboard-page__widgets-section__item skeleton" + class: "pdk_dashboard-page__widgets-section__item skeleton", }, - "" + "", ); } function renderDefaultState2({ title, items }) { @@ -1699,28 +1727,28 @@ function renderDefaultState2({ title, items }) { E( "b", { class: "pdk_dashboard-page__widgets-section__item__title" }, - title + title, ), - ...items.map( - (item) => E( + ...items.map((item) => + E( "div", { - class: `pdk_dashboard-page__widgets-section__item__row ${item?.attributes?.class || ""}` + class: `pdk_dashboard-page__widgets-section__item__row ${item?.attributes?.class || ""}`, }, [ E( "span", { class: "pdk_dashboard-page__widgets-section__item__row__key" }, - `${item.key}: ` + `${item.key}: `, ), E( "span", { class: "pdk_dashboard-page__widgets-section__item__row__value" }, - item.value - ) - ] - ) - ) + item.value, + ), + ], + ), + ), ]); } function renderWidget(props) { @@ -1739,7 +1767,7 @@ function render() { "div", { id: "dashboard-status", - class: "pdk_dashboard-page" + class: "pdk_dashboard-page", }, [ // Widgets section @@ -1747,23 +1775,23 @@ function render() { E( "div", { id: "dashboard-widget-traffic" }, - renderWidget({ loading: true, failed: false, title: "", items: [] }) + renderWidget({ loading: true, failed: false, title: "", items: [] }), ), E( "div", { id: "dashboard-widget-traffic-total" }, - renderWidget({ loading: true, failed: false, title: "", items: [] }) + renderWidget({ loading: true, failed: false, title: "", items: [] }), ), E( "div", { id: "dashboard-widget-system-info" }, - renderWidget({ loading: true, failed: false, title: "", items: [] }) + renderWidget({ loading: true, failed: false, title: "", items: [] }), ), E( "div", { id: "dashboard-widget-service-info" }, - renderWidget({ loading: true, failed: false, title: "", items: [] }) - ) + renderWidget({ loading: true, failed: false, title: "", items: [] }), + ), ]), // All outbounds E( @@ -1776,16 +1804,14 @@ function render() { code: "", displayName: "", outbounds: [], - withTagSelect: false + withTagSelect: false, }, - onTestLatency: () => { - }, - onChooseOutbound: () => { - }, - latencyFetching: false - }) - ) - ] + onTestLatency: () => {}, + onChooseOutbound: () => {}, + latencyFetching: false, + }), + ), + ], ); } @@ -1805,15 +1831,15 @@ function prettyBytes(n) { async function fetchServicesInfo() { const [podkop, singbox] = await Promise.all([ PodkopShellMethods.getStatus(), - PodkopShellMethods.getSingBoxStatus() + PodkopShellMethods.getSingBoxStatus(), ]); if (!podkop.success || !singbox.success) { store.set({ servicesInfoWidget: { loading: false, failed: true, - data: { singbox: 0, podkop: 0 } - } + data: { singbox: 0, podkop: 0 }, + }, }); } if (podkop.success && singbox.success) { @@ -1821,8 +1847,8 @@ async function fetchServicesInfo() { servicesInfoWidget: { loading: false, failed: false, - data: { singbox: singbox.data.running, podkop: podkop.data.enabled } - } + data: { singbox: singbox.data.running, podkop: podkop.data.enabled }, + }, }); } } @@ -1833,8 +1859,8 @@ async function fetchDashboardSections() { store.set({ sectionsWidget: { ...prev, - failed: false - } + failed: false, + }, }); const { data, success } = await CustomPodkopMethods.getDashboardSections(); if (!success) { @@ -1845,8 +1871,8 @@ async function fetchDashboardSections() { latencyFetching: false, loading: false, failed: !success, - data - } + data, + }, }); } async function connectToClashSockets() { @@ -1858,24 +1884,24 @@ async function connectToClashSockets() { bandwidthWidget: { loading: false, failed: false, - data: { up: parsedMsg.up, down: parsedMsg.down } - } + data: { up: parsedMsg.up, down: parsedMsg.down }, + }, }); }, (_err) => { logger.error( "[DASHBOARD]", "connectToClashSockets - traffic: failed to connect to", - getClashWsUrl() + getClashWsUrl(), ); store.set({ bandwidthWidget: { loading: false, failed: true, - data: { up: 0, down: 0 } - } + data: { up: 0, down: 0 }, + }, }); - } + }, ); socket.subscribe( `${getClashWsUrl()}/connections?token=`, @@ -1887,41 +1913,41 @@ async function connectToClashSockets() { failed: false, data: { downloadTotal: parsedMsg.downloadTotal, - uploadTotal: parsedMsg.uploadTotal - } + uploadTotal: parsedMsg.uploadTotal, + }, }, systemInfoWidget: { loading: false, failed: false, data: { connections: parsedMsg.connections?.length, - memory: parsedMsg.memory - } - } + memory: parsedMsg.memory, + }, + }, }); }, (_err) => { logger.error( "[DASHBOARD]", "connectToClashSockets - connections: failed to connect to", - getClashWsUrl() + getClashWsUrl(), ); store.set({ trafficTotalWidget: { loading: false, failed: true, - data: { downloadTotal: 0, uploadTotal: 0 } + data: { downloadTotal: 0, uploadTotal: 0 }, }, systemInfoWidget: { loading: false, failed: true, data: { connections: 0, - memory: 0 - } - } + memory: 0, + }, + }, }); - } + }, ); } async function handleChooseOutbound(selector, tag) { @@ -1932,32 +1958,32 @@ async function handleTestGroupLatency(tag) { store.set({ sectionsWidget: { ...store.get().sectionsWidget, - latencyFetching: true - } + latencyFetching: true, + }, }); await PodkopShellMethods.getClashApiGroupLatency(tag); await fetchDashboardSections(); store.set({ sectionsWidget: { ...store.get().sectionsWidget, - latencyFetching: false - } + latencyFetching: false, + }, }); } async function handleTestProxyLatency(tag) { store.set({ sectionsWidget: { ...store.get().sectionsWidget, - latencyFetching: true - } + latencyFetching: true, + }, }); await PodkopShellMethods.getClashApiProxyLatency(tag); await fetchDashboardSections(); store.set({ sectionsWidget: { ...store.get().sectionsWidget, - latencyFetching: false - } + latencyFetching: false, + }, }); } async function renderSectionsWidget() { @@ -1972,20 +1998,18 @@ async function renderSectionsWidget() { code: "", displayName: "", outbounds: [], - withTagSelect: false + withTagSelect: false, }, - onTestLatency: () => { - }, - onChooseOutbound: () => { - }, - latencyFetching: sectionsWidget.latencyFetching + onTestLatency: () => {}, + onChooseOutbound: () => {}, + latencyFetching: sectionsWidget.latencyFetching, }); return preserveScrollForPage(() => { container.replaceChildren(renderedWidget); }); } - const renderedWidgets = sectionsWidget.data.map( - (section) => renderSections({ + const renderedWidgets = sectionsWidget.data.map((section) => + renderSections({ loading: sectionsWidget.loading, failed: sectionsWidget.failed, section, @@ -1998,8 +2022,8 @@ async function renderSectionsWidget() { }, onChooseOutbound: (selector, tag) => { handleChooseOutbound(selector, tag); - } - }) + }, + }), ); return preserveScrollForPage(() => { container.replaceChildren(...renderedWidgets); @@ -2014,7 +2038,7 @@ async function renderBandwidthWidget() { loading: traffic.loading, failed: traffic.failed, title: "", - items: [] + items: [], }); return container.replaceChildren(renderedWidget2); } @@ -2024,8 +2048,8 @@ async function renderBandwidthWidget() { title: _("Traffic"), items: [ { key: _("Uplink"), value: `${prettyBytes(traffic.data.up)}/s` }, - { key: _("Downlink"), value: `${prettyBytes(traffic.data.down)}/s` } - ] + { key: _("Downlink"), value: `${prettyBytes(traffic.data.down)}/s` }, + ], }); container.replaceChildren(renderedWidget); } @@ -2038,7 +2062,7 @@ async function renderTrafficTotalWidget() { loading: trafficTotalWidget.loading, failed: trafficTotalWidget.failed, title: "", - items: [] + items: [], }); return container.replaceChildren(renderedWidget2); } @@ -2049,13 +2073,13 @@ async function renderTrafficTotalWidget() { items: [ { key: _("Uplink"), - value: String(prettyBytes(trafficTotalWidget.data.uploadTotal)) + value: String(prettyBytes(trafficTotalWidget.data.uploadTotal)), }, { key: _("Downlink"), - value: String(prettyBytes(trafficTotalWidget.data.downloadTotal)) - } - ] + value: String(prettyBytes(trafficTotalWidget.data.downloadTotal)), + }, + ], }); container.replaceChildren(renderedWidget); } @@ -2068,7 +2092,7 @@ async function renderSystemInfoWidget() { loading: systemInfoWidget.loading, failed: systemInfoWidget.failed, title: "", - items: [] + items: [], }); return container.replaceChildren(renderedWidget2); } @@ -2079,13 +2103,13 @@ async function renderSystemInfoWidget() { items: [ { key: _("Active Connections"), - value: String(systemInfoWidget.data.connections) + value: String(systemInfoWidget.data.connections), }, { key: _("Memory Usage"), - value: String(prettyBytes(systemInfoWidget.data.memory)) - } - ] + value: String(prettyBytes(systemInfoWidget.data.memory)), + }, + ], }); container.replaceChildren(renderedWidget); } @@ -2098,7 +2122,7 @@ async function renderServicesInfoWidget() { loading: servicesInfoWidget.loading, failed: servicesInfoWidget.failed, title: "", - items: [] + items: [], }); return container.replaceChildren(renderedWidget2); } @@ -2109,19 +2133,27 @@ async function renderServicesInfoWidget() { items: [ { key: _("Podkop"), - value: servicesInfoWidget.data.podkop ? _("\u2714 Enabled") : _("\u2718 Disabled"), + value: servicesInfoWidget.data.podkop + ? _("\u2714 Enabled") + : _("\u2718 Disabled"), attributes: { - class: servicesInfoWidget.data.podkop ? "pdk_dashboard-page__widgets-section__item__row--success" : "pdk_dashboard-page__widgets-section__item__row--error" - } + class: servicesInfoWidget.data.podkop + ? "pdk_dashboard-page__widgets-section__item__row--success" + : "pdk_dashboard-page__widgets-section__item__row--error", + }, }, { key: _("Sing-box"), - value: servicesInfoWidget.data.singbox ? _("\u2714 Running") : _("\u2718 Stopped"), + value: servicesInfoWidget.data.singbox + ? _("\u2714 Running") + : _("\u2718 Stopped"), attributes: { - class: servicesInfoWidget.data.singbox ? "pdk_dashboard-page__widgets-section__item__row--success" : "pdk_dashboard-page__widgets-section__item__row--error" - } - } - ] + class: servicesInfoWidget.data.singbox + ? "pdk_dashboard-page__widgets-section__item__row--success" + : "pdk_dashboard-page__widgets-section__item__row--error", + }, + }, + ], }); container.replaceChildren(renderedWidget); } @@ -2156,24 +2188,27 @@ function onPageUnmount() { "trafficTotalWidget", "systemInfoWidget", "servicesInfoWidget", - "sectionsWidget" + "sectionsWidget", ]); socket.resetAll(); } function registerLifecycleListeners() { store.subscribe((next, prev, diff) => { - if (diff.tabService && next.tabService.current !== prev.tabService.current) { + if ( + diff.tabService && + next.tabService.current !== prev.tabService.current + ) { logger.debug( "[DASHBOARD]", "active tab diff event, active tab:", - diff.tabService.current + diff.tabService.current, ); const isDashboardVisible = next.tabService.current === "dashboard"; if (isDashboardVisible) { logger.debug( "[DASHBOARD]", "registerLifecycleListeners", - "onPageMount" + "onPageMount", ); return onPageMount(); } @@ -2181,7 +2216,7 @@ function registerLifecycleListeners() { logger.debug( "[DASHBOARD]", "registerLifecycleListeners", - "onPageUnmount" + "onPageUnmount", ); return onPageUnmount(); } @@ -2321,7 +2356,7 @@ var styles = ` var DashboardTab = { render, initController, - styles + styles, }; // src/podkop/tabs/diagnostic/renderDiagnostic.ts @@ -2331,13 +2366,13 @@ function render2() { E("div", { id: "pdk_diagnostic-page-run-check" }), E("div", { class: "pdk_diagnostic-page__checks", - id: "pdk_diagnostic-page-checks" - }) + id: "pdk_diagnostic-page-checks", + }), ]), E("div", { class: "pdk_diagnostic-page__right-bar" }, [ E("div", { id: "pdk_diagnostic-page-actions" }), - E("div", { id: "pdk_diagnostic-page-system-info" }) - ]) + E("div", { id: "pdk_diagnostic-page-system-info" }), + ]), ]); } @@ -2347,11 +2382,11 @@ function updateCheckStore(check, minified) { const other = diagnosticsChecks.filter((item) => item.code !== check.code); const smallCheck = { ...check, - items: check.items.filter((item) => item.state !== "success") + items: check.items.filter((item) => item.state !== "success"), }; const targetCheck = minified ? smallCheck : check; store.set({ - diagnosticsChecks: [...other, targetCheck] + diagnosticsChecks: [...other, targetCheck], }); } @@ -2364,7 +2399,7 @@ async function runDnsCheck() { title, description: _("Checking dns, please wait"), state: "loading", - items: [] + items: [], }); const dnsChecks = await PodkopShellMethods.checkDNSAvailable(); if (!dnsChecks.success) { @@ -2374,13 +2409,21 @@ async function runDnsCheck() { title, description: _("Cannot receive DNS checks result"), state: "error", - items: [] + items: [], }); throw new Error("DNS checks failed"); } const data = dnsChecks.data; - const allGood = Boolean(data.dns_on_router) && Boolean(data.dhcp_config_status) && Boolean(data.bootstrap_dns_status) && Boolean(data.dns_status); - const atLeastOneGood = Boolean(data.dns_on_router) || Boolean(data.dhcp_config_status) || Boolean(data.bootstrap_dns_status) || Boolean(data.dns_status); + const allGood = + Boolean(data.dns_on_router) && + Boolean(data.dhcp_config_status) && + Boolean(data.bootstrap_dns_status) && + Boolean(data.dns_status); + const atLeastOneGood = + Boolean(data.dns_on_router) || + Boolean(data.dhcp_config_status) || + Boolean(data.bootstrap_dns_status) || + Boolean(data.dns_status); function getStatus() { if (allGood) { return "success"; @@ -2397,32 +2440,29 @@ async function runDnsCheck() { description: _("DNS checks passed"), state: getStatus(), items: [ - ...insertIf( - data.dns_type === "doh" || data.dns_type === "dot", - [ - { - state: data.bootstrap_dns_status ? "success" : "error", - key: _("Bootsrap DNS"), - value: data.bootstrap_dns_server - } - ] - ), + ...insertIf(data.dns_type === "doh" || data.dns_type === "dot", [ + { + state: data.bootstrap_dns_status ? "success" : "error", + key: _("Bootsrap DNS"), + value: data.bootstrap_dns_server, + }, + ]), { state: data.dns_status ? "success" : "error", key: _("Main DNS"), - value: `${data.dns_server} [${data.dns_type}]` + value: `${data.dns_server} [${data.dns_type}]`, }, { state: data.dns_on_router ? "success" : "error", key: _("DNS on router"), - value: "" + value: "", }, { state: data.dhcp_config_status ? "success" : "error", key: _("DHCP has DNS server"), - value: "" - } - ] + value: "", + }, + ], }); if (!atLeastOneGood) { throw new Error("DNS checks failed"); @@ -2438,7 +2478,7 @@ async function runSingBoxCheck() { title, description: _("Checking sing-box, please wait"), state: "loading", - items: [] + items: [], }); const singBoxChecks = await PodkopShellMethods.checkSingBox(); if (!singBoxChecks.success) { @@ -2448,13 +2488,25 @@ async function runSingBoxCheck() { title, description: _("Cannot receive Sing-box checks result"), state: "error", - items: [] + items: [], }); throw new Error("Sing-box checks failed"); } const data = singBoxChecks.data; - const allGood = Boolean(data.sing_box_installed) && Boolean(data.sing_box_version_ok) && Boolean(data.sing_box_service_exist) && Boolean(data.sing_box_autostart_disabled) && Boolean(data.sing_box_process_running) && Boolean(data.sing_box_ports_listening); - const atLeastOneGood = Boolean(data.sing_box_installed) || Boolean(data.sing_box_version_ok) || Boolean(data.sing_box_service_exist) || Boolean(data.sing_box_autostart_disabled) || Boolean(data.sing_box_process_running) || Boolean(data.sing_box_ports_listening); + const allGood = + Boolean(data.sing_box_installed) && + Boolean(data.sing_box_version_ok) && + Boolean(data.sing_box_service_exist) && + Boolean(data.sing_box_autostart_disabled) && + Boolean(data.sing_box_process_running) && + Boolean(data.sing_box_ports_listening); + const atLeastOneGood = + Boolean(data.sing_box_installed) || + Boolean(data.sing_box_version_ok) || + Boolean(data.sing_box_service_exist) || + Boolean(data.sing_box_autostart_disabled) || + Boolean(data.sing_box_process_running) || + Boolean(data.sing_box_ports_listening); function getStatus() { if (allGood) { return "success"; @@ -2474,34 +2526,34 @@ async function runSingBoxCheck() { { state: data.sing_box_installed ? "success" : "error", key: _("Sing-box installed"), - value: "" + value: "", }, { state: data.sing_box_version_ok ? "success" : "error", key: _("Sing-box version >= 1.12.4"), - value: "" + value: "", }, { state: data.sing_box_service_exist ? "success" : "error", key: _("Sing-box service exist"), - value: "" + value: "", }, { state: data.sing_box_autostart_disabled ? "success" : "error", key: _("Sing-box autostart disabled"), - value: "" + value: "", }, { state: data.sing_box_process_running ? "success" : "error", key: _("Sing-box process running"), - value: "" + value: "", }, { state: data.sing_box_ports_listening ? "success" : "error", key: _("Sing-box listening ports"), - value: "" - } - ] + value: "", + }, + ], }); if (!atLeastOneGood || !data.sing_box_process_running) { throw new Error("Sing-box checks failed"); @@ -2517,7 +2569,7 @@ async function runNftCheck() { title, description: _("Checking nftables, please wait"), state: "loading", - items: [] + items: [], }); await RemoteFakeIPMethods.getFakeIpCheck(); await RemoteFakeIPMethods.getIpCheck(); @@ -2529,13 +2581,29 @@ async function runNftCheck() { title, description: _("Cannot receive nftables checks result"), state: "error", - items: [] + items: [], }); throw new Error("Nftables checks failed"); } const data = nftablesChecks.data; - const allGood = Boolean(data.table_exist) && Boolean(data.rules_mangle_exist) && Boolean(data.rules_mangle_counters) && Boolean(data.rules_mangle_output_exist) && Boolean(data.rules_mangle_output_counters) && Boolean(data.rules_proxy_exist) && Boolean(data.rules_proxy_counters) && Boolean(data.rules_other_mark_exist); - const atLeastOneGood = Boolean(data.table_exist) || Boolean(data.rules_mangle_exist) || Boolean(data.rules_mangle_counters) || Boolean(data.rules_mangle_output_exist) || Boolean(data.rules_mangle_output_counters) || Boolean(data.rules_proxy_exist) || Boolean(data.rules_proxy_counters) || Boolean(data.rules_other_mark_exist); + const allGood = + Boolean(data.table_exist) && + Boolean(data.rules_mangle_exist) && + Boolean(data.rules_mangle_counters) && + Boolean(data.rules_mangle_output_exist) && + Boolean(data.rules_mangle_output_counters) && + Boolean(data.rules_proxy_exist) && + Boolean(data.rules_proxy_counters) && + Boolean(data.rules_other_mark_exist); + const atLeastOneGood = + Boolean(data.table_exist) || + Boolean(data.rules_mangle_exist) || + Boolean(data.rules_mangle_counters) || + Boolean(data.rules_mangle_output_exist) || + Boolean(data.rules_mangle_output_counters) || + Boolean(data.rules_proxy_exist) || + Boolean(data.rules_proxy_counters) || + Boolean(data.rules_other_mark_exist); function getStatus() { if (allGood) { return "success"; @@ -2549,50 +2617,54 @@ async function runNftCheck() { order, code, title, - description: allGood ? _("Nftables checks passed") : _("Nftables checks partially passed"), + description: allGood + ? _("Nftables checks passed") + : _("Nftables checks partially passed"), state: getStatus(), items: [ { state: data.table_exist ? "success" : "error", key: _("Table exist"), - value: "" + value: "", }, { state: data.rules_mangle_exist ? "success" : "error", key: _("Rules mangle exist"), - value: "" + value: "", }, { state: data.rules_mangle_counters ? "success" : "error", key: _("Rules mangle counters"), - value: "" + value: "", }, { state: data.rules_mangle_output_exist ? "success" : "error", key: _("Rules mangle output exist"), - value: "" + value: "", }, { state: data.rules_mangle_output_counters ? "success" : "error", key: _("Rules mangle output counters"), - value: "" + value: "", }, { state: data.rules_proxy_exist ? "success" : "error", key: _("Rules proxy exist"), - value: "" + value: "", }, { state: data.rules_proxy_counters ? "success" : "error", key: _("Rules proxy counters"), - value: "" + value: "", }, { state: !data.rules_other_mark_exist ? "success" : "warning", - key: !data.rules_other_mark_exist ? _("No other marking rules found") : _("Additional marking rules found"), - value: "" - } - ] + key: !data.rules_other_mark_exist + ? _("No other marking rules found") + : _("Additional marking rules found"), + value: "", + }, + ], }); if (!atLeastOneGood) { throw new Error("Nftables checks failed"); @@ -2608,34 +2680,39 @@ async function runFakeIPCheck() { title, description: _("Checking FakeIP, please wait"), state: "loading", - items: [] + items: [], }); const routerFakeIPResponse = await PodkopShellMethods.checkFakeIP(); const checkFakeIPResponse = await RemoteFakeIPMethods.getFakeIpCheck(); const checkIPResponse = await RemoteFakeIPMethods.getIpCheck(); const checks = { router: routerFakeIPResponse.success && routerFakeIPResponse.data.fakeip, - browserFakeIP: checkFakeIPResponse.success && checkFakeIPResponse.data.fakeip, - differentIP: checkFakeIPResponse.success && checkIPResponse.success && checkFakeIPResponse.data.IP !== checkIPResponse.data.IP + browserFakeIP: + checkFakeIPResponse.success && checkFakeIPResponse.data.fakeip, + differentIP: + checkFakeIPResponse.success && + checkIPResponse.success && + checkFakeIPResponse.data.IP !== checkIPResponse.data.IP, }; const allGood = checks.router || checks.browserFakeIP || checks.differentIP; - const atLeastOneGood = checks.router && checks.browserFakeIP && checks.differentIP; + const atLeastOneGood = + checks.router && checks.browserFakeIP && checks.differentIP; function getMeta() { if (allGood) { return { state: "success", - description: _("FakeIP checks passed") + description: _("FakeIP checks passed"), }; } if (atLeastOneGood) { return { state: "warning", - description: _("FakeIP checks partially passed") + description: _("FakeIP checks partially passed"), }; } return { state: "error", - description: _("FakeIP checks failed") + description: _("FakeIP checks failed"), }; } const { state, description } = getMeta(); @@ -2648,22 +2725,28 @@ async function runFakeIPCheck() { items: [ { state: checks.router ? "success" : "warning", - key: checks.router ? _("Router DNS is routed through sing-box") : _("Router DNS is not routed through sing-box"), - value: "" + key: checks.router + ? _("Router DNS is routed through sing-box") + : _("Router DNS is not routed through sing-box"), + value: "", }, { state: checks.browserFakeIP ? "success" : "error", - key: checks.browserFakeIP ? _("Browser is using FakeIP correctly") : _("Browser is not using FakeIP"), - value: "" + key: checks.browserFakeIP + ? _("Browser is using FakeIP correctly") + : _("Browser is not using FakeIP"), + value: "", }, ...insertIf(checks.browserFakeIP, [ { state: checks.differentIP ? "success" : "error", - key: checks.differentIP ? _("Proxy traffic is routed via FakeIP") : _("Proxy traffic is not routed via FakeIP"), - value: "" - } - ]) - ] + key: checks.differentIP + ? _("Proxy traffic is routed via FakeIP") + : _("Proxy traffic is not routed via FakeIP"), + value: "", + }, + ]), + ], }); } @@ -2735,11 +2818,11 @@ function renderLoaderCircleIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-loader-circle rotate" + class: "lucide lucide-loader-circle rotate", }, [ svgEl("path", { - d: "M21 12a9 9 0 1 1-6.219-8.56" + d: "M21 12a9 9 0 1 1-6.219-8.56", }), svgEl("animateTransform", { attributeName: "transform", @@ -2748,9 +2831,9 @@ function renderLoaderCircleIcon24() { from: "0 12 12", to: "360 12 12", dur: "1s", - repeatCount: "indefinite" - }) - ] + repeatCount: "indefinite", + }), + ], ); } @@ -2769,27 +2852,27 @@ function renderCircleAlertIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-alert-icon lucide-circle-alert" + class: "lucide lucide-circle-alert-icon lucide-circle-alert", }, [ svgEl("circle", { cx: "12", cy: "12", - r: "10" + r: "10", }), svgEl("line", { x1: "12", y1: "8", x2: "12", - y2: "12" + y2: "12", }), svgEl("line", { x1: "12", y1: "16", x2: "12.01", - y2: "16" - }) - ] + y2: "16", + }), + ], ); } @@ -2808,18 +2891,18 @@ function renderCircleCheckIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-check-icon lucide-circle-check" + class: "lucide lucide-circle-check-icon lucide-circle-check", }, [ svgEl("circle", { cx: "12", cy: "12", - r: "10" + r: "10", }), svgEl("path", { - d: "M9 12l2 2 4-4" - }) - ] + d: "M9 12l2 2 4-4", + }), + ], ); } @@ -2838,21 +2921,21 @@ function renderCircleSlashIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-slash-icon lucide-circle-slash" + class: "lucide lucide-circle-slash-icon lucide-circle-slash", }, [ svgEl("circle", { cx: "12", cy: "12", - r: "10" + r: "10", }), svgEl("line", { x1: "9", y1: "15", x2: "15", - y2: "9" - }) - ] + y2: "9", + }), + ], ); } @@ -2871,21 +2954,21 @@ function renderCircleXIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-x-icon lucide-circle-x" + class: "lucide lucide-circle-x-icon lucide-circle-x", }, [ svgEl("circle", { cx: "12", cy: "12", - r: "10" + r: "10", }), svgEl("path", { - d: "M15 9L9 15" + d: "M15 9L9 15", }), svgEl("path", { - d: "M9 9L15 15" - }) - ] + d: "M9 9L15 15", + }), + ], ); } @@ -2902,13 +2985,13 @@ function renderCheckIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-check-icon lucide-check" + class: "lucide lucide-check-icon lucide-check", }, [ svgEl("path", { - d: "M20 6 9 17l-5-5" - }) - ] + d: "M20 6 9 17l-5-5", + }), + ], ); } @@ -2925,9 +3008,9 @@ function renderXIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-x-icon lucide-x" + class: "lucide lucide-x-icon lucide-x", }, - [svgEl("path", { d: "M18 6 6 18" }), svgEl("path", { d: "m6 6 12 12" })] + [svgEl("path", { d: "M18 6 6 18" }), svgEl("path", { d: "m6 6 12 12" })], ); } @@ -2944,15 +3027,15 @@ function renderTriangleAlertIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-triangle-alert-icon lucide-triangle-alert" + class: "lucide lucide-triangle-alert-icon lucide-triangle-alert", }, [ svgEl("path", { - d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" + d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3", }), svgEl("path", { d: "M12 9v4" }), - svgEl("path", { d: "M12 17h.01" }) - ] + svgEl("path", { d: "M12 17h.01" }), + ], ); } @@ -2969,7 +3052,7 @@ function renderPauseIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-pause-icon lucide-pause" + class: "lucide lucide-pause-icon lucide-pause", }, [ svgEl("rect", { @@ -2977,16 +3060,16 @@ function renderPauseIcon24() { y: "3", width: "5", height: "18", - rx: "1" + rx: "1", }), svgEl("rect", { x: "5", y: "3", width: "5", height: "18", - rx: "1" - }) - ] + rx: "1", + }), + ], ); } @@ -3003,13 +3086,13 @@ function renderPlayIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-play-icon lucide-play" + class: "lucide lucide-play-icon lucide-play", }, [ svgEl("path", { - d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z" - }) - ] + d: "M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z", + }), + ], ); } @@ -3026,16 +3109,16 @@ function renderRotateCcwIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-rotate-ccw-icon lucide-rotate-ccw" + class: "lucide lucide-rotate-ccw-icon lucide-rotate-ccw", }, [ svgEl("path", { - d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" + d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", }), svgEl("path", { - d: "M3 3v5h5" - }) - ] + d: "M3 3v5h5", + }), + ], ); } @@ -3052,22 +3135,22 @@ function renderCircleStopIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-stop-icon lucide-circle-stop" + class: "lucide lucide-circle-stop-icon lucide-circle-stop", }, [ svgEl("circle", { cx: "12", cy: "12", - r: "10" + r: "10", }), svgEl("rect", { x: "9", y: "9", width: "6", height: "6", - rx: "1" - }) - ] + rx: "1", + }), + ], ); } @@ -3084,18 +3167,18 @@ function renderCirclePlayIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-play-icon lucide-circle-play" + class: "lucide lucide-circle-play-icon lucide-circle-play", }, [ svgEl("path", { - d: "M9 9.003a1 1 0 0 1 1.517-.859l4.997 2.997a1 1 0 0 1 0 1.718l-4.997 2.997A1 1 0 0 1 9 14.996z" + d: "M9 9.003a1 1 0 0 1 1.517-.859l4.997 2.997a1 1 0 0 1 0 1.718l-4.997 2.997A1 1 0 0 1 9 14.996z", }), svgEl("circle", { cx: "12", cy: "12", - r: "10" - }) - ] + r: "10", + }), + ], ); } @@ -3112,16 +3195,16 @@ function renderCircleCheckBigIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-circle-check-big-icon lucide-circle-check-big" + class: "lucide lucide-circle-check-big-icon lucide-circle-check-big", }, [ svgEl("path", { - d: "M21.801 10A10 10 0 1 1 17 3.335" + d: "M21.801 10A10 10 0 1 1 17 3.335", }), svgEl("path", { - d: "m9 11 3 3L22 4" - }) - ] + d: "m9 11 3 3L22 4", + }), + ], ); } @@ -3138,7 +3221,7 @@ function renderSquareChartGanttIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-square-chart-gantt-icon lucide-square-chart-gantt" + class: "lucide lucide-square-chart-gantt-icon lucide-square-chart-gantt", }, [ svgEl("rect", { @@ -3146,12 +3229,12 @@ function renderSquareChartGanttIcon24() { height: "18", x: "3", y: "3", - rx: "2" + rx: "2", }), svgEl("path", { d: "M9 8h7" }), svgEl("path", { d: "M8 12h6" }), - svgEl("path", { d: "M11 16h5" }) - ] + svgEl("path", { d: "M11 16h5" }), + ], ); } @@ -3168,7 +3251,7 @@ function renderCogIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-cog-icon lucide-cog" + class: "lucide lucide-cog-icon lucide-cog", }, [ svgEl("path", { d: "M11 10.27 7 3.34" }), @@ -3184,8 +3267,8 @@ function renderCogIcon24() { svgEl("path", { d: "m3.34 17 1.73-1" }), svgEl("path", { d: "m3.34 7 1.73 1" }), svgEl("circle", { cx: "12", cy: "12", r: "2" }), - svgEl("circle", { cx: "12", cy: "12", r: "8" }) - ] + svgEl("circle", { cx: "12", cy: "12", r: "8" }), + ], ); } @@ -3202,12 +3285,12 @@ function renderSearchIcon24() { "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", - class: "lucide lucide-search-icon lucide-search" + class: "lucide lucide-search-icon lucide-search", }, [ svgEl("path", { d: "m21 21-4.34-4.34" }), - svgEl("circle", { cx: "11", cy: "11", r: "8" }) - ] + svgEl("circle", { cx: "11", cy: "11", r: "8" }), + ], ); } @@ -3218,12 +3301,12 @@ function renderButton({ loading, onClick, text, - icon + icon, }) { const hasIcon = !!loading || !!icon; function getWrappedIcon() { const iconWrap = E("span", { - class: "pdk-partial-button__icon" + class: "pdk-partial-button__icon", }); if (loading) { iconWrap.appendChild(renderLoaderCircleIcon24()); @@ -3242,8 +3325,10 @@ function renderButton({ ...insertIf(Boolean(disabled), ["pdk-partial-button--disabled"]), ...insertIf(Boolean(loading), ["pdk-partial-button--loading"]), ...insertIf(Boolean(hasIcon), ["pdk-partial-button--with-icon"]), - ...classNames - ].filter(Boolean).join(" "); + ...classNames, + ] + .filter(Boolean) + .join(" "); } function getDisabled() { if (loading || disabled) { @@ -3254,7 +3339,7 @@ function renderButton({ return E( "button", { class: getClass(), disabled: getDisabled(), click: onClick }, - [...insertIf(hasIcon, [getWrappedIcon()]), E("span", {}, text)] + [...insertIf(hasIcon, [getWrappedIcon()]), E("span", {}, text)], ); } @@ -3304,22 +3389,23 @@ function renderModal(text, name) { renderButton({ classNames: ["cbi-button-apply"], text: _("Download"), - onClick: () => downloadAsTxt(text, name) + onClick: () => downloadAsTxt(text, name), }), renderButton({ classNames: ["cbi-button-apply"], text: _("Copy"), - onClick: () => copyToClipboard(` \`\`\`${name} + onClick: () => + copyToClipboard(` \`\`\`${name} ${text} - \`\`\``) + \`\`\``), }), renderButton({ classNames: ["cbi-button-remove"], text: _("Close"), - onClick: ui.hideModal - }) - ]) - ]) + onClick: ui.hideModal, + }), + ]), + ]), ); } @@ -3338,7 +3424,7 @@ function renderAvailableActions({ disable, globalCheck, viewLogs, - showSingBoxConfig + showSingBoxConfig, }) { return E("div", { class: "pdk_diagnostic-page__right-bar__actions" }, [ E("b", {}, "Available actions"), @@ -3349,8 +3435,8 @@ function renderAvailableActions({ icon: renderRotateCcwIcon24, text: _("Restart podkop"), loading: restart.loading, - disabled: restart.disabled - }) + disabled: restart.disabled, + }), ]), ...insertIf(stop.visible, [ renderButton({ @@ -3359,8 +3445,8 @@ function renderAvailableActions({ icon: renderCircleStopIcon24, text: _("Stop podkop"), loading: stop.loading, - disabled: stop.disabled - }) + disabled: stop.disabled, + }), ]), ...insertIf(start.visible, [ renderButton({ @@ -3369,8 +3455,8 @@ function renderAvailableActions({ icon: renderCirclePlayIcon24, text: _("Start podkop"), loading: start.loading, - disabled: start.disabled - }) + disabled: start.disabled, + }), ]), ...insertIf(disable.visible, [ renderButton({ @@ -3379,8 +3465,8 @@ function renderAvailableActions({ icon: renderPauseIcon24, text: _("Disable autostart"), loading: disable.loading, - disabled: disable.disabled - }) + disabled: disable.disabled, + }), ]), ...insertIf(enable.visible, [ renderButton({ @@ -3389,8 +3475,8 @@ function renderAvailableActions({ icon: renderPlayIcon24, text: _("Enable autostart"), loading: enable.loading, - disabled: enable.disabled - }) + disabled: enable.disabled, + }), ]), ...insertIf(globalCheck.visible, [ renderButton({ @@ -3398,8 +3484,8 @@ function renderAvailableActions({ icon: renderCircleCheckBigIcon24, text: _("Get global check"), loading: globalCheck.loading, - disabled: globalCheck.disabled - }) + disabled: globalCheck.disabled, + }), ]), ...insertIf(viewLogs.visible, [ renderButton({ @@ -3407,8 +3493,8 @@ function renderAvailableActions({ icon: renderSquareChartGanttIcon24, text: _("View logs"), loading: viewLogs.loading, - disabled: viewLogs.disabled - }) + disabled: viewLogs.disabled, + }), ]), ...insertIf(showSingBoxConfig.visible, [ renderButton({ @@ -3416,9 +3502,9 @@ function renderAvailableActions({ icon: renderCogIcon24, text: _("Show sing-box config"), loading: showSingBoxConfig.loading, - disabled: showSingBoxConfig.disabled - }) - ]) + disabled: showSingBoxConfig.disabled, + }), + ]), ]); } @@ -3430,7 +3516,7 @@ function renderCheckSummary(items) { const renderedItems = items.map((item) => { function getIcon() { const iconWrap = E("span", { - class: "pdk_diagnostic_alert__summary__item__icon" + class: "pdk_diagnostic_alert__summary__item__icon", }); if (item.state === "success") { iconWrap.appendChild(renderCheckIcon24()); @@ -3446,9 +3532,9 @@ function renderCheckSummary(items) { return E( "div", { - class: `pdk_diagnostic_alert__summary__item pdk_diagnostic_alert__summary__item--${item.state}` + class: `pdk_diagnostic_alert__summary__item pdk_diagnostic_alert__summary__item--${item.state}`, }, - [getIcon(), E("b", {}, item.key), E("div", {}, item.value)] + [getIcon(), E("b", {}, item.key), E("div", {}, item.value)], ); }); return E("div", { class: "pdk_diagnostic_alert__summary" }, renderedItems); @@ -3466,12 +3552,12 @@ function renderLoadingState3(props) { E( "div", { class: "pdk_diagnostic_alert__description" }, - props.description - ) + props.description, + ), ]), E("div", {}, ""), - renderCheckSummary(props.items) - ] + renderCheckSummary(props.items), + ], ); } function renderWarningState(props) { @@ -3487,12 +3573,12 @@ function renderWarningState(props) { E( "div", { class: "pdk_diagnostic_alert__description" }, - props.description - ) + props.description, + ), ]), E("div", {}, ""), - renderCheckSummary(props.items) - ] + renderCheckSummary(props.items), + ], ); } function renderErrorState(props) { @@ -3508,12 +3594,12 @@ function renderErrorState(props) { E( "div", { class: "pdk_diagnostic_alert__description" }, - props.description - ) + props.description, + ), ]), E("div", {}, ""), - renderCheckSummary(props.items) - ] + renderCheckSummary(props.items), + ], ); } function renderSuccessState(props) { @@ -3529,12 +3615,12 @@ function renderSuccessState(props) { E( "div", { class: "pdk_diagnostic_alert__description" }, - props.description - ) + props.description, + ), ]), E("div", {}, ""), - renderCheckSummary(props.items) - ] + renderCheckSummary(props.items), + ], ); } function renderSkippedState(props) { @@ -3550,12 +3636,12 @@ function renderSkippedState(props) { E( "div", { class: "pdk_diagnostic_alert__description" }, - props.description - ) + props.description, + ), ]), E("div", {}, ""), - renderCheckSummary(props.items) - ] + renderCheckSummary(props.items), + ], ); } function renderCheckSection(props) { @@ -3578,18 +3664,15 @@ function renderCheckSection(props) { } // src/podkop/tabs/diagnostic/partials/renderRunAction.ts -function renderRunAction({ - loading, - click -}) { +function renderRunAction({ loading, click }) { return E("div", { class: "pdk_diagnostic-page__run_check_wrapper" }, [ renderButton({ text: _("Run Diagnostic"), onClick: click, icon: renderSearchIcon24, loading, - classNames: ["cbi-button-apply"] - }) + classNames: ["cbi-button-apply"], + }), ]); } @@ -3599,18 +3682,20 @@ function renderSystemInfo({ items }) { E( "b", { class: "pdk_diagnostic-page__right-bar__system-info__title" }, - "System information" + "System information", ), ...items.map((item) => { const tagClass = [ "pdk_diagnostic-page__right-bar__system-info__row__tag", ...insertIf(item.tag?.kind === "warning", [ - "pdk_diagnostic-page__right-bar__system-info__row__tag--warning" + "pdk_diagnostic-page__right-bar__system-info__row__tag--warning", ]), ...insertIf(item.tag?.kind === "success", [ - "pdk_diagnostic-page__right-bar__system-info__row__tag--success" - ]) - ].filter(Boolean).join(" "); + "pdk_diagnostic-page__right-bar__system-info__row__tag--success", + ]), + ] + .filter(Boolean) + .join(" "); return E( "div", { class: "pdk_diagnostic-page__right-bar__system-info__row" }, @@ -3618,11 +3703,11 @@ function renderSystemInfo({ items }) { E("b", {}, item.key), E("div", {}, [ E("span", {}, item.value), - E("span", { class: tagClass }, item?.tag?.label) - ]) - ] + E("span", { class: tagClass }, item?.tag?.label), + ]), + ], ); - }) + }), ]); } @@ -3641,8 +3726,8 @@ async function fetchSystemInfo() { store.set({ diagnosticsSystemInfo: { loading: false, - ...systemInfo.data - } + ...systemInfo.data, + }, }); } else { store.set({ @@ -3653,17 +3738,19 @@ async function fetchSystemInfo() { luci_app_version: _("unknown"), sing_box_version: _("unknown"), openwrt_version: _("unknown"), - device_model: _("unknown") - } + device_model: _("unknown"), + }, }); } } function renderDiagnosticsChecks() { logger.debug("[DIAGNOSTIC]", "renderDiagnosticsChecks"); - const diagnosticsChecks = store.get().diagnosticsChecks.sort((a, b) => a.order - b.order); + const diagnosticsChecks = store + .get() + .diagnosticsChecks.sort((a, b) => a.order - b.order); const container = document.getElementById("pdk_diagnostic-page-checks"); - const renderedDiagnosticsChecks = diagnosticsChecks.map( - (check) => renderCheckSection(check) + const renderedDiagnosticsChecks = diagnosticsChecks.map((check) => + renderCheckSection(check), ); return preserveScrollForPage(() => { container.replaceChildren(...renderedDiagnosticsChecks); @@ -3675,7 +3762,7 @@ function renderDiagnosticRunActionWidget() { const container = document.getElementById("pdk_diagnostic-page-run-check"); const renderedAction = renderRunAction({ loading, - click: () => runChecks() + click: () => runChecks(), }); return preserveScrollForPage(() => { container.replaceChildren(renderedAction); @@ -3686,8 +3773,8 @@ async function handleRestart() { store.set({ diagnosticsActions: { ...diagnosticsActions, - restart: { loading: true } - } + restart: { loading: true }, + }, }); try { await PodkopShellMethods.restart(); @@ -3699,8 +3786,8 @@ async function handleRestart() { store.set({ diagnosticsActions: { ...diagnosticsActions, - restart: { loading: false } - } + restart: { loading: false }, + }, }); store.reset(["diagnosticsChecks"]); }, 5e3); @@ -3711,8 +3798,8 @@ async function handleStop() { store.set({ diagnosticsActions: { ...diagnosticsActions, - stop: { loading: true } - } + stop: { loading: true }, + }, }); try { await PodkopShellMethods.stop(); @@ -3723,8 +3810,8 @@ async function handleStop() { store.set({ diagnosticsActions: { ...diagnosticsActions, - stop: { loading: false } - } + stop: { loading: false }, + }, }); store.reset(["diagnosticsChecks"]); } @@ -3734,8 +3821,8 @@ async function handleStart() { store.set({ diagnosticsActions: { ...diagnosticsActions, - start: { loading: true } - } + start: { loading: true }, + }, }); try { await PodkopShellMethods.start(); @@ -3747,8 +3834,8 @@ async function handleStart() { store.set({ diagnosticsActions: { ...diagnosticsActions, - start: { loading: false } - } + start: { loading: false }, + }, }); store.reset(["diagnosticsChecks"]); }, 5e3); @@ -3759,8 +3846,8 @@ async function handleEnable() { store.set({ diagnosticsActions: { ...diagnosticsActions, - enable: { loading: true } - } + enable: { loading: true }, + }, }); try { await PodkopShellMethods.enable(); @@ -3771,8 +3858,8 @@ async function handleEnable() { store.set({ diagnosticsActions: { ...diagnosticsActions, - enable: { loading: false } - } + enable: { loading: false }, + }, }); } } @@ -3781,8 +3868,8 @@ async function handleDisable() { store.set({ diagnosticsActions: { ...diagnosticsActions, - disable: { loading: true } - } + disable: { loading: true }, + }, }); try { await PodkopShellMethods.disable(); @@ -3793,8 +3880,8 @@ async function handleDisable() { store.set({ diagnosticsActions: { ...diagnosticsActions, - disable: { loading: false } - } + disable: { loading: false }, + }, }); } } @@ -3803,15 +3890,15 @@ async function handleShowGlobalCheck() { store.set({ diagnosticsActions: { ...diagnosticsActions, - globalCheck: { loading: true } - } + globalCheck: { loading: true }, + }, }); try { const globalCheck = await PodkopShellMethods.globalCheck(); if (globalCheck.success) { ui.showModal( _("Global check"), - renderModal(globalCheck.data, "global_check") + renderModal(globalCheck.data, "global_check"), ); } } catch (e) { @@ -3820,8 +3907,8 @@ async function handleShowGlobalCheck() { store.set({ diagnosticsActions: { ...diagnosticsActions, - globalCheck: { loading: false } - } + globalCheck: { loading: false }, + }, }); } } @@ -3830,16 +3917,13 @@ async function handleViewLogs() { store.set({ diagnosticsActions: { ...diagnosticsActions, - viewLogs: { loading: true } - } + viewLogs: { loading: true }, + }, }); try { const viewLogs = await PodkopShellMethods.checkLogs(); if (viewLogs.success) { - ui.showModal( - _("View logs"), - renderModal(viewLogs.data, "view_logs") - ); + ui.showModal(_("View logs"), renderModal(viewLogs.data, "view_logs")); } } catch (e) { logger.error("[DIAGNOSTIC]", "handleViewLogs - e", e); @@ -3847,8 +3931,8 @@ async function handleViewLogs() { store.set({ diagnosticsActions: { ...diagnosticsActions, - viewLogs: { loading: false } - } + viewLogs: { loading: false }, + }, }); } } @@ -3857,15 +3941,15 @@ async function handleShowSingBoxConfig() { store.set({ diagnosticsActions: { ...diagnosticsActions, - showSingBoxConfig: { loading: true } - } + showSingBoxConfig: { loading: true }, + }, }); try { const showSingBoxConfig = await PodkopShellMethods.showSingBoxConfig(); if (showSingBoxConfig.success) { ui.showModal( _("Show sing-box config"), - renderModal(showSingBoxConfig.data, "show_sing_box_config") + renderModal(showSingBoxConfig.data, "show_sing_box_config"), ); } } catch (e) { @@ -3874,8 +3958,8 @@ async function handleShowSingBoxConfig() { store.set({ diagnosticsActions: { ...diagnosticsActions, - showSingBoxConfig: { loading: false } - } + showSingBoxConfig: { loading: false }, + }, }); } } @@ -3885,57 +3969,61 @@ function renderDiagnosticAvailableActionsWidget() { logger.debug("[DIAGNOSTIC]", "renderDiagnosticAvailableActionsWidget"); const podkopEnabled = Boolean(servicesInfoWidget.data.podkop); const singBoxRunning = Boolean(servicesInfoWidget.data.singbox); - const atLeastOneServiceCommandLoading = servicesInfoWidget.loading || diagnosticsActions.restart.loading || diagnosticsActions.start.loading || diagnosticsActions.stop.loading; + const atLeastOneServiceCommandLoading = + servicesInfoWidget.loading || + diagnosticsActions.restart.loading || + diagnosticsActions.start.loading || + diagnosticsActions.stop.loading; const container = document.getElementById("pdk_diagnostic-page-actions"); const renderedActions = renderAvailableActions({ restart: { loading: diagnosticsActions.restart.loading, visible: true, onClick: handleRestart, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, start: { loading: diagnosticsActions.start.loading, visible: !singBoxRunning, onClick: handleStart, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, stop: { loading: diagnosticsActions.stop.loading, visible: singBoxRunning, onClick: handleStop, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, enable: { loading: diagnosticsActions.enable.loading, visible: !podkopEnabled, onClick: handleEnable, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, disable: { loading: diagnosticsActions.disable.loading, visible: podkopEnabled, onClick: handleDisable, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, globalCheck: { loading: diagnosticsActions.globalCheck.loading, visible: true, onClick: handleShowGlobalCheck, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, viewLogs: { loading: diagnosticsActions.viewLogs.loading, visible: true, onClick: handleViewLogs, - disabled: atLeastOneServiceCommandLoading + disabled: atLeastOneServiceCommandLoading, }, showSingBoxConfig: { loading: diagnosticsActions.showSingBoxConfig.loading, visible: true, onClick: handleShowSingBoxConfig, - disabled: atLeastOneServiceCommandLoading - } + disabled: atLeastOneServiceCommandLoading, + }, }); return preserveScrollForPage(() => { container.replaceChildren(renderedActions); @@ -3949,16 +4037,16 @@ function renderDiagnosticSystemInfoWidget() { const loading = diagnosticsSystemInfo.loading; const unknown = diagnosticsSystemInfo.podkop_version === _("unknown"); const hasActualVersion = Boolean( - diagnosticsSystemInfo.podkop_latest_version + diagnosticsSystemInfo.podkop_latest_version, ); const version = normalizeCompiledVersion( - diagnosticsSystemInfo.podkop_version + diagnosticsSystemInfo.podkop_version, ); const isDevVersion = version === "dev"; if (loading || unknown || !hasActualVersion || isDevVersion) { return { key: "Podkop", - value: version + value: version, }; } if (version !== diagnosticsSystemInfo.podkop_latest_version) { @@ -3967,8 +4055,8 @@ function renderDiagnosticSystemInfoWidget() { value: version, tag: { label: _("Outdated"), - kind: "warning" - } + kind: "warning", + }, }; } return { @@ -3976,8 +4064,8 @@ function renderDiagnosticSystemInfoWidget() { value: version, tag: { label: _("Latest"), - kind: "success" - } + kind: "success", + }, }; } const renderedSystemInfo = renderSystemInfo({ @@ -3985,21 +4073,21 @@ function renderDiagnosticSystemInfoWidget() { getPodkopVersionRow(), { key: "Luci App", - value: normalizeCompiledVersion(diagnosticsSystemInfo.luci_app_version) + value: normalizeCompiledVersion(diagnosticsSystemInfo.luci_app_version), }, { key: "Sing-box", - value: diagnosticsSystemInfo.sing_box_version + value: diagnosticsSystemInfo.sing_box_version, }, { key: "OS", - value: diagnosticsSystemInfo.openwrt_version + value: diagnosticsSystemInfo.openwrt_version, }, { key: "Device", - value: diagnosticsSystemInfo.device_model - } - ] + value: diagnosticsSystemInfo.device_model, + }, + ], }); return preserveScrollForPage(() => { container.replaceChildren(renderedSystemInfo); @@ -4023,7 +4111,7 @@ async function runChecks() { try { store.set({ diagnosticsRunAction: { loading: true }, - diagnosticsChecks: loadingDiagnosticsChecksStore.diagnosticsChecks + diagnosticsChecks: loadingDiagnosticsChecksStore.diagnosticsChecks, }); await runDnsCheck(); await runSingBoxCheck(); @@ -4051,23 +4139,26 @@ function onPageUnmount2() { "diagnosticsActions", "diagnosticsSystemInfo", "diagnosticsChecks", - "diagnosticsRunAction" + "diagnosticsRunAction", ]); } function registerLifecycleListeners2() { store.subscribe((next, prev, diff) => { - if (diff.tabService && next.tabService.current !== prev.tabService.current) { + if ( + diff.tabService && + next.tabService.current !== prev.tabService.current + ) { logger.debug( "[DIAGNOSTIC]", "active tab diff event, active tab:", - diff.tabService.current + diff.tabService.current, ); const isDIAGNOSTICVisible = next.tabService.current === "diagnostic"; if (isDIAGNOSTICVisible) { logger.debug( "[DIAGNOSTIC]", "registerLifecycleListeners", - "onPageMount" + "onPageMount", ); return onPageMount2(); } @@ -4075,7 +4166,7 @@ function registerLifecycleListeners2() { logger.debug( "[DIAGNOSTIC]", "registerLifecycleListeners", - "onPageUnmount" + "onPageUnmount", ); return onPageUnmount2(); } @@ -4260,7 +4351,7 @@ var styles4 = ` var DiagnosticTab = { render: render2, initController: initController2, - styles: styles4 + styles: styles4, }; // src/styles.ts @@ -4381,12 +4472,17 @@ function injectGlobalStyles() { - ` + `, ); } // src/helpers/withTimeout.ts -async function withTimeout(promise, timeoutMs, operationName, timeoutMessage = _("Operation timed out")) { +async function withTimeout( + promise, + timeoutMs, + operationName, + timeoutMessage = _("Operation timed out"), +) { let timeoutId; const start = performance.now(); const timeoutPromise = new Promise((_2, reject) => { @@ -4405,13 +4501,13 @@ async function withTimeout(promise, timeoutMs, operationName, timeoutMessage = _ async function executeShellCommand({ command, args, - timeout = COMMAND_TIMEOUT + timeout = COMMAND_TIMEOUT, }) { try { return withTimeout( fs.exec(command, args), timeout, - [command, ...args].join(" ") + [command, ...args].join(" "), ); } catch (err) { const error = err; @@ -4461,7 +4557,7 @@ async function onMount(id) { }); observer.observe(document.body, { childList: true, - subtree: true + subtree: true, }); }); } @@ -4478,7 +4574,11 @@ function getClashUIUrl() { // src/helpers/splitProxyString.ts function splitProxyString(str) { - return str.split("\n").map((line) => line.trim()).filter((line) => !line.startsWith("//")).filter(Boolean); + return str + .split("\n") + .map((line) => line.trim()) + .filter((line) => !line.startsWith("//")) + .filter(Boolean); } // src/helpers/preserveScrollForPage.ts @@ -4497,7 +4597,9 @@ function svgEl(tag, attrs = {}, children = []) { for (const [k, v] of Object.entries(attrs)) { if (v != null) el.setAttribute(k, String(v)); } - (Array.isArray(children) ? children : [children]).filter(Boolean).forEach((ch) => el.appendChild(ch)); + (Array.isArray(children) ? children : [children]) + .filter(Boolean) + .forEach((ch) => el.appendChild(ch)); return el; } @@ -4566,5 +4668,5 @@ return baseclass.extend({ validateTrojanUrl, validateUrl, validateVlessUrl, - withTimeout + withTimeout, }); diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js index 7903b96..c03a3e0 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js @@ -42,39 +42,20 @@ function createSectionContent(section) { o.textarea = true; o.rmempty = false; 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"; o.validate = function (section_id, value) { // Optional if (!value || value.length === 0) { return true; } - try { - const activeConfigs = main.splitProxyString(value); + const validation = main.validateProxyUrl(value); - if (!activeConfigs.length) { - return _( - "No active configuration found. One configuration is required.", - ); - } - - if (activeConfigs.length > 1) { - return _( - "Multiply active configurations found. Please leave one configuration.", - ); - } - - const validation = main.validateProxyUrl(activeConfigs[0]); - - if (validation.valid) { - return true; - } - - return validation.message; - } catch (e) { - return `${_("Invalid URL format:")} ${e?.message}`; + if (validation.valid) { + return true; } + + return validation.message; }; o = section.option( diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js index b36e70a..3b735bc 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js @@ -83,6 +83,43 @@ function createSettingsContent(section) { return true; }; + o = section.option( + widgets.DeviceSelect, + "source_network_interfaces", + _("Source Network Interface"), + _("Select the network interface from which the traffic will originate"), + ); + o.default = "br-lan"; + o.noaliases = true; + o.nobridges = false; + o.noinactive = false; + o.multiple = true; + o.filter = function (section_id, value) { + // Block specific interface names from being selectable + const blocked = ["wan", "phy0-ap0", "phy1-ap0", "pppoe-wan"]; + if (blocked.includes(value)) { + return false; + } + + // Try to find the device object by its name + const device = this.devices.find((dev) => dev.getName() === value); + + // If no device is found, allow the value + if (!device) { + return true; + } + + // Check the type of the device + const type = device.getType(); + + // Consider any Wi-Fi / wireless / wlan device as invalid + const isWireless = + type === "wifi" || type === "wireless" || type.includes("wlan"); + + // Allow only non-wireless devices + return !isWireless; + }; + o = section.option( form.Flag, "enable_output_network_interface", @@ -139,43 +176,6 @@ function createSettingsContent(section) { return !isWireless; }; - o = section.option( - widgets.DeviceSelect, - "source_network_interfaces", - _("Source Network Interface"), - _("Select the network interface from which the traffic will originate"), - ); - o.default = "br-lan"; - o.noaliases = true; - o.nobridges = false; - o.noinactive = false; - o.multiple = true; - o.filter = function (section_id, value) { - // Block specific interface names from being selectable - const blocked = ["wan", "phy0-ap0", "phy1-ap0", "pppoe-wan"]; - if (blocked.includes(value)) { - return false; - } - - // Try to find the device object by its name - const device = this.devices.find((dev) => dev.getName() === value); - - // If no device is found, allow the value - if (!device) { - return true; - } - - // Check the type of the device - const type = device.getType(); - - // Consider any Wi-Fi / wireless / wlan device as invalid - const isWireless = - type === "wifi" || type === "wireless" || type.includes("wlan"); - - // Allow only non-wireless devices - return !isWireless; - }; - o = section.option( form.Flag, "enable_badwan_interface_monitoring",