From 4d2866e2cd9a39c248471ad68eeaee37dbabb9f4 Mon Sep 17 00:00:00 2001 From: Runya Date: Sun, 20 Sep 2026 19:42:58 +0300 Subject: [PATCH 1/2] ui: clarify worker count wording in add/edit dialogs --- frontend/src/modals/Add-server.tsx | 4 ++-- frontend/src/modals/Edit-server.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/modals/Add-server.tsx b/frontend/src/modals/Add-server.tsx index aa2f7cb6..426aee87 100644 --- a/frontend/src/modals/Add-server.tsx +++ b/frontend/src/modals/Add-server.tsx @@ -138,7 +138,7 @@ export default function AddServer({ onClose, onAdd }: Props) {
- Мощность + Количество воркеров {filledHashes === 0 ? 'нет хешей' : power}
0 ? Math.round((Math.min(power, powerMax) - 9) / Math.max(powerMax - 9, 1) * 100) : 0 } as React.CSSProperties} onChange={e => setPower(+e.target.value)} - aria-label="Мощность" + aria-label="Количество воркеров" />
diff --git a/frontend/src/modals/Edit-server.tsx b/frontend/src/modals/Edit-server.tsx index e0522b64..71141ed9 100644 --- a/frontend/src/modals/Edit-server.tsx +++ b/frontend/src/modals/Edit-server.tsx @@ -127,7 +127,7 @@ export default function EditServer({ server, onClose, onSave, onDelete }: Props)
- Мощность + Количество воркеров {filledHashes === 0 ? 'нет хешей' : power}
0 ? Math.round((Math.min(power, powerMax) - 9) / Math.max(powerMax - 9, 1) * 100) : 0 } as React.CSSProperties} onChange={e => setPower(+e.target.value)} - aria-label="Мощность" + aria-label="Количество воркеров" />
From 5e7894dd71a273975882f4074e870100d75e45e9 Mon Sep 17 00:00:00 2001 From: Runya Date: Sun, 20 Sep 2026 20:16:21 +0300 Subject: [PATCH 2/2] fix: validate workers parsed from qwdtt link --- frontend/src/__tests__/wdttLink.test.ts | 18 ++++++++++++++++++ frontend/src/lib/utils/wdttLink.ts | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/frontend/src/__tests__/wdttLink.test.ts b/frontend/src/__tests__/wdttLink.test.ts index 30599c14..ef33a2bf 100644 --- a/frontend/src/__tests__/wdttLink.test.ts +++ b/frontend/src/__tests__/wdttLink.test.ts @@ -107,4 +107,22 @@ describe('parseWdttUrl', () => { it('qwdtt без query string → null', () => { expect(parseWdttUrl('qwdtt://config')).toBeNull(); }); + + it('workers=abc → undefined', () => { + const link = parseWdttUrl('qwdtt://config?peer=1.2.3.4:5555&pass=secret&workers=abc'); + expect(link).not.toBeNull(); + expect(link!.workers).toBeUndefined(); + }); + + it('workers=-5 → undefined', () => { + const link = parseWdttUrl('qwdtt://config?peer=1.2.3.4:5555&pass=secret&workers=-5'); + expect(link).not.toBeNull(); + expect(link!.workers).toBeUndefined(); + }); + + it('workers=9999 → undefined', () => { + const link = parseWdttUrl('qwdtt://config?peer=1.2.3.4:5555&pass=secret&workers=9999'); + expect(link).not.toBeNull(); + expect(link!.workers).toBeUndefined(); + }); }); diff --git a/frontend/src/lib/utils/wdttLink.ts b/frontend/src/lib/utils/wdttLink.ts index 1c794040..d24906b5 100644 --- a/frontend/src/lib/utils/wdttLink.ts +++ b/frontend/src/lib/utils/wdttLink.ts @@ -42,11 +42,23 @@ function parseQwdttConfig(raw: string): WdttLink | null { if (!peer || !pass) return null; const hashes = hashesStr.split(',').map(h => h.trim()).filter(Boolean); - const workers = workersStr ? parseInt(workersStr, 10) : undefined; + const workers = parseWorkers(workersStr); return { name, host: peer, password: pass, hashes, workers, port }; } +// workers валиден только как целое число в диапазоне 9–108 (4 хеша × 27). +// Любой мусор (NaN, вне диапазона, нечисловой) → undefined, без clamp. +function parseWorkers(workersStr: string): number | undefined { + if (!workersStr) return undefined; + const trimmed = workersStr.trim(); + if (!/^-?\d+$/.test(trimmed)) return undefined; + const n = Number(trimmed); + if (!Number.isFinite(n) || !Number.isInteger(n)) return undefined; + if (n < 9 || n > 108) return undefined; + return n; +} + // Парсинг старого формата: wdtt://IP:DTLS:WG:PROXY:PASSWORD[:HASHES][#name] function parseLegacyWdtt(raw: string): WdttLink | null { const stripped = raw.replace(/^wdtt:\/\//, '');