From 72b2a34af9dd7729b70a6299161268b28b7115e6 Mon Sep 17 00:00:00 2001 From: divocat Date: Tue, 7 Oct 2025 19:19:10 +0300 Subject: [PATCH] fix: allow .tld for user_domains_text & user_domains --- .../src/validators/tests/validateDomain.test.js | 17 +++++++++++++++++ fe-app-podkop/src/validators/validateDomain.ts | 14 ++++++++++++-- .../resources/view/podkop/configSection.js | 4 ++-- .../luci-static/resources/view/podkop/main.js | 8 +++++++- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/fe-app-podkop/src/validators/tests/validateDomain.test.js b/fe-app-podkop/src/validators/tests/validateDomain.test.js index a2c312a..b26bc23 100644 --- a/fe-app-podkop/src/validators/tests/validateDomain.test.js +++ b/fe-app-podkop/src/validators/tests/validateDomain.test.js @@ -29,6 +29,13 @@ export const invalidDomains = [ ['Too long domain (>253 chars)', Array(40).fill('abcdef').join('.') + '.com'], ]; +export const dotTLDTests = [ + ['Dot TLD allowed (.net)', '.net', true, true], + ['Dot TLD not allowed (.net)', '.net', false, false], + ['Invalid with double dot', '..net', true, false], + ['Invalid single word TLD (net)', 'net', true, false], +]; + describe('validateDomain', () => { describe.each(validDomains)('Valid domain: %s', (_desc, domain) => { it(`returns valid=true for "${domain}"`, () => { @@ -43,4 +50,14 @@ describe('validateDomain', () => { expect(res.valid).toBe(false); }); }); + + describe.each(dotTLDTests)( + 'Dot TLD toggle: %s', + (_desc, domain, allowDotTLD, expected) => { + it(`"${domain}" with allowDotTLD=${allowDotTLD} → valid=${expected}`, () => { + const res = validateDomain(domain, allowDotTLD); + expect(res.valid).toBe(expected); + }); + }, + ); }); diff --git a/fe-app-podkop/src/validators/validateDomain.ts b/fe-app-podkop/src/validators/validateDomain.ts index fdebefa..d4ff863 100644 --- a/fe-app-podkop/src/validators/validateDomain.ts +++ b/fe-app-podkop/src/validators/validateDomain.ts @@ -1,8 +1,18 @@ import { ValidationResult } from './types'; -export function validateDomain(domain: string): ValidationResult { +export function validateDomain( + domain: string, + allowDotTLD = false +): ValidationResult { 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]*)?$/; + /^(?=.{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)) { + return { valid: true, message: _('Valid') }; + } + } if (!domainRegex.test(domain)) { return { valid: false, message: _('Invalid domain address') }; 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 cde7914..bc49dc7 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 @@ -455,7 +455,7 @@ function createConfigSection(section) { return true; } - const validation = main.validateDomain(value); + const validation = main.validateDomain(value, true); if (validation.valid) { return true; @@ -493,7 +493,7 @@ function createConfigSection(section) { ); } - const { valid, results } = main.bulkValidate(domains, main.validateDomain); + const { valid, results } = main.bulkValidate(domains, row => main.validateDomain(row, true)); if (!valid) { const errors = results 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 99ffd3d..d417fca 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 @@ -14,8 +14,14 @@ function validateIPV4(ip) { } // src/validators/validateDomain.ts -function validateDomain(domain) { +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]*)?$/; + if (allowDotTLD) { + const dotTLD = /^\.[a-zA-Z]{2,}$/; + if (dotTLD.test(domain)) { + return { valid: true, message: _("Valid") }; + } + } if (!domainRegex.test(domain)) { return { valid: false, message: _("Invalid domain address") }; }