Add packaged DLP broker and protected Windows service foundation

This commit is contained in:
Karl committed 2026-10-14 14:19:22 +02:00
1 parent 95d23f4e0b
commit 7b5057901a
140 files changed
+11215 -60

No files matched your search

@@ -0,0 +1,49 @@
'use strict';
const {spawn}=require('node:child_process');
const path=require('node:path');
const {TextDecoder}=require('node:util');
const {installationRoot}=require('./service-store-client.cjs');
const {createWorkAdmission}=require('./work-admission.cjs');
const refusal=()=>Error('broker-management-refused');
const exact=(v,keys)=>v&&typeof v==='object'&&!Array.isArray(v)&&Object.keys(v).sort().join(',')===keys.sort().join(',');
const keys=['deviceId','origin','policyVersion','policyKeySha256','policyDigest'];
function validBinding(value){
if(!exact(value,keys)||! /^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/.test(value.deviceId)||!Number.isSafeInteger(value.policyVersion)||value.policyVersion<1||![value.policyKeySha256,value.policyDigest].every(v=>typeof v==='string'&&/^[a-f0-9]{64}$/.test(v)))throw refusal();
if(typeof value.origin!=='string'||value.origin.length>2048)throw refusal();const u=new URL(value.origin);if(u.protocol!=='https:'||u.origin!==value.origin||u.username||u.password||u.pathname!=='/'||u.search||u.hash)throw refusal();return Object.freeze({...value});
}
// Read-only contract for the fixed native protected store. Native command must
// authenticate enabled SCM SID + retained signed Node parent and validate its
// OS-minted user SID, signed deployment and exact accepted policy digest.
// This module never creates a store or treats an environment SID as authority.
function createNativeManagementCredentialLoader({expectedBinding,current,launch=spawn,deadlineMs=10000}={}){
let expected;try{expected=validBinding(expectedBinding);if(typeof current!=='function'||typeof launch!=='function'||!Number.isSafeInteger(deadlineMs)||deadlineMs<1||deadlineMs>30000)throw refusal();}catch{throw refusal();}
let closed=false,closing;const stops=new Set(),operations=new Set(),admission=createWorkAdmission({maxJobs:1}),active=()=>{try{return !closed&&current()===true;}catch{return false;}};
const load=async(binding,{signal}={})=>{
try{
const request=validBinding(binding);if(!active()||signal?.aborted||keys.some(k=>request[k]!==expected[k]))throw refusal();
const operation=admission.run(()=>new Promise((resolve,reject)=>{
let child,timer,total=0,failed=false;const output=Buffer.alloc(8196);
const stop=()=>{failed=true;try{child?.kill();}catch{}};stops.add(stop);
try{
const sid=process.env.SAFETYNET_SERVICE_CLIENT_SID;if(typeof sid!=='string'||! /^(?:S-1-5-21|S-1-12-1)-(?:(?:0|[1-9][0-9]{0,9})-){3}(?:0|[1-9][0-9]{0,9})$/.test(sid)||sid.split('-').slice(4).some(n=>Number(n)>4294967295))throw refusal();
child=launch(path.join(installationRoot,'safetynet-service-host.exe'),['--management-credential'],{cwd:installationRoot,shell:false,windowsHide:true,stdio:['pipe','pipe','ignore'],env:{SystemRoot:process.env.SystemRoot,WINDIR:process.env.WINDIR,SAFETYNET_SERVICE_CLIENT_SID:sid}});
signal?.addEventListener('abort',stop,{once:true});timer=setTimeout(stop,deadlineMs);child.once('error',stop);child.stdin.on('error',stop);child.stdout.on('error',stop);
child.stdout.on('data',part=>{if(failed)return;if(!Buffer.isBuffer(part)||total+part.length>output.length){stop();return;}part.copy(output,total);total+=part.length;if(total>=4&&(output.readUInt32LE(0)<2||output.readUInt32LE(0)>8192||total>output.readUInt32LE(0)+4))stop();});
child.once('close',(code,endedSignal)=>{
stops.delete(stop);clearTimeout(timer);signal?.removeEventListener('abort',stop);let token;
try{
if(failed||code!==0||endedSignal||!active()||signal?.aborted||total<6||output.readUInt32LE(0)!==total-4)throw refusal();
const value=JSON.parse(new TextDecoder('utf-8',{fatal:true}).decode(output.subarray(4,total)));
if(!exact(value,[...keys,'token'])||keys.some(k=>value[k]!==expected[k])||typeof value.token!=='string'||value.token.length<16||value.token.length>4096||! /^[A-Za-z0-9._~-]+$/.test(value.token))throw refusal();
token=Buffer.from(value.token);resolve(Object.freeze({deviceId:expected.deviceId,origin:expected.origin,token}));
}catch{token?.fill(0);reject(refusal());}finally{output.fill(0);}
});
const payload=Buffer.from(JSON.stringify(request));if(payload.length>4096){payload.fill(0);throw refusal();}const frame=Buffer.alloc(payload.length+4);frame.writeUInt32LE(payload.length);payload.copy(frame,4);payload.fill(0);child.stdin.end(frame,()=>frame.fill(0));
}catch{stop();if(!child){stops.delete(stop);clearTimeout(timer);output.fill(0);reject(refusal());}}
}));
operations.add(operation);try{return await operation;}finally{operations.delete(operation);}
}catch{throw refusal();}
};
return Object.freeze({load,close(){if(closing)return closing;closed=true;admission.close();for(const stop of stops)stop();closing=Promise.allSettled([...operations]).then(()=>undefined);return closing;}});
}
module.exports={createNativeManagementCredentialLoader};