fix(wireguard): исправить endpoint и поля клиентского шаблона
This commit is contained in:
1 parent
206255b856
commit
c82e8fa12b
13 files changed
+128
-29
No files matched your search
@@ -967,6 +967,7 @@ function WireGuardPageContent({ selectedServerId, selectedInterfaceId, allInterf
|
||||
<WgExportSheet
|
||||
open={!!exportIface}
|
||||
iface={exportIface}
|
||||
serverHost={displayServers.find(server => server.id === exportIface?.serverId)?.host}
|
||||
initialTab={exportInitialTab}
|
||||
peerId={exportPeerId}
|
||||
onClose={() => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
wgImportRequestSchema,
|
||||
wgPatchInterfaceSchema,
|
||||
wgPatchPeerSchema,
|
||||
resolveWgClientEndpoint,
|
||||
type WgCreatePeerRequest,
|
||||
type WgIfaceDto,
|
||||
} from "@mmapp/contracts/wireguard"
|
||||
@@ -451,23 +452,13 @@ const wireguardRoutes: FastifyPluginAsyncZod = async (app) => {
|
||||
if (!iface.publicKey) {
|
||||
return reply.status(400).send({ error: "У интерфейса нет public-key" })
|
||||
}
|
||||
const endpoint =
|
||||
peer.clientEndpoint ||
|
||||
(peer.endpoint
|
||||
? peer.endpoint
|
||||
: undefined)
|
||||
const endpoint = resolveWgClientEndpoint(peer.clientEndpoint, server.host, iface.listenPort)
|
||||
const content = generatePeerClientConf({
|
||||
peerAddress: peer.clientAddress,
|
||||
peerDns: peer.clientDns,
|
||||
serverPublicKey: iface.publicKey,
|
||||
allowedIps: peer.allowedIps.length ? peer.allowedIps : ["0.0.0.0/0"],
|
||||
endpoint:
|
||||
endpoint ||
|
||||
(peer.clientEndpoint
|
||||
? peer.clientEndpoint.includes(":")
|
||||
? peer.clientEndpoint
|
||||
: `${peer.clientEndpoint}:${iface.listenPort}`
|
||||
: undefined),
|
||||
// Server allowed-address describes the remote peer, not the client's routes.
|
||||
endpoint,
|
||||
persistentKeepalive: peer.persistentKeepalive ?? 25,
|
||||
})
|
||||
return reply.send({
|
||||
|
||||
@@ -291,13 +291,16 @@ export function generatePeerClientConf(args: {
|
||||
? `PrivateKey = ${args.peerPrivateKey}`
|
||||
: `# 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}`)
|
||||
lines.push(``)
|
||||
lines.push(`[Peer]`)
|
||||
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}`)
|
||||
else lines.push(`# Endpoint = <укажите адрес сервера и порт>`)
|
||||
if (args.persistentKeepalive != null && args.persistentKeepalive > 0) {
|
||||
lines.push(`PersistentKeepalive = ${args.persistentKeepalive}`)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import { useMemo } from "react"
|
||||
import { resolveWgClientEndpoint } from "@mmapp/contracts/wireguard"
|
||||
import { selectWgExportPeer } from "@/lib/wg-export-peer"
|
||||
import type { WgIfaceWithServer } from "@/components/data-grids/wireguard-data-grid"
|
||||
import {
|
||||
@@ -22,6 +23,7 @@ function WgExportSheet({
|
||||
onRequestLiveExport,
|
||||
initialTab = "rsc",
|
||||
peerId,
|
||||
serverHost,
|
||||
}: {
|
||||
open: boolean
|
||||
iface: WgIfaceWithServer | null
|
||||
@@ -32,6 +34,7 @@ function WgExportSheet({
|
||||
initialTab?: "rsc" | "conf" | "peer"
|
||||
/** Selected peer for Peer .conf (defaults to first peer) */
|
||||
peerId?: string | null
|
||||
serverHost?: string
|
||||
}) {
|
||||
const formats = useMemo((): CodeExportFormat[] => {
|
||||
if (!iface) {
|
||||
@@ -90,8 +93,7 @@ function WgExportSheet({
|
||||
peerAddress: peer.clientAddress,
|
||||
peerDns: peer.clientDns,
|
||||
serverPublicKey: iface.publicKey,
|
||||
allowedIps: peer.allowedIps,
|
||||
endpoint: peer.clientEndpoint || peer.endpoint || undefined,
|
||||
endpoint: resolveWgClientEndpoint(peer.clientEndpoint, serverHost, iface.listenPort),
|
||||
persistentKeepalive: peer.persistentKeepalive ?? 25,
|
||||
})
|
||||
}
|
||||
@@ -120,7 +122,7 @@ function WgExportSheet({
|
||||
isLive: Boolean(liveContent?.peerConf),
|
||||
},
|
||||
]
|
||||
}, [iface, liveContent, peerId])
|
||||
}, [iface, liveContent, peerId, serverHost])
|
||||
|
||||
return (
|
||||
<CodeExportSheet
|
||||
@@ -129,6 +131,7 @@ function WgExportSheet({
|
||||
title="Экспорт WireGuard"
|
||||
description={iface ? `${iface.name} · ${iface.serverName}` : "—"}
|
||||
formats={formats}
|
||||
beforeCode={<p className="text-xs text-muted-foreground">Peer .conf — шаблон для клиента. Заполните его приватный ключ, адрес и сети AllowedIPs. При NAT укажите доступный извне client-endpoint; endpoint удалённого пира здесь не используется.</p>}
|
||||
initialFormatId={initialTab}
|
||||
liveBusy={liveBusy}
|
||||
liveLabel="С роутера"
|
||||
|
||||
@@ -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 проверки.
|
||||
|
||||
Финальный 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
@@ -1,12 +1,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 открыт.
|
||||
|
||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-08. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||
|
||||
## Актуальная точка продолжения — 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).
|
||||
|
||||
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
# 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).
|
||||
|
||||
@@ -34,7 +34,19 @@
|
||||
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
|
||||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
|
||||
| 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)
|
||||
|
||||
|
||||
+13
-1
@@ -1,6 +1,6 @@
|
||||
# Этап 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.
|
||||
|
||||
@@ -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 проверки.
|
||||
|
||||
Финальный 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.
|
||||
@@ -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 проверки.
|
||||
|
||||
Финальный 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.
|
||||
@@ -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
@@ -324,13 +324,16 @@ export function generatePeerClientConf(args: {
|
||||
const lines: string[] = []
|
||||
lines.push(`[Interface]`)
|
||||
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}`)
|
||||
lines.push(``)
|
||||
lines.push(`[Peer]`)
|
||||
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}`)
|
||||
else lines.push(`# Endpoint = <укажите адрес сервера и порт>`)
|
||||
if (args.persistentKeepalive != null && args.persistentKeepalive > 0) {
|
||||
lines.push(`PersistentKeepalive = ${args.persistentKeepalive}`)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
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 wgPeerDtoSchema = z.object({
|
||||
|
||||
@@ -419,8 +419,8 @@ test("WireGuard: экспорт отклоняет повреждённый от
|
||||
test("WireGuard: экспорт второго пира использует его RouterOS ID", async ({ page }) => {
|
||||
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: [
|
||||
{ id: "first", rosId: "*P1", publicKey: "fixture-peer-one", allowedIps: ["10.0.1.1/32"] },
|
||||
{ id: "second", rosId: "*P2", publicKey: "fixture-peer-two", allowedIps: ["10.0.2.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"], 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 }))
|
||||
let body: Record<string, unknown> | undefined
|
||||
@@ -433,8 +433,13 @@ test("WireGuard: экспорт второго пира использует е
|
||||
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()
|
||||
const dialog = page.getByRole("dialog", { name: "Экспорт WireGuard" })
|
||||
await expect(dialog.locator("pre")).toContainText("10.0.2.1/32")
|
||||
await expect(dialog.locator("pre")).not.toContainText("10.0.1.1/32")
|
||||
await expect(dialog.locator("pre")).toContainText("Address = 10.0.2.9/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 expect(dialog.locator("pre")).toContainText("SECOND_PEER_EXPORT")
|
||||
expect(body).toMatchObject({ serverId: "1", interfaceName: "wg-peers", peerId: "*P2", format: "peer-conf", includePrivateKey: false })
|
||||
|
||||
Reference in new issue
Block a user