Files
MikrotikManager/backend/src/services/bandwidth-peer-metadata.test.ts
T

153 lines
12 KiB
TypeScript

/** Genuine localhost authenticated license observation + private reader token.
* Metadata checker is an explicit trusted fixture service, not request JSON.
* No remote RouterOS, key files, PostgreSQL or writer/Q authority. */
import assert from "node:assert/strict"
import { randomUUID } from "node:crypto"
import { createServer } from "node:http"
import { once } from "node:events"
import { isDeepStrictEqual } from "node:util"
import { after, test } from "node:test"
import { createBandwidthPeerObservationReader, BandwidthPeerObservationError, type BandwidthPeerSourceSnapshot, type BandwidthPeerTrustedSource, type BandwidthPeerPublicMetadata, type BandwidthPeerObservationEvidence } from "./bandwidth-peer-observation.js"
const db=await import("../db/index.js"),originalQuery=db.pool.query,originalConnect=db.pool.connect
let databaseCalls=0
db.pool.query=(()=>{databaseCalls++;throw Error("metadata unit must not query DB")}) as typeof db.pool.query
db.pool.connect=(()=>{databaseCalls++;throw Error("metadata unit must not borrow DB")}) as typeof db.pool.connect
after(async()=>{db.pool.query=originalQuery;db.pool.connect=originalConnect;assert.equal(databaseCalls,0);await db.closePool()})
const scope=(ms=5000,signal?:AbortSignal)=>({deadlineAt:Date.now()+ms,signal})
const deferred=()=>{let resolve!:()=>void;const promise=new Promise<void>(done=>{resolve=done});return {promise,resolve}}
const turn=()=>new Promise<void>(done=>setImmediate(done))
const refused=(code?:BandwidthPeerObservationError["code"])=>(error:unknown)=>error instanceof BandwidthPeerObservationError&&(!code||error.code===code)
function publicNotOrdinary(value:BandwidthPeerPublicMetadata){
// @ts-expect-error PUBLIC wrapper cannot satisfy an ordinary evidence input.
const ordinary:BandwidthPeerObservationEvidence=value
void ordinary
return value
}
async function fixture(checker=true,managed=false,originalScope=scope()){
const username="OWNED_METADATA_USER",password="OWNED_METADATA_PRIVATE_PASSWORD",auth="Basic "+Buffer.from(username+":"+password).toString("base64")
let gets=0,reads=0,checks=0,forbidReads=false
const server=createServer((request,response)=>{gets++;assert.equal(request.url,"/rest/system/license");assert.equal(request.method,"GET");assert.equal(request.headers.authorization,auth);response.writeHead(200,{"content-type":"application/json"});response.end(JSON.stringify({"system-id":"OWNED-METADATA-SYSTEM","software-id":"OWNED-METADATA-SOFTWARE"}))})
server.listen(0,"127.0.0.1");await once(server,"listening");const address=server.address();assert(address&&typeof address!=="string")
let current:BandwidthPeerSourceSnapshot={peerRef:managed?{kind:"server",serverId:83}:{kind:"external",enrollmentId:randomUUID()},enabled:true,sourceProof:"a".repeat(64),authorityGeneration:"owned-metadata-original",endpoint:{host:"127.0.0.1",port:address.port,useSsl:false,verifySsl:true,username,password,routingEndpointEpoch:randomUUID()}}
const original=structuredClone(current),received:Readonly<BandwidthPeerSourceSnapshot>[]=[],controls:{check?:()=>Promise<void>}={}
const source:BandwidthPeerTrustedSource={async read(){reads++;if(forbidReads)throw Error("metadata credential fallback attempted");return current}}
if(checker)source.assertMetadataCurrent=async(expected,input)=>{
checks++;received.push(expected);assert(Object.isFrozen(expected));assert(Object.isFrozen(expected.endpoint));assert(Object.isFrozen(expected.peerRef));assert.equal(expected.endpoint.password,password)
assert(input.deadlineAt<=originalScope.deadlineAt);assert(input.signal instanceof AbortSignal)
await controls.check?.()
if(!isDeepStrictEqual(current,expected))throw new BandwidthPeerObservationError("SOURCE_CHANGED")
}
const reader=createBandwidthPeerObservationReader(source)
let token:Awaited<ReturnType<typeof reader.observe>>,ordinary:BandwidthPeerObservationEvidence
try{token=await reader.observe(current.peerRef,originalScope);ordinary=await reader.inspect(token,scope())}
catch(error){reader.close();server.closeAllConnections();await new Promise<void>(done=>server.close(()=>done()));throw error}
const originalReads=reads,originalGets=gets;forbidReads=true
return {reader,source,token,ordinary,original,received,controls,get current(){return current},set current(value){current=value},get checks(){return checks},get reads(){return reads},get gets(){return gets},originalReads,originalGets,password,async close(){reader.close();server.closeAllConnections();await new Promise<void>(done=>server.close(()=>done()));assert.equal(reads,originalReads);assert.equal(gets,originalGets)}}
}
test("genuine managed/external metadata preserves original evidence, shares private frozen snapshot and never projects credentials",async()=>{
for(const managed of [false,true]){
const f=await fixture(true,managed)
try{
const first=publicNotOrdinary(await f.reader.inspectMetadata(f.token,scope())),second=await f.reader.inspectMetadata(f.token,scope())
assert.equal(first.format,"mmapp-bandwidth-peer-public-metadata-v1");assert.deepEqual(first.evidence,f.ordinary);assert.deepEqual(second.evidence,f.ordinary)
assert.equal(f.checks,2);assert.equal(f.received[0],f.received[1]);assert.equal(first.evidence.claims,second.evidence.claims)
for(const part of [first,first.evidence,first.evidence.peerRef,first.evidence.claims,first.evidence.claims[0]])assert(Object.isFrozen(part))
const output=JSON.stringify(first);for(const forbidden of [f.password,f.original.endpoint.username,f.original.endpoint.host,"password","endpoint","keyCurrent","credentialsVerified","currentLicense","writerBarrier"])assert.equal(output.includes(forbidden),false)
assert.equal(first.evidence.physicalUniquenessVerified,false);assert.equal(first.evidence.cloneResistanceVerified,false)
}finally{await f.close()}
}
})
test("absent checker refuses without credential fallback; method is captured once and later replacement cannot grant or revoke",async()=>{
const missing=await fixture(false)
try{
missing.source.assertMetadataCurrent=async()=>{assert.fail("late checker must not be adopted")}
await assert.rejects(missing.reader.inspectMetadata(missing.token,scope()),refused("SOURCE_UNAVAILABLE"));assert.equal(missing.checks,0)
}finally{await missing.close()}
const f=await fixture()
try{
f.source.assertMetadataCurrent=async()=>{assert.fail("replacement checker must not execute")}
assert.deepEqual((await f.reader.inspectMetadata(f.token,scope())).evidence,f.ordinary);assert.equal(f.checks,1)
f.current={...f.current,enabled:false};await assert.rejects(f.reader.inspectMetadata(f.token,scope()),refused("SOURCE_CHANGED"));assert.equal(f.checks,2)
}finally{await f.close()}
})
test("copies, ordinary/public evidence, proxies and foreign reader tokens never reach metadata checker",async()=>{
const f=await fixture(),foreign=await fixture()
try{
const wrapper=await f.reader.inspectMetadata(f.token,scope()),before=f.checks
for(const token of [{...f.token},structuredClone(f.token),f.ordinary,wrapper,new Proxy(f.token,{get(){assert.fail("token trap")}}),null])await assert.rejects(f.reader.inspectMetadata(token,scope()),refused("NOT_GENUINE"))
await assert.rejects(foreign.reader.inspectMetadata(f.token,scope()),refused("NOT_GENUINE"));assert.equal(f.checks,before);assert.equal(foreign.checks,0)
}finally{await foreign.close();await f.close()}
})
test("all current endpoint/credential/epoch/enabled/source drift must be rejected by checker, no refreshed secret snapshot",async()=>{
const mutations:Array<(value:BandwidthPeerSourceSnapshot)=>void>=[value=>{value.enabled=false},value=>{value.sourceProof="b".repeat(64)},value=>{value.authorityGeneration="new"},value=>{value.endpoint.host="192.0.2.2"},value=>{value.endpoint.port++},value=>{value.endpoint.useSsl=true},value=>{value.endpoint.verifySsl=false},value=>{value.endpoint.username="new"},value=>{value.endpoint.password="new"},value=>{value.endpoint.routingEndpointEpoch=randomUUID()},value=>{value.peerRef={kind:"server",serverId:84}}]
const f=await fixture()
try{for(const mutate of mutations){const current=structuredClone(f.original);mutate(current);f.current=current;await assert.rejects(f.reader.inspectMetadata(f.token,scope()),refused("SOURCE_CHANGED"))}assert.equal(f.checks,mutations.length)}
finally{await f.close()}
})
test("malformed checker/scope descriptors and proxies never execute caller getters; hostile native signal methods ignored",async()=>{
let called=0;const trap=()=>{called++;throw Error("caller code")}
const source={async read(){assert.fail("constructor IO")}}
assert.throws(()=>createBandwidthPeerObservationReader(Object.defineProperty(source,"assertMetadataCurrent",{get:trap})),refused("INVALID_INPUT"))
assert.throws(()=>createBandwidthPeerObservationReader(new Proxy(source,{get:trap})),refused("INVALID_INPUT"))
const f=await fixture()
try{
for(const input of [Object.defineProperty(scope(),"deadlineAt",{get:trap}),{...scope(),checker:trap},{...scope(),toJSON:trap},new Proxy(scope(),{getPrototypeOf:trap})])await assert.rejects(f.reader.inspectMetadata(f.token,input),refused("INVALID_INPUT"))
assert.equal(f.checks,0);assert.equal(called,0)
const signal=new AbortController().signal
for(const field of ["aborted","addEventListener","removeEventListener"])Object.defineProperty(signal,field,{get:trap})
await f.reader.inspectMetadata(f.token,scope(5000,signal));assert.equal(called,0);assert.equal(f.checks,1)
}finally{await f.close()}
})
test("checker failure reveals no private message and cannot fall back to source.read/native",async()=>{
const f=await fixture()
try{
f.controls.check=async()=>{throw Error(f.password)}
const error=await f.reader.inspectMetadata(f.token,scope()).then(()=>assert.fail("expected refusal"),error=>error as Error)
assert(error instanceof BandwidthPeerObservationError);assert.equal(error.code,"SOURCE_UNAVAILABLE");assert.equal(error.message.includes(f.password),false);assert.equal(f.checks,1)
}finally{await f.close()}
})
test("blocked checker abort/close/deadline/original signal cancellation refuse promptly; late success cannot publish",async()=>{
for(const mode of ["abort","close","deadline","original-abort"]){
const originalController=new AbortController(),f=await fixture(true,false,scope(5000,originalController.signal)),gate=deferred(),entered=deferred(),controller=new AbortController()
try{
f.controls.check=async()=>{entered.resolve();await gate.promise}
const input=scope(mode==="deadline"?40:5000,controller.signal),pending=f.reader.inspectMetadata(f.token,input);void pending.catch(()=>{})
await entered.promise
if(mode==="abort")controller.abort();if(mode==="original-abort")originalController.abort();if(mode==="close")f.reader.close()
input.deadlineAt=Date.now()+50000
await assert.rejects(pending,refused());gate.resolve();await turn();await turn();assert.equal(f.checks,1)
}finally{gate.resolve();await f.close()}
}
})
test("expired original observation or original aborted signal cannot be renewed by a fresh metadata scope",async()=>{
const f=await fixture(),now=Date.now
try{
Date.now=()=>f.ordinary.expiresAt+1
await assert.rejects(f.reader.inspectMetadata(f.token,{deadlineAt:f.ordinary.expiresAt+50000}),refused("CANCELLED"));assert.equal(f.checks,0)
}finally{Date.now=now;await f.close()}
})
test("wall rollback before and during checker is refused; original evidence timestamps never adopted from later scope",async()=>{
for(const mode of ["before","during"]){
const f=await fixture(),now=Date.now,gate=deferred(),entered=deferred()
try{
if(mode==="before"){Date.now=()=>f.ordinary.observedAt-1000;await assert.rejects(f.reader.inspectMetadata(f.token,scope()),refused("CANCELLED"));assert.equal(f.checks,0)}
else{
f.controls.check=async()=>{entered.resolve();await gate.promise}
const pending=f.reader.inspectMetadata(f.token,scope());void pending.catch(()=>{});await entered.promise
Date.now=()=>f.ordinary.observedAt-1000;gate.resolve();await assert.rejects(pending,refused("CANCELLED"))
}
}finally{Date.now=now;gate.resolve();await f.close()}
}
})