fix(wireguard): исправить endpoint и поля клиентского шаблона

This commit is contained in:
Denozordec committed 2026-10-08 23:21:45 +07:00
1 parent 206255b856
commit c82e8fa12b
13 files changed
+128 -29

No files matched your search

+1
View File
@@ -967,6 +967,7 @@ function WireGuardPageContent({ selectedServerId, selectedInterfaceId, allInterf
<WgExportSheet <WgExportSheet
open={!!exportIface} open={!!exportIface}
iface={exportIface} iface={exportIface}
serverHost={displayServers.find(server => server.id === exportIface?.serverId)?.host}
initialTab={exportInitialTab} initialTab={exportInitialTab}
peerId={exportPeerId} peerId={exportPeerId}
onClose={() => { onClose={() => {
+4 -13
View File
@@ -6,6 +6,7 @@ import {
wgImportRequestSchema, wgImportRequestSchema,
wgPatchInterfaceSchema, wgPatchInterfaceSchema,
wgPatchPeerSchema, wgPatchPeerSchema,
resolveWgClientEndpoint,
type WgCreatePeerRequest, type WgCreatePeerRequest,
type WgIfaceDto, type WgIfaceDto,
} from "@mmapp/contracts/wireguard" } from "@mmapp/contracts/wireguard"
@@ -451,23 +452,13 @@ const wireguardRoutes: FastifyPluginAsyncZod = async (app) => {
if (!iface.publicKey) { if (!iface.publicKey) {
return reply.status(400).send({ error: "У интерфейса нет public-key" }) return reply.status(400).send({ error: "У интерфейса нет public-key" })
} }
const endpoint = const endpoint = resolveWgClientEndpoint(peer.clientEndpoint, server.host, iface.listenPort)
peer.clientEndpoint ||
(peer.endpoint
? peer.endpoint
: undefined)
const content = generatePeerClientConf({ const content = generatePeerClientConf({
peerAddress: peer.clientAddress, peerAddress: peer.clientAddress,
peerDns: peer.clientDns, peerDns: peer.clientDns,
serverPublicKey: iface.publicKey, serverPublicKey: iface.publicKey,
allowedIps: peer.allowedIps.length ? peer.allowedIps : ["0.0.0.0/0"], // Server allowed-address describes the remote peer, not the client's routes.
endpoint: endpoint,
endpoint ||
(peer.clientEndpoint
? peer.clientEndpoint.includes(":")
? peer.clientEndpoint
: `${peer.clientEndpoint}:${iface.listenPort}`
: undefined),
persistentKeepalive: peer.persistentKeepalive ?? 25, persistentKeepalive: peer.persistentKeepalive ?? 25,
}) })
return reply.send({ return reply.send({
+5 -2
View File
@@ -291,13 +291,16 @@ export function generatePeerClientConf(args: {
? `PrivateKey = ${args.peerPrivateKey}` ? `PrivateKey = ${args.peerPrivateKey}`
: `# PrivateKey = <ключ клиента>`, : `# PrivateKey = <ключ клиента>`,
) )
if (args.peerAddress) lines.push(`Address = ${args.peerAddress}`) if (args.peerAddress?.trim()) lines.push(`Address = ${args.peerAddress.trim()}`)
else lines.push(`# Address = <укажите адрес клиента>`)
if (args.peerDns) lines.push(`DNS = ${args.peerDns}`) if (args.peerDns) lines.push(`DNS = ${args.peerDns}`)
lines.push(``) lines.push(``)
lines.push(`[Peer]`) lines.push(`[Peer]`)
lines.push(`PublicKey = ${args.serverPublicKey}`) lines.push(`PublicKey = ${args.serverPublicKey}`)
lines.push(`AllowedIPs = ${(args.allowedIps?.length ? args.allowedIps : ["0.0.0.0/0"]).join(", ")}`) if (args.allowedIps?.length) lines.push(`AllowedIPs = ${args.allowedIps.join(", ")}`)
else lines.push(`# AllowedIPs = <укажите сети через туннель>`)
if (args.endpoint) lines.push(`Endpoint = ${args.endpoint}`) if (args.endpoint) lines.push(`Endpoint = ${args.endpoint}`)
else lines.push(`# Endpoint = <укажите адрес сервера и порт>`)
if (args.persistentKeepalive != null && args.persistentKeepalive > 0) { if (args.persistentKeepalive != null && args.persistentKeepalive > 0) {
lines.push(`PersistentKeepalive = ${args.persistentKeepalive}`) lines.push(`PersistentKeepalive = ${args.persistentKeepalive}`)
} }
+6 -3
View File
@@ -1,6 +1,7 @@
"use client" "use client"
import { useMemo } from "react" import { useMemo } from "react"
import { resolveWgClientEndpoint } from "@mmapp/contracts/wireguard"
import { selectWgExportPeer } from "@/lib/wg-export-peer" import { selectWgExportPeer } from "@/lib/wg-export-peer"
import type { WgIfaceWithServer } from "@/components/data-grids/wireguard-data-grid" import type { WgIfaceWithServer } from "@/components/data-grids/wireguard-data-grid"
import { import {
@@ -22,6 +23,7 @@ function WgExportSheet({
onRequestLiveExport, onRequestLiveExport,
initialTab = "rsc", initialTab = "rsc",
peerId, peerId,
serverHost,
}: { }: {
open: boolean open: boolean
iface: WgIfaceWithServer | null iface: WgIfaceWithServer | null
@@ -32,6 +34,7 @@ function WgExportSheet({
initialTab?: "rsc" | "conf" | "peer" initialTab?: "rsc" | "conf" | "peer"
/** Selected peer for Peer .conf (defaults to first peer) */ /** Selected peer for Peer .conf (defaults to first peer) */
peerId?: string | null peerId?: string | null
serverHost?: string
}) { }) {
const formats = useMemo((): CodeExportFormat[] => { const formats = useMemo((): CodeExportFormat[] => {
if (!iface) { if (!iface) {
@@ -90,8 +93,7 @@ function WgExportSheet({
peerAddress: peer.clientAddress, peerAddress: peer.clientAddress,
peerDns: peer.clientDns, peerDns: peer.clientDns,
serverPublicKey: iface.publicKey, serverPublicKey: iface.publicKey,
allowedIps: peer.allowedIps, endpoint: resolveWgClientEndpoint(peer.clientEndpoint, serverHost, iface.listenPort),
endpoint: peer.clientEndpoint || peer.endpoint || undefined,
persistentKeepalive: peer.persistentKeepalive ?? 25, persistentKeepalive: peer.persistentKeepalive ?? 25,
}) })
} }
@@ -120,7 +122,7 @@ function WgExportSheet({
isLive: Boolean(liveContent?.peerConf), isLive: Boolean(liveContent?.peerConf),
}, },
] ]
}, [iface, liveContent, peerId]) }, [iface, liveContent, peerId, serverHost])
return ( return (
<CodeExportSheet <CodeExportSheet
@@ -129,6 +131,7 @@ function WgExportSheet({
title="Экспорт WireGuard" title="Экспорт WireGuard"
description={iface ? `${iface.name} · ${iface.serverName}` : "—"} description={iface ? `${iface.name} · ${iface.serverName}` : "—"}
formats={formats} formats={formats}
beforeCode={<p className="text-xs text-muted-foreground">Peer .conf — шаблон для клиента. Заполните его приватный ключ, адрес и сети AllowedIPs. При NAT укажите доступный извне client-endpoint; endpoint удалённого пира здесь не используется.</p>}
initialFormatId={initialTab} initialFormatId={initialTab}
liveBusy={liveBusy} liveBusy={liveBusy}
liveLabel="С роутера" liveLabel="С роутера"
+12
View File
@@ -513,3 +513,15 @@ RSC/CONF совпали с native address/listenPort/MTU и выбранным p
UI live export не запускался: его текущий handler запрашивает includePrivateKey:true дляRSC/CONF. Этот блок доказывает API false redaction и выбранные параметры, не безопасность всех UI/export режимов. Native/API snapshot GET, plaintext memory сравнения и отсутствие чувствительных полей в публичном JSON проверены. Product source не менялся, общая регрессия не запускалась для внешней read-only проверки. UI live export не запускался: его текущий handler запрашивает includePrivateKey:true дляRSC/CONF. Этот блок доказывает API false redaction и выбранные параметры, не безопасность всех UI/export режимов. Native/API snapshot GET, plaintext memory сравнения и отсутствие чувствительных полей в публичном JSON проверены. Product source не менялся, общая регрессия не запускалась для внешней read-only проверки.
Финальный fixture cleanup exit0, selected WG/peers/IP/routes/IPv4 Firewall baseline совпал. Own peers/IP явно удалялись harness перед интерфейсом; полное обычное UI удаление уже отдельно подтверждено в60/62/64. Эфемерный контейнер удалён, остались три основные службы, backend healthy. [DB controls](ux-ui/acceptance/wg-export-db-controls-2026-10-08.json) до/после servers2/speedHistory9/retention14/migrations9 совпали, audit revisions намеренно сохранены. Runtime backend3722fad/frontendbf43263 не менялся. Настоящий import roundtrip, export private-key modes/UI download, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и остальные протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push. Финальный fixture cleanup exit0, selected WG/peers/IP/routes/IPv4 Firewall baseline совпал. Own peers/IP явно удалялись harness перед интерфейсом; полное обычное UI удаление уже отдельно подтверждено в60/62/64. Эфемерный контейнер удалён, остались три основные службы, backend healthy. [DB controls](ux-ui/acceptance/wg-export-db-controls-2026-10-08.json) до/после servers2/speedHistory9/retention14/migrations9 совпали, audit revisions намеренно сохранены. Runtime backend3722fad/frontendbf43263 не менялся. Настоящий import roundtrip, export private-key modes/UI download, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и остальные протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
## 12.5.66 — правильный client endpoint и явный шаблон Peer .conf (2026-10-08)
Ошибка65 исправлена локально в backend и preview. Общий resolveWgClientEndpoint в packages/contracts/src/wireguard.ts приоритетно использует явный client-endpoint, добавляет listenPort для hostname/IPv4 без порта и brackets для IPv6; иначе берёт host/listenPort экспортирующего устройства. Неизвестный host/неподходящий формат оставляют Endpoint placeholder. Backend export route больше не использует peer.endpoint; frontend WgExportSheet получает host выбранного устройства из текущего каталога серверов и использует тот же resolver.
Server allowed-address не обозначает клиентские маршруты: API/preview больше не передают его в Peer .conf. Оба codec generatePeerClientConf сохраняют явно переданные client параметры, но без client Address/AllowedIPs/Endpoint выводят комментарии-подсказки вместо активных выдуманных значений; default0.0.0.0/0 не создаётся. PrivateKey клиента остаётся placeholder. Существующие client-address/client-dns/client-endpoint overrides сохраняются. UI сообщает, что Peer .conf — шаблон: заполнить собственный ключ/адрес/сети и проверить endpoint заNAT. Политика поддерживаемых client routes не расширена новыми RouterOS полями; ready client config без этих данных не обещается.
Схема после исправления: экспорт интерфейсаA для клиентаB → PublicKey интерфейсаA + Endpoint устройстваA:listenPort; Address клиентаB и его AllowedIPs задаются явно. Backend/frontend изменения согласованы через общий contracts helper, Zod wire format и HTTP response shape не менялись. Общие ReUI primitives не менялись; beforeCode — существующий slot CodeExportSheet.
Проверки lib/wg-client-template.test.ts —5/5: endpoint exporting server/явный override/hostname/IPv6/неизвестные значения, одинаковые backend/frontend placeholders, отсутствие активного Address/AllowedIPs и default route без явных данных, сохранение явно заданных client параметров. Existing backend wireguard-config.test.ts passed; contracts build, backend TypeScript, scoped frontend TypeScript и ESLint всех изменённых файлов passed. Profile wireguard-links.spec.ts --grep экспорт —4/4: late response isolation/error, неправильный формат, выбор второго peer/ROS ID, его client-address/client-endpoint и отсутствие remote endpoint/server allowed-address в preview. Первый запуск старого теста ожидал ошибочно скопированные peer.allowedIps; fixture и assertions заменены на отличающиеся client metadata, защита выбора второго пира сохранена. ReUI checklist checked.
Исправление локальное: runtime backend3722fad/frontendbf43263 не менялся. Следующий12.5.67 — production Docker build/deploy backend и frontend с обновлённым contracts source, новая собственная WG пара, native/API export false redaction и правильный endpoint/шаблон, browser preview соответствие, cleanup/baseline. Поддержка client-allowed-address, настоящий client import/connectivity, import roundtrip/private-key modes, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и другие протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
+2 -2
View File
@@ -1,12 +1,12 @@
# План реализации UX/UI по пятичасовым окнам # План реализации UX/UI по пятичасовым окнам
Актуальное продолжение 2026-10-08: 12.5.65 проверил API export includePrivateKey=false на новой собственной WG паре: RSC/CONF/native поля совпали, все6 ответов200 без приватных ключей, конфиги/ключи не сохранены. Peer-conf содержит выбранный server key, но при отсутствии client metadata ошибочно использует endpoint удалённого пира; клиентский шаблон не принят как готовый. Own объекты удалены, selected baseline/DB controls совпали, backend healthy. Следующий12.5.66 — исправить client endpoint/defaults и явное состояние шаблона в API/preview, профильные тесты; import roundtrip после этого. Runtime backend3722fad/frontendbf43263. Этап12.5 открыт. Актуальное продолжение 2026-10-08: 12.5.66 локально исправил Peer .conf: общий resolver использует client-endpoint или host/listenPort экспортирующего сервера; remote peer endpoint и server allowed-address не подставляются как клиентские значения. Недостающие Address/AllowedIPs/Endpoint явно отмечены шаблоном, UI поясняет ручное заполнение. Unit5/5, codec, export UI4/4, contracts/backend/frontend TypeScript и ESLint passed. Runtime backend3722fad/frontendbf43263 ещё прежний. Следующий12.5.67 — Docker build/deploy обеих частей с обновлённым contracts, реальный API/preview Peer .conf на собственной WG паре с очисткой; import после этого. Этап12.5 открыт.
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-08. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-08. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
## Актуальная точка продолжения — 2026-10-08 ## Актуальная точка продолжения — 2026-10-08
Этапы0–11 завершены в описанных локальных границах. Этап12 открыт. На тестовом сервере161.104.46.222 работают backend3722fad/frontendbf43263 и два CHR. Внешние проверки подтвердили PG backup/restore/rollback, остановку фоновой работы для одного экземпляра, API JWT/RBAC и браузерные состояния восстановления. Native TCP/UDP speed, история и UI проверены в границах журнала; доступ ко второму CHR восстановлен пользователем. Очередь Telegram проверена на реальном PG: dedupe, конкурентный claim, retry/version, ошибки сохранения и неопределённый исход; ответы отправителя подменялись, реальной доставки это не доказывает. Блоки12.5.43–45 подтвердили browser retry/checkpoint и развернули понятное пояснение HTTP500. 12.5.46 подтвердил browser JWT/RBAC очереди на реальном HTTP/PG; 12.5.47 подтвердил изоляцию checkpoint при смене двух реальных HTTP/PG источников в конфигурации local; 12.5.48 подтвердил scoped axe/клавиатуру в обеих темах и320px; 12.5.49 собрал Q-матрицу и подтвердил отсутствие настройки Telegram; 12.5.50 подтвердил GET-only инвентаризацию: VPN/BGP/OSPF пусты, роли home-router/home-router; По уточнению пользователя12.5.51 создал реальные GRE туннели и подтвердил lifecycle/связность; обнаружена потеря peer IP, 12.5.52 локально исправил сохранение peer metadata, профильные проверки passed; 12.5.53 развернул исправление и подтвердил его на реальной GRE паре/API/UI; 12.5.54 локально исправил устойчивость меню GRE, профильные проверки passed; 12.5.55 развернул frontend731803b и подтвердил устойчивость меню на реальной GRE паре; 12.5.56 локально адаптировал внутренние IP поля GRE для320px, обе темы и профильные проверки passed; 12.5.57 развернул frontendfd521f6 и подтвердил мобильную GRE форму на реальной паре CHR; 12.5.58 подтвердил настоящую WireGuard пару, handshake/Ping/native/UI и финальную очистку; 12.5.59 подтвердил оставшиеся peers/IP после удаления WG и локально исправил backend; 12.5.60 развернул backend/frontend3722fad и подтвердил полное обычное удаление WG; 12.5.61 подтвердил UI создание WG и локально исправил remount меню; переключение осталось открытым. 12.5.62 развернул frontend6a46fb1 и подтвердил полный WG UI lifecycle; 12.5.63 локально адаптировал ширину трёх WireGuard Sheets и подтвердил footer/клавиатуру в обеих темах; 12.5.64 развернул frontendbf43263 и подтвердил live mobile Sheets/UI lifecycle; 12.5.65 подтвердил API export false redaction/RSC-CONF параметры и нашёл ошибочный client endpoint вpeer-conf; следующий12.5.66 — исправить client template defaults/API/preview, import roundtrip после этого. Реальная Telegram доставка, Portal SSO, физический TCP disconnect, multi-instance и остальные профильные сетевые сценарии остаются открытыми. [Протокол](ux-ui-external-acceptance.md) и [журнал](ux-ui-stage-12.md) содержат доказательства и ограничения. Этапы0–11 завершены в описанных локальных границах. Этап12 открыт. На тестовом сервере161.104.46.222 работают backend3722fad/frontendbf43263 и два CHR. Внешние проверки подтвердили PG backup/restore/rollback, остановку фоновой работы для одного экземпляра, API JWT/RBAC и браузерные состояния восстановления. Native TCP/UDP speed, история и UI проверены в границах журнала; доступ ко второму CHR восстановлен пользователем. Очередь Telegram проверена на реальном PG: dedupe, конкурентный claim, retry/version, ошибки сохранения и неопределённый исход; ответы отправителя подменялись, реальной доставки это не доказывает. Блоки12.5.43–45 подтвердили browser retry/checkpoint и развернули понятное пояснение HTTP500. 12.5.46 подтвердил browser JWT/RBAC очереди на реальном HTTP/PG; 12.5.47 подтвердил изоляцию checkpoint при смене двух реальных HTTP/PG источников в конфигурации local; 12.5.48 подтвердил scoped axe/клавиатуру в обеих темах и320px; 12.5.49 собрал Q-матрицу и подтвердил отсутствие настройки Telegram; 12.5.50 подтвердил GET-only инвентаризацию: VPN/BGP/OSPF пусты, роли home-router/home-router; По уточнению пользователя12.5.51 создал реальные GRE туннели и подтвердил lifecycle/связность; обнаружена потеря peer IP, 12.5.52 локально исправил сохранение peer metadata, профильные проверки passed; 12.5.53 развернул исправление и подтвердил его на реальной GRE паре/API/UI; 12.5.54 локально исправил устойчивость меню GRE, профильные проверки passed; 12.5.55 развернул frontend731803b и подтвердил устойчивость меню на реальной GRE паре; 12.5.56 локально адаптировал внутренние IP поля GRE для320px, обе темы и профильные проверки passed; 12.5.57 развернул frontendfd521f6 и подтвердил мобильную GRE форму на реальной паре CHR; 12.5.58 подтвердил настоящую WireGuard пару, handshake/Ping/native/UI и финальную очистку; 12.5.59 подтвердил оставшиеся peers/IP после удаления WG и локально исправил backend; 12.5.60 развернул backend/frontend3722fad и подтвердил полное обычное удаление WG; 12.5.61 подтвердил UI создание WG и локально исправил remount меню; переключение осталось открытым. 12.5.62 развернул frontend6a46fb1 и подтвердил полный WG UI lifecycle; 12.5.63 локально адаптировал ширину трёх WireGuard Sheets и подтвердил footer/клавиатуру в обеих темах; 12.5.64 развернул frontendbf43263 и подтвердил live mobile Sheets/UI lifecycle; 12.5.65 подтвердил API export false redaction/RSC-CONF параметры и нашёл ошибочный client endpoint вpeer-conf; 12.5.66 локально исправил client endpoint и явные template placeholders; следующий12.5.67 — Docker deploy обеих частей/contracts и повторный реальный Peer .conf export/preview; import после этого. Реальная Telegram доставка, Portal SSO, физический TCP disconnect, multi-instance и остальные профильные сетевые сценарии остаются открытыми. [Протокол](ux-ui-external-acceptance.md) и [журнал](ux-ui-stage-12.md) содержат доказательства и ограничения.
Выполненные внешние сценарии не заменяют приёмку оставшихся интеграций и условий эксплуатации. Датированные продолжения ниже — история; точный следующий шаг указан в начале [журнала](ux-ui-progress.md). Выполненные внешние сценарии не заменяют приёмку оставшихся интеграций и условий эксплуатации. Датированные продолжения ниже — история; точный следующий шаг указан в начале [журнала](ux-ui-progress.md).
+14 -2
View File
@@ -1,6 +1,6 @@
# UX/UI: журнал реализации # UX/UI: журнал реализации
Актуальное продолжение 2026-10-08: 12.5.65 проверил API export includePrivateKey=false на новой собственной WG паре: RSC/CONF/native поля совпали, все6 ответов200 без приватных ключей, конфиги/ключи не сохранены. Peer-conf содержит выбранный server key, но при отсутствии client metadata ошибочно использует endpoint удалённого пира; клиентский шаблон не принят как готовый. Own объекты удалены, selected baseline/DB controls совпали, backend healthy. Следующий12.5.66 — исправить client endpoint/defaults и явное состояние шаблона в API/preview, профильные тесты; import roundtrip после этого. Runtime backend3722fad/frontendbf43263. Этап12.5 открыт. Актуальное продолжение 2026-10-08: 12.5.66 локально исправил Peer .conf: общий resolver использует client-endpoint или host/listenPort экспортирующего сервера; remote peer endpoint и server allowed-address не подставляются как клиентские значения. Недостающие Address/AllowedIPs/Endpoint явно отмечены шаблоном, UI поясняет ручное заполнение. Unit5/5, codec, export UI4/4, contracts/backend/frontend TypeScript и ESLint passed. Runtime backend3722fad/frontendbf43263 ещё прежний. Следующий12.5.67 — Docker build/deploy обеих частей с обновлённым contracts, реальный API/preview Peer .conf на собственной WG паре с очисткой; import после этого. Этап12.5 открыт.
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
@@ -34,7 +34,19 @@
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 | | 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 | | 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–65 и ограничения ниже. Runtime backend3722fad/frontendbf43263. | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–66 и ограничения ниже. Runtime backend3722fad/frontendbf43263. |
## 12.5.66 — правильный client endpoint и явный шаблон Peer .conf (2026-10-08)
Ошибка65 исправлена локально в backend и preview. Общий resolveWgClientEndpoint в packages/contracts/src/wireguard.ts приоритетно использует явный client-endpoint, добавляет listenPort для hostname/IPv4 без порта и brackets для IPv6; иначе берёт host/listenPort экспортирующего устройства. Неизвестный host/неподходящий формат оставляют Endpoint placeholder. Backend export route больше не использует peer.endpoint; frontend WgExportSheet получает host выбранного устройства из текущего каталога серверов и использует тот же resolver.
Server allowed-address не обозначает клиентские маршруты: API/preview больше не передают его в Peer .conf. Оба codec generatePeerClientConf сохраняют явно переданные client параметры, но без client Address/AllowedIPs/Endpoint выводят комментарии-подсказки вместо активных выдуманных значений; default0.0.0.0/0 не создаётся. PrivateKey клиента остаётся placeholder. Существующие client-address/client-dns/client-endpoint overrides сохраняются. UI сообщает, что Peer .conf — шаблон: заполнить собственный ключ/адрес/сети и проверить endpoint заNAT. Политика поддерживаемых client routes не расширена новыми RouterOS полями; ready client config без этих данных не обещается.
Схема после исправления: экспорт интерфейсаA для клиентаB → PublicKey интерфейсаA + Endpoint устройстваA:listenPort; Address клиентаB и его AllowedIPs задаются явно. Backend/frontend изменения согласованы через общий contracts helper, Zod wire format и HTTP response shape не менялись. Общие ReUI primitives не менялись; beforeCode — существующий slot CodeExportSheet.
Проверки lib/wg-client-template.test.ts —5/5: endpoint exporting server/явный override/hostname/IPv6/неизвестные значения, одинаковые backend/frontend placeholders, отсутствие активного Address/AllowedIPs и default route без явных данных, сохранение явно заданных client параметров. Existing backend wireguard-config.test.ts passed; contracts build, backend TypeScript, scoped frontend TypeScript и ESLint всех изменённых файлов passed. Profile wireguard-links.spec.ts --grep экспорт —4/4: late response isolation/error, неправильный формат, выбор второго peer/ROS ID, его client-address/client-endpoint и отсутствие remote endpoint/server allowed-address в preview. Первый запуск старого теста ожидал ошибочно скопированные peer.allowedIps; fixture и assertions заменены на отличающиеся client metadata, защита выбора второго пира сохранена. ReUI checklist checked.
Исправление локальное: runtime backend3722fad/frontendbf43263 не менялся. Следующий12.5.67 — production Docker build/deploy backend и frontend с обновлённым contracts source, новая собственная WG пара, native/API export false redaction и правильный endpoint/шаблон, browser preview соответствие, cleanup/baseline. Поддержка client-allowed-address, настоящий client import/connectivity, import roundtrip/private-key modes, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и другие протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
## 12.5.65 — экспорт WireGuard без приватных ключей и ошибка client endpoint (2026-10-08) ## 12.5.65 — экспорт WireGuard без приватных ключей и ошибка client endpoint (2026-10-08)
+13 -1
View File
@@ -1,6 +1,6 @@
# Этап 12: итоговая приёмка UX/UI # Этап 12: итоговая приёмка UX/UI
Актуальное продолжение 2026-10-08: 12.5.65 проверил API export includePrivateKey=false на новой собственной WG паре: RSC/CONF/native поля совпали, все6 ответов200 без приватных ключей, конфиги/ключи не сохранены. Peer-conf содержит выбранный server key, но при отсутствии client metadata ошибочно использует endpoint удалённого пира; клиентский шаблон не принят как готовый. Own объекты удалены, selected baseline/DB controls совпали, backend healthy. Следующий12.5.66 — исправить client endpoint/defaults и явное состояние шаблона в API/preview, профильные тесты; import roundtrip после этого. Runtime backend3722fad/frontendbf43263. Этап12.5 открыт. Актуальное продолжение 2026-10-08: 12.5.66 локально исправил Peer .conf: общий resolver использует client-endpoint или host/listenPort экспортирующего сервера; remote peer endpoint и server allowed-address не подставляются как клиентские значения. Недостающие Address/AllowedIPs/Endpoint явно отмечены шаблоном, UI поясняет ручное заполнение. Unit5/5, codec, export UI4/4, contracts/backend/frontend TypeScript и ESLint passed. Runtime backend3722fad/frontendbf43263 ещё прежний. Следующий12.5.67 — Docker build/deploy обеих частей с обновлённым contracts, реальный API/preview Peer .conf на собственной WG паре с очисткой; import после этого. Этап12.5 открыт.
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
@@ -1678,3 +1678,15 @@ RSC/CONF совпали с native address/listenPort/MTU и выбранным p
UI live export не запускался: его текущий handler запрашивает includePrivateKey:true дляRSC/CONF. Этот блок доказывает API false redaction и выбранные параметры, не безопасность всех UI/export режимов. Native/API snapshot GET, plaintext memory сравнения и отсутствие чувствительных полей в публичном JSON проверены. Product source не менялся, общая регрессия не запускалась для внешней read-only проверки. UI live export не запускался: его текущий handler запрашивает includePrivateKey:true дляRSC/CONF. Этот блок доказывает API false redaction и выбранные параметры, не безопасность всех UI/export режимов. Native/API snapshot GET, plaintext memory сравнения и отсутствие чувствительных полей в публичном JSON проверены. Product source не менялся, общая регрессия не запускалась для внешней read-only проверки.
Финальный fixture cleanup exit0, selected WG/peers/IP/routes/IPv4 Firewall baseline совпал. Own peers/IP явно удалялись harness перед интерфейсом; полное обычное UI удаление уже отдельно подтверждено в60/62/64. Эфемерный контейнер удалён, остались три основные службы, backend healthy. [DB controls](ux-ui/acceptance/wg-export-db-controls-2026-10-08.json) до/после servers2/speedHistory9/retention14/migrations9 совпали, audit revisions намеренно сохранены. Runtime backend3722fad/frontendbf43263 не менялся. Настоящий import roundtrip, export private-key modes/UI download, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и остальные протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push. Финальный fixture cleanup exit0, selected WG/peers/IP/routes/IPv4 Firewall baseline совпал. Own peers/IP явно удалялись harness перед интерфейсом; полное обычное UI удаление уже отдельно подтверждено в60/62/64. Эфемерный контейнер удалён, остались три основные службы, backend healthy. [DB controls](ux-ui/acceptance/wg-export-db-controls-2026-10-08.json) до/после servers2/speedHistory9/retention14/migrations9 совпали, audit revisions намеренно сохранены. Runtime backend3722fad/frontendbf43263 не менялся. Настоящий import roundtrip, export private-key modes/UI download, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и остальные протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
## 12.5.66 — правильный client endpoint и явный шаблон Peer .conf (2026-10-08)
Ошибка65 исправлена локально в backend и preview. Общий resolveWgClientEndpoint в packages/contracts/src/wireguard.ts приоритетно использует явный client-endpoint, добавляет listenPort для hostname/IPv4 без порта и brackets для IPv6; иначе берёт host/listenPort экспортирующего устройства. Неизвестный host/неподходящий формат оставляют Endpoint placeholder. Backend export route больше не использует peer.endpoint; frontend WgExportSheet получает host выбранного устройства из текущего каталога серверов и использует тот же resolver.
Server allowed-address не обозначает клиентские маршруты: API/preview больше не передают его в Peer .conf. Оба codec generatePeerClientConf сохраняют явно переданные client параметры, но без client Address/AllowedIPs/Endpoint выводят комментарии-подсказки вместо активных выдуманных значений; default0.0.0.0/0 не создаётся. PrivateKey клиента остаётся placeholder. Существующие client-address/client-dns/client-endpoint overrides сохраняются. UI сообщает, что Peer .conf — шаблон: заполнить собственный ключ/адрес/сети и проверить endpoint заNAT. Политика поддерживаемых client routes не расширена новыми RouterOS полями; ready client config без этих данных не обещается.
Схема после исправления: экспорт интерфейсаA для клиентаB → PublicKey интерфейсаA + Endpoint устройстваA:listenPort; Address клиентаB и его AllowedIPs задаются явно. Backend/frontend изменения согласованы через общий contracts helper, Zod wire format и HTTP response shape не менялись. Общие ReUI primitives не менялись; beforeCode — существующий slot CodeExportSheet.
Проверки lib/wg-client-template.test.ts —5/5: endpoint exporting server/явный override/hostname/IPv6/неизвестные значения, одинаковые backend/frontend placeholders, отсутствие активного Address/AllowedIPs и default route без явных данных, сохранение явно заданных client параметров. Existing backend wireguard-config.test.ts passed; contracts build, backend TypeScript, scoped frontend TypeScript и ESLint всех изменённых файлов passed. Profile wireguard-links.spec.ts --grep экспорт —4/4: late response isolation/error, неправильный формат, выбор второго peer/ROS ID, его client-address/client-endpoint и отсутствие remote endpoint/server allowed-address в preview. Первый запуск старого теста ожидал ошибочно скопированные peer.allowedIps; fixture и assertions заменены на отличающиеся client metadata, защита выбора второго пира сохранена. ReUI checklist checked.
Исправление локальное: runtime backend3722fad/frontendbf43263 не менялся. Следующий12.5.67 — production Docker build/deploy backend и frontend с обновлённым contracts source, новая собственная WG пара, native/API export false redaction и правильный endpoint/шаблон, browser preview соответствие, cleanup/baseline. Поддержка client-allowed-address, настоящий client import/connectivity, import roundtrip/private-key modes, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и другие протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
+12
View File
@@ -521,3 +521,15 @@ RSC/CONF совпали с native address/listenPort/MTU и выбранным p
UI live export не запускался: его текущий handler запрашивает includePrivateKey:true дляRSC/CONF. Этот блок доказывает API false redaction и выбранные параметры, не безопасность всех UI/export режимов. Native/API snapshot GET, plaintext memory сравнения и отсутствие чувствительных полей в публичном JSON проверены. Product source не менялся, общая регрессия не запускалась для внешней read-only проверки. UI live export не запускался: его текущий handler запрашивает includePrivateKey:true дляRSC/CONF. Этот блок доказывает API false redaction и выбранные параметры, не безопасность всех UI/export режимов. Native/API snapshot GET, plaintext memory сравнения и отсутствие чувствительных полей в публичном JSON проверены. Product source не менялся, общая регрессия не запускалась для внешней read-only проверки.
Финальный fixture cleanup exit0, selected WG/peers/IP/routes/IPv4 Firewall baseline совпал. Own peers/IP явно удалялись harness перед интерфейсом; полное обычное UI удаление уже отдельно подтверждено в60/62/64. Эфемерный контейнер удалён, остались три основные службы, backend healthy. [DB controls](ux-ui/acceptance/wg-export-db-controls-2026-10-08.json) до/после servers2/speedHistory9/retention14/migrations9 совпали, audit revisions намеренно сохранены. Runtime backend3722fad/frontendbf43263 не менялся. Настоящий import roundtrip, export private-key modes/UI download, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и остальные протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push. Финальный fixture cleanup exit0, selected WG/peers/IP/routes/IPv4 Firewall baseline совпал. Own peers/IP явно удалялись harness перед интерфейсом; полное обычное UI удаление уже отдельно подтверждено в60/62/64. Эфемерный контейнер удалён, остались три основные службы, backend healthy. [DB controls](ux-ui/acceptance/wg-export-db-controls-2026-10-08.json) до/после servers2/speedHistory9/retention14/migrations9 совпали, audit revisions намеренно сохранены. Runtime backend3722fad/frontendbf43263 не менялся. Настоящий import roundtrip, export private-key modes/UI download, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и остальные протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
## 12.5.66 — правильный client endpoint и явный шаблон Peer .conf (2026-10-08)
Ошибка65 исправлена локально в backend и preview. Общий resolveWgClientEndpoint в packages/contracts/src/wireguard.ts приоритетно использует явный client-endpoint, добавляет listenPort для hostname/IPv4 без порта и brackets для IPv6; иначе берёт host/listenPort экспортирующего устройства. Неизвестный host/неподходящий формат оставляют Endpoint placeholder. Backend export route больше не использует peer.endpoint; frontend WgExportSheet получает host выбранного устройства из текущего каталога серверов и использует тот же resolver.
Server allowed-address не обозначает клиентские маршруты: API/preview больше не передают его в Peer .conf. Оба codec generatePeerClientConf сохраняют явно переданные client параметры, но без client Address/AllowedIPs/Endpoint выводят комментарии-подсказки вместо активных выдуманных значений; default0.0.0.0/0 не создаётся. PrivateKey клиента остаётся placeholder. Существующие client-address/client-dns/client-endpoint overrides сохраняются. UI сообщает, что Peer .conf — шаблон: заполнить собственный ключ/адрес/сети и проверить endpoint заNAT. Политика поддерживаемых client routes не расширена новыми RouterOS полями; ready client config без этих данных не обещается.
Схема после исправления: экспорт интерфейсаA для клиентаB → PublicKey интерфейсаA + Endpoint устройстваA:listenPort; Address клиентаB и его AllowedIPs задаются явно. Backend/frontend изменения согласованы через общий contracts helper, Zod wire format и HTTP response shape не менялись. Общие ReUI primitives не менялись; beforeCode — существующий slot CodeExportSheet.
Проверки lib/wg-client-template.test.ts —5/5: endpoint exporting server/явный override/hostname/IPv6/неизвестные значения, одинаковые backend/frontend placeholders, отсутствие активного Address/AllowedIPs и default route без явных данных, сохранение явно заданных client параметров. Existing backend wireguard-config.test.ts passed; contracts build, backend TypeScript, scoped frontend TypeScript и ESLint всех изменённых файлов passed. Profile wireguard-links.spec.ts --grep экспорт —4/4: late response isolation/error, неправильный формат, выбор второго peer/ROS ID, его client-address/client-endpoint и отсутствие remote endpoint/server allowed-address в preview. Первый запуск старого теста ожидал ошибочно скопированные peer.allowedIps; fixture и assertions заменены на отличающиеся client metadata, защита выбора второго пира сохранена. ReUI checklist checked.
Исправление локальное: runtime backend3722fad/frontendbf43263 не менялся. Следующий12.5.67 — production Docker build/deploy backend и frontend с обновлённым contracts source, новая собственная WG пара, native/API export false redaction и правильный endpoint/шаблон, browser preview соответствие, cleanup/baseline. Поддержка client-allowed-address, настоящий client import/connectivity, import roundtrip/private-key modes, throughput/IPv6/RBAC/внешние failures/multi-instance/Telegram/Portal и другие протоколы/интеграции остаются открытыми. Пользовательское правило настоящих VPN объектов сохраняется. Локальный коммит без push.
+34
View File
@@ -0,0 +1,34 @@
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { resolveWgClientEndpoint } from '../packages/contracts/src/wireguard'
import { generatePeerClientConf as client } from './wg-config'
import { generatePeerClientConf as backend } from '../backend/src/services/wireguard-config'
test('client endpoint uses exporting server or explicit client metadata', () => {
assert.equal(resolveWgClientEndpoint(undefined, '192.0.2.1', 51879), '192.0.2.1:51879')
assert.equal(resolveWgClientEndpoint('vpn.example:443', '192.0.2.1', 51879), 'vpn.example:443')
assert.equal(resolveWgClientEndpoint('vpn.example', '192.0.2.1', 51879), 'vpn.example:51879')
assert.equal(resolveWgClientEndpoint(undefined, '2001:db8::1', 51879), '[2001:db8::1]:51879')
assert.equal(resolveWgClientEndpoint('[2001:db8::2]:443', '192.0.2.1', 51879), '[2001:db8::2]:443')
assert.equal(resolveWgClientEndpoint(undefined, undefined, 51879), undefined)
assert.equal(resolveWgClientEndpoint('vpn.example:0', '192.0.2.1', 51879), undefined)
assert.equal(resolveWgClientEndpoint('https://vpn.example', '192.0.2.1', 51879), undefined)
})
for (const [name, generate] of [['frontend', client], ['backend', backend]] as const) {
test(`${name}: incomplete client data stays a template without invented routes`, () => {
const code = generate({ serverPublicKey: 'fixture-server-key', endpoint: resolveWgClientEndpoint(undefined, '192.0.2.1', 51879) })
assert(code.includes('Endpoint = 192.0.2.1:51879'))
assert(code.includes('# Address = <'))
assert(code.includes('# AllowedIPs = <'))
assert(code.includes('# PrivateKey = <'))
assert(!/^AllowedIPs =|^Address =|^PrivateKey =/m.test(code))
assert(!code.includes('0.0.0.0/0'))
})
test(`${name}: explicit client parameters remain unchanged`, () => {
const code = generate({ serverPublicKey: 'fixture-server-key', peerAddress: '198.18.255.242/30', peerDns: '192.0.2.53', allowedIps: ['198.18.255.240/30'], endpoint: 'vpn.example:443', persistentKeepalive: 5 })
assert(code.includes('Address = 198.18.255.242/30'))
assert(code.includes('AllowedIPs = 198.18.255.240/30'))
assert(code.includes('DNS = 192.0.2.53'))
assert(code.includes('Endpoint = vpn.example:443'))
})
}
+5 -2
View File
@@ -324,13 +324,16 @@ export function generatePeerClientConf(args: {
const lines: string[] = [] const lines: string[] = []
lines.push(`[Interface]`) lines.push(`[Interface]`)
lines.push(`# PrivateKey = <ключ клиента>`) lines.push(`# PrivateKey = <ключ клиента>`)
if (args.peerAddress) lines.push(`Address = ${args.peerAddress}`) if (args.peerAddress?.trim()) lines.push(`Address = ${args.peerAddress.trim()}`)
else lines.push(`# Address = <укажите адрес клиента>`)
if (args.peerDns) lines.push(`DNS = ${args.peerDns}`) if (args.peerDns) lines.push(`DNS = ${args.peerDns}`)
lines.push(``) lines.push(``)
lines.push(`[Peer]`) lines.push(`[Peer]`)
lines.push(`PublicKey = ${args.serverPublicKey}`) lines.push(`PublicKey = ${args.serverPublicKey}`)
lines.push(`AllowedIPs = ${(args.allowedIps?.length ? args.allowedIps : ["0.0.0.0/0"]).join(", ")}`) if (args.allowedIps?.length) lines.push(`AllowedIPs = ${args.allowedIps.join(", ")}`)
else lines.push(`# AllowedIPs = <укажите сети через туннель>`)
if (args.endpoint) lines.push(`Endpoint = ${args.endpoint}`) if (args.endpoint) lines.push(`Endpoint = ${args.endpoint}`)
else lines.push(`# Endpoint = <укажите адрес сервера и порт>`)
if (args.persistentKeepalive != null && args.persistentKeepalive > 0) { if (args.persistentKeepalive != null && args.persistentKeepalive > 0) {
lines.push(`PersistentKeepalive = ${args.persistentKeepalive}`) lines.push(`PersistentKeepalive = ${args.persistentKeepalive}`)
} }
+11
View File
@@ -1,5 +1,16 @@
import { z } from "zod" import { z } from "zod"
/** The client's remote endpoint belongs to the exporting interface, not its peer. */
export function resolveWgClientEndpoint(clientEndpoint: string | undefined, serverHost: string | undefined, listenPort: number): string | undefined {
const value = clientEndpoint?.trim() || serverHost?.trim()
if (!value || /[\s/]/.test(value) || !Number.isInteger(listenPort) || listenPort < 1 || listenPort > 65535) return undefined
const explicit = value.match(/^(\[[^\]]+\]|[^:]+):(\d+)$/)
if (explicit) return Number(explicit[2]) >= 1 && Number(explicit[2]) <= 65535 ? value : undefined
if (value.startsWith("[")) return value.endsWith("]") ? `${value}:${listenPort}` : undefined
if (value.includes(":")) return value.split(":").length > 2 && /^[\da-f:]+$/i.test(value) ? `[${value}]:${listenPort}` : undefined
return `${value}:${listenPort}`
}
export const wgStatusSchema = z.enum(["up", "down"]) export const wgStatusSchema = z.enum(["up", "down"])
export const wgPeerDtoSchema = z.object({ export const wgPeerDtoSchema = z.object({
+9 -4
View File
@@ -419,8 +419,8 @@ test("WireGuard: экспорт отклоняет повреждённый от
test("WireGuard: экспорт второго пира использует его RouterOS ID", async ({ page }) => { test("WireGuard: экспорт второго пира использует его RouterOS ID", async ({ page }) => {
await setup(page, "/wireguard?server=1") await setup(page, "/wireguard?server=1")
const fixture = wgListResponseSchema.parse({ interfaces: [{ id: "iface", rosId: "*I", serverId: "1", serverName: "Источник", name: "wg-peers", publicKey: "fixture-server-key", listenPort: 13231, mtu: 1420, enabled: true, status: "up", comment: "", peers: [ const fixture = wgListResponseSchema.parse({ interfaces: [{ id: "iface", rosId: "*I", serverId: "1", serverName: "Источник", name: "wg-peers", publicKey: "fixture-server-key", listenPort: 13231, mtu: 1420, enabled: true, status: "up", comment: "", peers: [
{ id: "first", rosId: "*P1", publicKey: "fixture-peer-one", allowedIps: ["10.0.1.1/32"] }, { id: "first", rosId: "*P1", publicKey: "fixture-peer-one", allowedIps: ["10.0.1.1/32"], clientAddress: "10.0.1.9/32" },
{ id: "second", rosId: "*P2", publicKey: "fixture-peer-two", allowedIps: ["10.0.2.1/32"] }, { id: "second", rosId: "*P2", publicKey: "fixture-peer-two", allowedIps: ["10.0.2.1/32"], clientAddress: "10.0.2.9/32", clientEndpoint: "vpn-second.example:51879", endpoint: "remote-peer.example:1111" },
] }] }) ] }] })
await page.route("**/api/wireguard", route => route.fulfill({ json: fixture })) await page.route("**/api/wireguard", route => route.fulfill({ json: fixture }))
let body: Record<string, unknown> | undefined let body: Record<string, unknown> | undefined
@@ -433,8 +433,13 @@ test("WireGuard: экспорт второго пира использует е
await expect(page.locator("tr[data-row-id]")).toHaveCount(2) await expect(page.locator("tr[data-row-id]")).toHaveCount(2)
await page.locator("tr[data-row-id]").filter({ hasText: "10.0.2.1/32" }).getByRole("button", { name: "Экспорт peer .conf" }).click() await page.locator("tr[data-row-id]").filter({ hasText: "10.0.2.1/32" }).getByRole("button", { name: "Экспорт peer .conf" }).click()
const dialog = page.getByRole("dialog", { name: "Экспорт WireGuard" }) const dialog = page.getByRole("dialog", { name: "Экспорт WireGuard" })
await expect(dialog.locator("pre")).toContainText("10.0.2.1/32") await expect(dialog.locator("pre")).toContainText("Address = 10.0.2.9/32")
await expect(dialog.locator("pre")).not.toContainText("10.0.1.1/32") await expect(dialog.locator("pre")).toContainText("Endpoint = vpn-second.example:51879")
await expect(dialog.locator("pre")).toContainText("# AllowedIPs = <")
await expect(dialog.locator("pre")).not.toContainText("remote-peer.example")
await expect(dialog).toContainText("шаблон для клиента")
await expect(dialog.locator("pre")).not.toContainText("10.0.1.9/32")
await expect(dialog.locator("pre")).not.toContainText("10.0.2.1/32")
await dialog.getByRole("button", { name: "Подтянуть конфиг с роутера с private-key" }).click() await dialog.getByRole("button", { name: "Подтянуть конфиг с роутера с private-key" }).click()
await expect(dialog.locator("pre")).toContainText("SECOND_PEER_EXPORT") await expect(dialog.locator("pre")).toContainText("SECOND_PEER_EXPORT")
expect(body).toMatchObject({ serverId: "1", interfaceName: "wg-peers", peerId: "*P2", format: "peer-conf", includePrivateKey: false }) expect(body).toMatchObject({ serverId: "1", interfaceName: "wg-peers", peerId: "*P2", format: "peer-conf", includePrivateKey: false })