diff --git a/fe-app-podkop/src/validators/index.ts b/fe-app-podkop/src/validators/index.ts index 8c6c5e1..fd9e2cc 100644 --- a/fe-app-podkop/src/validators/index.ts +++ b/fe-app-podkop/src/validators/index.ts @@ -8,3 +8,4 @@ export * from './bulkValidate'; export * from './validateShadowsocksUrl'; export * from './validateVlessUrl'; export * from './validateOutboundJson'; +export * from './validateTrojanUrl'; diff --git a/fe-app-podkop/src/validators/validateTrojanUrl.ts b/fe-app-podkop/src/validators/validateTrojanUrl.ts new file mode 100644 index 0000000..03f53cd --- /dev/null +++ b/fe-app-podkop/src/validators/validateTrojanUrl.ts @@ -0,0 +1,26 @@ +import { ValidationResult } from './types'; + +// TODO refactor current validation and add tests +export function validateTrojanUrl(url: string): ValidationResult { + if (!url.startsWith('trojan://')) { + return { + valid: false, + message: 'Invalid Trojan URL: must start with trojan://', + }; + } + + try { + const parsedUrl = new URL(url); + + if (!parsedUrl.username || !parsedUrl.hostname || !parsedUrl.port) { + return { + valid: false, + message: 'Invalid Trojan URL: must contain username, hostname and port', + }; + } + } catch (e) { + return { valid: false, message: 'Invalid Trojan URL: parsing failed' }; + } + + return { valid: true, message: 'Valid' }; +} diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/configSection.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/configSection.js index 0d5862b..dd8ff31 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/configSection.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/configSection.js @@ -34,7 +34,7 @@ function createConfigSection(section) { o.rmempty = false; o.ucisection = s.section; 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'; + 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'; o.renderWidget = function (section_id, option_index, cfgvalue) { const original = form.TextValue.prototype.renderWidget.apply(this, [section_id, option_index, cfgvalue]); @@ -112,7 +112,17 @@ function createConfigSection(section) { return _(validation.message) } - return _('URL must start with vless:// or ss://') + if (activeConfig.startsWith('trojan://')) { + const validation = main.validateTrojanUrl(activeConfig); + + if (validation.valid) { + return true; + } + + return _(validation.message) + } + + return _('URL must start with vless:// or ss:// or trojan://') } catch (e) { return `${_('Invalid URL format:')} ${e?.message}`; 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 d837b30..ae3ee34 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 @@ -277,6 +277,28 @@ function validateOutboundJson(value) { } } +// src/validators/validateTrojanUrl.ts +function validateTrojanUrl(url) { + if (!url.startsWith("trojan://")) { + return { + valid: false, + message: "Invalid Trojan URL: must start with trojan://" + }; + } + try { + const parsedUrl = new URL(url); + if (!parsedUrl.username || !parsedUrl.hostname || !parsedUrl.port) { + return { + valid: false, + message: "Invalid Trojan URL: must contain username, hostname and port" + }; + } + } catch (e) { + return { valid: false, message: "Invalid Trojan URL: parsing failed" }; + } + return { valid: true, message: "Valid" }; +} + // src/helpers/getBaseUrl.ts function getBaseUrl() { const { protocol, hostname } = window.location; @@ -465,6 +487,7 @@ return baseclass.extend({ validatePath, validateShadowsocksUrl, validateSubnet, + validateTrojanUrl, validateUrl, validateVlessUrl });