Audit native transports and retain secure export diagnostics

This commit is contained in:
Karl committed 2026-10-14 00:37:32 +02:00
1 parent 8a253eda89
commit 0a5df7398e
28 files changed
+636 -53

No files matched your search

+27 -3
View File
@@ -210,12 +210,12 @@ async function flushAudit(){
try{for(let n=0;n<100&&auditQueue.length;n++){const record=auditQueue[0];await diagnostics.withCorrelation(record,()=>diagnosticSpan('browser.management',{operation:'audit.deliver'},()=>require('./evidence-delivery.cjs').deliverAuditRecord({record,send:(route,body)=>request(device.server,route,body,device.token),getContext:()=>({ready,policy,deviceId:device.id})})));auditQueue.shift();persistAudit();}}
catch{}finally{flushing=false;}
}
async function audit(kind,ruleId,host,fileFacts,requestFacts,evidencePayload,agentFacts,interactionFacts,origin){
async function audit(kind,ruleId,host,fileFacts,requestFacts,evidencePayload,agentFacts,interactionFacts,origin,transportFacts){
if(!device||!policy)return;
// Operational correlation contains no rule text, hostname or forensic payload.
try{diagnostics.event('browser.security',diagnosticContext({decision:kind.endsWith('.block')?'block':kind.endsWith('.denied')?'deny':kind.endsWith('.authorized')||kind.endsWith('.released')?'allow':'unknown',reason:ruleId}));}catch{}
if(auditQueue.length>=10000){quarantine('Security event queue is full. Contact your administrator.');return;}
try{const file=fileFacts?require('../../packages/core/transfer-facts.cjs').transferFacts(fileFacts):undefined;const request=requestFacts?require('../../packages/core/request-transfer-facts.cjs').requestTransferFacts(requestFacts):undefined;const agent=agentFacts?require('../../packages/core/agent-audit.cjs').agentAuditFacts(agentFacts):undefined;const interaction=interactionFacts?require('../../packages/core/interaction-facts.cjs').InteractionFactsSchema.parse(interactionFacts):undefined;const evidenceType=evidencePayload?.action?'interaction':'download';auditQueue.push({eventId:require('node:crypto').randomUUID(),kind,...(ruleId?{ruleId}:{}),...(host?{host}:{}),...(file?{file}:{}),...(request?{request}:{}),...(agent?{agent}:{}),...(interaction?{interaction}:{}),...(evidencePayload&&require('./evidence-delivery.cjs').collectionAllowed({ready,policy,type:evidenceType})?{protectedEvidence:{deviceId:device.id,type:evidenceType,payload:require('./evidence-delivery.cjs').validatedEvidence(evidencePayload,evidenceType)}}:{}),...diagnosticCorrelation(),policyVersion:Number.isSafeInteger(origin?.policyVersion)&&origin.policyVersion>0?origin.policyVersion:policy.version});persistAudit();const eventId=auditQueue.at(-1).eventId;flushAudit();return eventId;}
try{const file=fileFacts?require('../../packages/core/transfer-facts.cjs').transferFacts(fileFacts):undefined;const request=requestFacts?require('../../packages/core/request-transfer-facts.cjs').requestTransferFacts(requestFacts):undefined;const agent=agentFacts?require('../../packages/core/agent-audit.cjs').agentAuditFacts(agentFacts):undefined;const interaction=interactionFacts?require('../../packages/core/interaction-facts.cjs').InteractionFactsSchema.parse(interactionFacts):undefined;const transport=transportFacts?require('../../packages/core/transport-facts.cjs').transportFactsForEvent(kind,transportFacts):undefined;if(transportFacts&&!transport)throw Error('Transport audit metadata mismatch');const evidenceType=evidencePayload?.action?'interaction':'download';auditQueue.push({eventId:require('node:crypto').randomUUID(),kind,...(ruleId?{ruleId}:{}),...(host?{host}:{}),...(file?{file}:{}),...(request?{request}:{}),...(agent?{agent}:{}),...(interaction?{interaction}:{}),...(transport?{transport}:{}),...(evidencePayload&&require('./evidence-delivery.cjs').collectionAllowed({ready,policy,type:evidenceType})?{protectedEvidence:{deviceId:device.id,type:evidenceType,payload:require('./evidence-delivery.cjs').validatedEvidence(evidencePayload,evidenceType)}}:{}),...diagnosticCorrelation(),policyVersion:Number.isSafeInteger(origin?.policyVersion)&&origin.policyVersion>0?origin.policyVersion:policy.version});persistAudit();const eventId=auditQueue.at(-1).eventId;flushAudit();return eventId;}
catch{quarantine('Security events cannot be persisted. Contact your administrator.');}
}
function auditAgent(event){
@@ -695,6 +695,28 @@ function installSiteHooks(tab){
audit:event=>audit(event.kind,event.ruleId,event.host),block:result=>{security.visualBlocked={...result,message:result.reason==='credential-brand-impersonation'?'Blocked: this login resembles a protected brand on an unapproved origin.':'Blocked: this login could not be inspected safely.'};security.visualApproval=null;quarantine(security.visualBlocked.message);}
});
}
function installTransportObserver(tab){
const contents=tab.contents;
const current=context=>!!context&&context.deviceId===device?.id&&context.sessionId===tab.id&&tabs?.fromContents(contents.id)===tab&&!contents.isDestroyed();
const unavailable=reason=>{clipboardFatal=true;quarantine('Managed transport monitoring failed. Restart this browser.');try{tab.security.transportObserver?.dispose();}catch{}return diagnosticSpan('browser.transport',{operation:'transport.monitor-unavailable',sessionId:tab.id,reason,status:'error'},()=>audit('transport.monitor-unavailable',reason));};
tab.security.transportObserver=require('./native-transport-observer.cjs').createNativeTransportObserver({
channel:require('./page-clipboard-guard.cjs').createNativeTransportChannel(contents),
getContext:()=>ready&&policy&&device&&localRelay&&Date.parse(policy.expiresAt)>Date.now()?Object.freeze({deviceId:device.id,policyVersion:policy.version,sessionId:tab.id,documentGeneration:tab.security.interactionDocumentGeneration}):null,
isCurrent:current,
traceOperation:(operation,callback,context)=>diagnosticSpan('browser.transport',{operation,sessionId:context?.sessionId||tab.id,policyVersion:context?.policyVersion||policy?.version},callback),
// Synchronous native alarm precedes the serialized durable audit queue.
onEstablished:context=>{if(current(context)){clipboardFatal=true;quarantine('An uninspectable transport connected. Restart this browser.');}},
audit:async(facts,context)=>{
if(!current(context))return;
const {host,...transport}=facts;
const eventId=await diagnosticSpan('browser.transport',{operation:`transport.${transport.phase}`,sessionId:tab.id,policyVersion:context.policyVersion},()=>audit(`transport.${transport.phase}`,undefined,host,undefined,undefined,undefined,undefined,undefined,{policyVersion:context.policyVersion},transport));
if(typeof eventId!=='string')throw Error('Transport audit persistence failed');
if(transport.phase==='established')await unavailable('unexpected-webtransport-established');
},
onFailure:unavailable
});
return tab.security.transportObserver.install();
}
function createNativeTab(input={}){return diagnosticSpan('browser.tab',{operation:'create'},()=>createNativeTabImpl(input));}
async function createNativeTabImpl(input={},controls={}){
if(!input||typeof input!=='object'||Object.keys(input).some(key=>!['group','url'].includes(key)))throw Error('Invalid native tab request');
@@ -705,6 +727,8 @@ async function createNativeTabImpl(input={},controls={}){
await tab.view.webContents.loadURL('about:blank');
controls.assertCurrent?.();
await diagnosticSpan('browser.clipboard',{operation:'create',sessionId:tab.id},()=>attachPageClipboardGuard(tab.view.webContents,()=>{clipboardFatal=true;quarantine('Managed clipboard protection failed; restart the browser');audit('clipboard.block','clipboard-primitive-unavailable');app.quit();}));
controls.assertCurrent?.();
await installTransportObserver(tab);
controls.assertCurrent?.();tab.guarded=true;selectTab(tab.id);controls.onActivated?.(tab);controls.assertCurrent?.();
if(input.url){if(tab.security.agentAuthority){await agentActorStorage.run(tab.security.agentAuthority,()=>navigate({url:input.url,tabId:tab.id},undefined,{signal:controls.signal}));}else await navigate({url:input.url,tabId:tab.id},undefined,{signal:controls.signal});}controls.assertCurrent?.();emit();return state();
}catch(error){if(tabs.all().includes(tab)){tabs.remove(tab.id);if(tabs.active()?.guarded)selectTab(tabs.active().id);}throw error;}
@@ -811,7 +835,7 @@ app.whenReady().then(async()=>{
Menu.setApplicationMenu(null);
win=new BrowserWindow({width:1320,height:900,minWidth:800,minHeight:600,frame:false,roundedCorners:true,hasShadow:true,backgroundMaterial:'acrylic',backgroundColor:'#eef1f5',autoHideMenuBar:true,webPreferences:{preload:path.join(__dirname,'preload.cjs'),nodeIntegration:false,contextIsolation:true,sandbox:true,devTools:false}});
win.removeMenu();
tabs=createTabRegistry({createView:()=>new WebContentsView({webPreferences:{session:browserSession,preload:path.join(__dirname,'site-preload.cjs'),nodeIntegration:false,nodeIntegrationInSubFrames:true,contextIsolation:true,sandbox:true,webSecurity:true,allowRunningInsecureContent:false}}),attach:v=>win.contentView.addChildView(v),detach:v=>win.contentView.removeChildView(v),dispose:tab=>{tab.security.interactionObserver?.dispose();disposePageClipboardGuard(tab.contents);}});
tabs=createTabRegistry({createView:()=>new WebContentsView({webPreferences:{session:browserSession,preload:path.join(__dirname,'site-preload.cjs'),nodeIntegration:false,nodeIntegrationInSubFrames:true,contextIsolation:true,sandbox:true,webSecurity:true,allowRunningInsecureContent:false}}),attach:v=>win.contentView.addChildView(v),detach:v=>win.contentView.removeChildView(v),dispose:tab=>{tab.security.interactionObserver?.dispose();Promise.resolve(tab.security.transportObserver?.dispose()).catch(()=>{});disposePageClipboardGuard(tab.contents);}});
const executeClipboard=(mode,args)=>args.webContents.executeJavaScriptInIsolatedWorld(999,[{code:clipboardScript(mode,args)}],false);
clipboardGuard=createClipboardGuard({
getContext:contents=>{const target=contents||view?.webContents,tab=target&&tabs.fromContents(target.id),site=!!tab,url=target?.getURL()||'',token=site?tabContext(tab.id):null;return {ready:ready&&target?.isFocused()&&(site?tab===activeTab()&&!tab.startPage&&!overviewPanel&&!toolsOpen&&core.destinationAllowed(url,policy):target===win.webContents&&url===uiUrl),policy,webContents:target,url,navigationId:site?tab.navigationId:0,tabId:tab?.id,activation:token?.activation};},