From 4d2866e2cd9a39c248471ad68eeaee37dbabb9f4 Mon Sep 17 00:00:00 2001 From: Runya Date: Sun, 20 Sep 2026 19:42:58 +0300 Subject: [PATCH 1/3] 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/3] 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:\/\//, ''); From da33ecec9d571887039ea3f5a7c9e217826b7f7f Mon Sep 17 00:00:00 2001 From: Runya Date: Sun, 20 Sep 2026 20:41:33 +0300 Subject: [PATCH 3/3] ui: add WARN and DEBUG to log filter buttons --- frontend/src/pages/Logs.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Logs.tsx b/frontend/src/pages/Logs.tsx index 4d954a18..d96cc7fc 100644 --- a/frontend/src/pages/Logs.tsx +++ b/frontend/src/pages/Logs.tsx @@ -3,7 +3,7 @@ import { IconSearch, IconTrashX, IconCopy, IconCheck } from '@tabler/icons-react import { logStore, type LogEntry, type LogLevel } from '../lib/stores/logStore'; import './Logs.css'; -type Filter = 'ALL' | 'INFO' | 'ERROR'; +type Filter = 'ALL' | 'INFO' | 'WARN' | 'ERROR' | 'DEBUG'; const LEVEL_COLOR: Record = { INFO: 'var(--text)', @@ -62,7 +62,7 @@ export default function Logs() {
setSearch(e.target.value)} /> @@ -71,7 +71,7 @@ export default function Logs() {
- {(['ALL', 'INFO', 'ERROR'] as Filter[]).map(f => ( + {(['ALL', 'INFO', 'WARN', 'ERROR', 'DEBUG'] as Filter[]).map(f => ( ))}