Files
safetynet/apps/network-broker/service-bootstrap.cjs
T

38 lines
3.0 KiB
JavaScript

'use strict';
const {BootstrapSchema}=require('./production-factory.cjs');
const {createHash}=require('node:crypto');
// Matches the installed native service's fixed receiver/WFP contract. Caller
// bootstrap JSON cannot choose a port outside that protected boundary.
const SERVICE_BROKER_PORT=43120;
function freeze(value){if(value&&typeof value==='object'){for(const child of Object.values(value))freeze(child);Object.freeze(value);}return value;}
// loadTrust is fixed privileged code: verify protected release/deployment files,
// rollback state and native-authenticated SID before returning its bootstrap.
// No IPC field may select this callback, trust paths, keys or SID.
function createServiceFactory({loadTrust,factory}={}){
if(typeof loadTrust!=='function'||typeof factory!=='function')throw Error('broker-bootstrap-invalid');
return async(config,callbacks)=>{
let parsed,binding,expiresAt;
try{
parsed=freeze(BootstrapSchema.parse(config));
if(parsed.brokerPort!==SERVICE_BROKER_PORT)throw Error();
const verified=await loadTrust(parsed);binding=verified?.bootstrap;expiresAt=verified?.deployment?.manifest?.expiresAt;
if(!Number.isSafeInteger(expiresAt)||expiresAt<=Date.now())throw Error();
if(!Number.isSafeInteger(verified?.policyVersion)||verified.policyVersion<1||verified.policyVersion!==callbacks?.expectedPolicyVersion||typeof verified.policyDigest!=='string'||!/^[a-f0-9]{64}$/.test(verified.policyDigest)||verified.policyDigest!==createHash('sha256').update(parsed.envelope.payload).digest('hex'))throw Error();
if(!binding||typeof binding.publicKey!=='string'||typeof binding.deviceId!=='string'||!Number.isSafeInteger(binding.minimumVersion)||binding.minimumVersion<1||
parsed.publicKey!==binding.publicKey||parsed.deviceId!==binding.deviceId||parsed.minimumVersion<binding.minimumVersion)throw Error();
// Reparse the trusted projection to prevent a malformed privileged loader
// from weakening the production bootstrap contract.
parsed=BootstrapSchema.parse({...parsed,publicKey:binding.publicKey,deviceId:binding.deviceId,minimumVersion:Math.max(parsed.minimumVersion,binding.minimumVersion)});
}catch{throw Error('broker-bootstrap-invalid');}
const created=await factory(parsed,callbacks);
if(!created||typeof created.listen!=='function'||typeof created.close!=='function')throw Error('broker-bootstrap-invalid');
let closed=false,timer,closeWork;
const close=()=>{if(closeWork)return closeWork;closed=true;clearTimeout(timer);closeWork=Promise.resolve().then(()=>created.close());return closeWork;};
const live=()=>!closed&&Date.now()<expiresAt;
const expire=()=>{if(!live()){void close().catch(()=>{});return;}timer=setTimeout(expire,Math.min(expiresAt-Date.now(),2147483647));timer.unref?.();};
expire();
return Object.freeze({...created,async listen(){if(!live()){await close();throw Error('broker-bootstrap-invalid');}const result=await created.listen();if(!live()){await close();throw Error('broker-bootstrap-invalid');}return result;},close});
};
}
module.exports={createServiceFactory,SERVICE_BROKER_PORT};