153 lines
12 KiB
TypeScript
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()}
|
|
}
|
|
})
|