fix(ui): подтверждать выполнение команд терминала
This commit is contained in:
1 parent
bc20e5b9f4
commit
a2eae189be
7 files changed
+205
-422
No files matched your search
@@ -227,6 +227,7 @@ export function permissionForPath(pathname: string): string | null {
|
||||
if (pathname === "/" || pathname.startsWith("/dashboard")) {
|
||||
return "mm:dashboard:read"
|
||||
}
|
||||
if (pathname.startsWith("/terminal")) return "mm:servers:read"
|
||||
if (pathname.startsWith("/servers")) return "mm:servers:read"
|
||||
if (pathname.startsWith("/filters") || pathname.startsWith("/gre")) {
|
||||
return "mm:filters:read"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import {test} from "node:test"
|
||||
import assert from "node:assert/strict"
|
||||
import {terminalServersSchema,readTerminalOutput,readTerminalUrl,patchTerminalUrl} from "./terminal-response"
|
||||
test("terminal catalog requires explicit state and unique IDs",()=>{const row={id:1,name:"",host:"192.0.2.1",country:"RU",enabled:true,status:null};assert.equal(terminalServersSchema.parse([row])[0].status,null);for(const raw of [{},[row,row],[{...row,status:undefined}],[{...row,enabled:undefined}]])assert.equal(terminalServersSchema.safeParse(raw).success,false)})
|
||||
test("terminal output distinguishes empty success, malformed and legacy errors",()=>{assert.equal(readTerminalOutput({output:""}),"");assert.equal(readTerminalOutput({output:"0\nok"}),"0\nok");for(const raw of [{},{error:"fail"},{output:null},{output:"error: refused"},{output:"bad command name remove"},{output:"ok",error:"fail"}])assert.throws(()=>readTerminalOutput(raw))})
|
||||
test("terminal URL refuses ambiguous/malformed context, preserves unrelated parameters",()=>{for(const q of ["server=1&host=x","server=1&server=2","host=","server=bad%20id"])assert.ok(readTerminalUrl(new URLSearchParams(q)).error);assert.equal(readTerminalUrl(new URLSearchParams("host=192.0.2.1")).host,"192.0.2.1");assert.equal(patchTerminalUrl(new URLSearchParams("host=x&ref=map"),"2"),"/terminal?ref=map&server=2")})
|
||||
@@ -0,0 +1,24 @@
|
||||
import {z} from "zod"
|
||||
export const terminalServersSchema=z.array(z.object({
|
||||
id:z.number().int().positive(),name:z.string(),host:z.string().min(1),country:z.string(),enabled:z.boolean(),
|
||||
status:z.enum(["online","offline","degraded"]).nullable(),os:z.string().nullable().optional(),identityName:z.string().nullable().optional(),
|
||||
})).refine(rows=>new Set(rows.map(row=>row.id)).size===rows.length)
|
||||
const response=z.object({output:z.string().max(1024*1024)}).strict()
|
||||
export function readTerminalOutput(raw:unknown) {
|
||||
const data=response.safeParse(raw)
|
||||
if(!data.success)throw new Error("Некорректный ответ API: вывод команды не подтверждён.")
|
||||
if(/^(error:|bad command name |Usage:)/i.test(data.data.output))throw new Error(data.data.output)
|
||||
return data.data.output
|
||||
}
|
||||
export function readTerminalUrl(params:URLSearchParams) {
|
||||
const server=params.get("server"),host=params.get("host")
|
||||
const error=["server","host"].some(key=>params.getAll(key).length>1)?"В ссылке повторяется устройство терминала."
|
||||
:server!==null&&host!==null?"В ссылке одновременно указаны server и host."
|
||||
:server!==null&&!/^[a-zA-Z0-9_.:-]{1,64}$/.test(server)?"В ссылке указан некорректный сервер."
|
||||
:host!==null&&(!host.trim()||host.length>256||/[\u0000-\u001f]/.test(host))?"В ссылке указан некорректный host.":null
|
||||
return {server,host,error}
|
||||
}
|
||||
export function patchTerminalUrl(params:URLSearchParams,server:string|null){
|
||||
const next=new URLSearchParams(params);next.delete("server");next.delete("host");if(server)next.set("server",server)
|
||||
return "/terminal"+(next.size?"?"+next.toString():"")
|
||||
}
|
||||
Reference in new issue
Block a user