fix(ui): сохранять контекст и блокировку рекурсивных маршрутов

This commit is contained in:
Denozordec committed 2026-09-30 21:43:41 +07:00
1 parent 52493debc2
commit 50fad3ac80
10 files changed
+223 -28

No files matched your search

+1
View File
@@ -241,6 +241,7 @@ export function permissionForPath(pathname: string): string | null {
if (pathname.startsWith("/certificates")) return "mm:certificates:read"
if (
pathname.startsWith("/network") ||
pathname.startsWith("/recursive-routes") ||
pathname.startsWith("/ospf") ||
pathname.startsWith("/route-optimizer")
) {
+14
View File
@@ -0,0 +1,14 @@
import {test} from "node:test"
import assert from "node:assert/strict"
import {readRecursiveUrl,patchRecursiveUrl} from "./recursive-route-url-state"
import {permissionForPath} from "./auth"
test("recursive context roundtrip owns only its URL fields",()=>{
const params=new URLSearchParams("keep=x&server=2&q=ether&route=10.0.0.0%2F24&table=main")
assert.deepEqual(readRecursiveUrl(params),{serverId:"2",q:"ether",route:"10.0.0.0/24",table:"main",error:null})
const next=patchRecursiveUrl(params,{serverId:"1",q:null,route:null,table:null})
assert.equal(next.get("keep"),"x");assert.equal(next.get("server"),"1");assert.equal(next.has("q"),false)
assert.equal(permissionForPath("/recursive-routes"),"mm:network:read")
})
test("recursive invalid or ambiguous URL never guesses a device/group",()=>{
for(const q of ["server=0","server=srv1","server=1&server=2","route=10.0.0.0/24","table=main","q=a&q=b","q="+"x".repeat(257)]) assert.ok(readRecursiveUrl(new URLSearchParams(q)).error,q)
})
+22
View File
@@ -0,0 +1,22 @@
export type RecursiveUrlState = { serverId: string | null; q: string; route: string | null; table: string | null; error: string | null }
export type RecursiveUrlPatch = Partial<{ serverId: string | null; q: string | null; route: string | null; table: string | null }>
export function readRecursiveUrl(params: URLSearchParams): RecursiveUrlState {
const result: RecursiveUrlState = { serverId: null, q: "", route: null, table: null, error: null }
for (const [key, limit] of [["server", 64], ["q", 256], ["route", 128], ["table", 256]] as const) {
const values = params.getAll(key)
if (values.length > 1 || values.some(value => value.length > limit)) return { ...result, error: "Некорректный контекст маршрутов в ссылке" }
}
const server = params.get("server"), q = params.get("q")?.trim() ?? ""
if (server !== null && !/^[1-9]\d*$/.test(server)) return { ...result, error: "Некорректное устройство в ссылке" }
const route = params.get("route")?.trim() ?? null, table = params.get("table")?.trim() ?? null
if ((route !== null || table !== null) && (!route || !table)) return { ...result, error: "В ссылке маршрута нужны адрес и таблица" }
return { serverId: server, q, route, table, error: null }
}
export function patchRecursiveUrl(params: URLSearchParams, patch: RecursiveUrlPatch): URLSearchParams {
const next = new URLSearchParams(params)
for (const [field, value] of Object.entries(patch)) {
const key = field === "serverId" ? "server" : field
if (value === null || value.trim() === "") next.delete(key); else next.set(key, value.trim())
}
return next
}