41 lines
2.3 KiB
JavaScript
41 lines
2.3 KiB
JavaScript
'use strict';
|
|
const {BrokerAuditEventSchema}=require('../../packages/core/broker-audit.cjs');
|
|
// Parent-only adapter. persistQueue must synchronously encrypt, write, fsync and
|
|
// commit the complete queue, return undefined on success and throw on failure.
|
|
// An OTLP send, boolean result or asynchronous enqueue is insufficient.
|
|
// Bind current() to the authenticated child and the accepted policy generation.
|
|
function createBrokerAuditPersistence({current,policyVersion,getQueue,persistQueue,onFailure}={}){
|
|
if(![current,getQueue,persistQueue,onFailure].every(fn=>typeof fn==='function')||!Number.isSafeInteger(policyVersion)||policyVersion<1)throw Error('broker-audit-parent-invalid');
|
|
let failed=false;
|
|
const fail=()=>{const first=!failed;failed=true;if(first)try{onFailure();}catch{}throw Error('broker-audit-parent-unavailable');};
|
|
const active=()=>{try{return !failed&¤t()===true;}catch{return false;}};
|
|
return Object.freeze({
|
|
persist(input){
|
|
if(!active())return fail();
|
|
let event,queue;
|
|
try{
|
|
let nodes=0;
|
|
const plain=(value,depth=0)=>{
|
|
if(++nodes>128||depth>6)return false;
|
|
if(!value||typeof value!=='object')return true;
|
|
if(![Object.prototype,null].includes(Object.getPrototypeOf(value)))return false;
|
|
return Object.values(Object.getOwnPropertyDescriptors(value)).every(item=>'value'in item&&plain(item.value,depth+1));
|
|
};
|
|
if(!input||typeof input!=='object'||!plain(input))return fail();
|
|
event=BrokerAuditEventSchema.parse(input);queue=getQueue();
|
|
if(event.policyVersion!==policyVersion||!Array.isArray(queue)||queue.length>=10000||queue.some(item=>item.eventId===event.eventId))return fail();
|
|
Object.freeze(event.request);if(event.file)Object.freeze(event.file);if(event.broker)Object.freeze(event.broker);Object.freeze(event);
|
|
queue.push(event);
|
|
const result=persistQueue();
|
|
// Fail closed for an accidentally asynchronous writer; suppress its rejected
|
|
// promise without issuing a receipt or retrying uncertain persistence.
|
|
if(result&&typeof result.then==='function'){Promise.resolve(result).catch(()=>{});return fail();}
|
|
if(result!==undefined)return fail();
|
|
if(!active())return fail();
|
|
return Object.freeze({persisted:true,eventId:event.eventId});
|
|
}catch{return fail();}
|
|
}
|
|
});
|
|
}
|
|
module.exports={createBrokerAuditPersistence};
|