fix(api): проверять обязательные поля снимка RouterOS
This commit is contained in:
1 parent
b658f7127f
commit
160b39186a
6 files changed
+26
-8
No files matched your search
@@ -70,7 +70,7 @@ async function readRouteLookup(serverId: number): Promise<{ gateway: string | nu
|
||||
const row = (await db.select().from(servers).where(eq(servers.id, serverId)).limit(1))[0]
|
||||
if (!row) throw new Error(`Internet path: устройство ${serverId} не найдено`)
|
||||
const client = MikrotikClient.fromServer(row)
|
||||
const routes = await client.get<unknown>("/ip/route").then(raw => readInternetPathRows(raw, "routes " + serverId))
|
||||
const routes = await client.get<unknown>("/ip/route").then(raw => readInternetPathRows(raw, "routes " + serverId, ["dst-address"]))
|
||||
const best = routes
|
||||
.filter((r) => String(r["dst-address"] ?? "").trim() === "0.0.0.0/0")
|
||||
.filter((r) => isTrue(r.active))
|
||||
@@ -93,9 +93,9 @@ async function readWanRuntime(serverId: number) {
|
||||
if (!server || !row) throw new Error(`Internet path: устройство ${serverId} не найдено`)
|
||||
const client = MikrotikClient.fromServer(row)
|
||||
const [dhcpRaw, ipAddrs, routes] = await Promise.all([
|
||||
client.get<unknown>("/ip/dhcp-client").then(raw => readInternetPathRows(raw, "DHCP " + serverId)),
|
||||
client.get<unknown>("/ip/address").then(raw => readInternetPathRows(raw, "addresses " + serverId)),
|
||||
client.get<unknown>("/ip/route").then(raw => readInternetPathRows(raw, "routes " + serverId)),
|
||||
client.get<unknown>("/ip/dhcp-client").then(raw => readInternetPathRows(raw, "DHCP " + serverId, ["interface"])),
|
||||
client.get<unknown>("/ip/address").then(raw => readInternetPathRows(raw, "addresses " + serverId, ["address", "interface"])),
|
||||
client.get<unknown>("/ip/route").then(raw => readInternetPathRows(raw, "routes " + serverId, ["dst-address"])),
|
||||
])
|
||||
const defaultRoute = routes
|
||||
.filter((r) => String(r["dst-address"] ?? "").trim() === "0.0.0.0/0")
|
||||
@@ -176,7 +176,7 @@ async function collectGreTunnels() {
|
||||
const all = await Promise.all(enabled.map(async (srv) => {
|
||||
try {
|
||||
const client = MikrotikClient.fromServer(srv)
|
||||
const rows = await client.get<unknown>("/interface/gre").then(raw => readInternetPathRows(raw, "GRE " + srv.id))
|
||||
const rows = await client.get<unknown>("/interface/gre").then(raw => readInternetPathRows(raw, "GRE " + srv.id, [".id", "name", "local-address", "remote-address"]))
|
||||
return rows.map((g, idx) => {
|
||||
const keepalive = String(g.keepalive ?? "0,0").split(",")
|
||||
const inner = parseInnerIps(String(g.comment ?? ""))
|
||||
|
||||
@@ -20,3 +20,9 @@ console.log("internet path snapshot tests ok: complete, disabled home, six faile
|
||||
assert.deepEqual(readStoredInternetPathPayload('{"collectionComplete":true}'),{collectionComplete:true})
|
||||
assert.deepEqual(readStoredInternetPathPayload(good),good)
|
||||
for(const raw of [null,"null","[1]","bad",[],1])assert.throws(()=>readStoredInternetPathPayload(raw))
|
||||
|
||||
// A syntactically valid string record may still be an API error, not an entity.
|
||||
for(const [fields,row] of [[ ["dst-address"],{"message":"denied"} ],[["interface"],{}],[["address","interface"],{address:"192.0.2.1/24"}],[[".id","name","local-address","remote-address"],{".id":"*1",name:"gre", "local-address":"0.0.0.0"}] ] as Array<[string[],Record<string,string>]>)assert.throws(()=>readInternetPathRows([row],"test",fields),/повреждён/)
|
||||
assert.deepEqual(readInternetPathRows([],"routes",["dst-address"]),[])
|
||||
assert.equal(readInternetPathRows([{ "dst-address":"0.0.0.0/0",active:"true" }],"routes",["dst-address"]).length,1)
|
||||
assert.equal(readInternetPathRows([{ ".id":"*1",name:"gre", "local-address":"0.0.0.0","remote-address":"192.0.2.2" }],"gre",[".id","name","local-address","remote-address"]).length,1)
|
||||
@@ -18,8 +18,8 @@ export async function collectConfirmedInternetPath<S extends PathServer, G, F, P
|
||||
return {collectionComplete: true as const, sampledAt, servers, greTunnels, filtersRulesets, speedProbes, routeLookupByServerId, wanRuntimeByHomeId}
|
||||
}
|
||||
|
||||
export function readInternetPathRows(raw: unknown, source: string): Array<Record<string, string>> {
|
||||
if (!Array.isArray(raw) || raw.some(row => !row || typeof row !== "object" || Array.isArray(row) || Object.values(row).some(value => typeof value !== "string"))) {
|
||||
export function readInternetPathRows(raw: unknown, source: string, requiredFields: string[] = []): Array<Record<string, string>> {
|
||||
if (!Array.isArray(raw) || raw.some(row => !row || typeof row !== "object" || Array.isArray(row) || Object.values(row).some(value => typeof value !== "string") || requiredFields.some(field => typeof row[field] !== "string" || !row[field].trim()))) {
|
||||
throw new Error("Internet path: повреждён ответ " + source)
|
||||
}
|
||||
return raw as Array<Record<string, string>>
|
||||
|
||||
Reference in new issue
Block a user