Add packaged DLP broker and protected Windows service foundation
This commit is contained in:
1 parent
95d23f4e0b
commit
7b5057901a
140 files changed
+11215
-60
No files matched your search
@@ -0,0 +1,30 @@
|
||||
import {lstat,open} from 'node:fs/promises';
|
||||
import {createHash} from 'node:crypto';
|
||||
import path from 'node:path';
|
||||
function fail(code){throw Object.assign(new Error(code),{code});}
|
||||
function same(expected,actual){return actual&&['sourceSha256','runtimeSha256','packageSha256'].every(key=>actual[key]===expected[key]);}
|
||||
async function stat(file){try{return await lstat(file);}catch(error){if(error.code==='ENOENT')return null;throw error;}}
|
||||
// Guard actual invocation and result. Caller owns/protects the build directory.
|
||||
export async function buildVerifiedInstaller({plan,expectedIdentity,readIdentity,verify,run,installerPath}){
|
||||
if(typeof run!=='function'||!plan||!path.isAbsolute(installerPath)||path.dirname(installerPath)!==path.dirname(plan.unpacked.directory)||!installerPath.endsWith('.exe'))fail('installer_configuration_invalid');
|
||||
const stage=await plan.installer({expectedIdentity,readIdentity,verify});
|
||||
if(!same(stage.identity,await readIdentity(stage.directory)))fail('installer_identity_changed');
|
||||
const previous=await stat(installerPath);if(previous?.isSymbolicLink())fail('installer_artifact_invalid');
|
||||
const result=await run(stage.args);
|
||||
if(result?.status!==0)fail('installer_build_failed');
|
||||
if(!same(stage.identity,await readIdentity(stage.directory)))fail('installer_identity_changed');
|
||||
const receipt=await verify(stage.directory,stage.identity);
|
||||
if(!receipt||!same(stage.identity,receipt.identity)||!['fuses','resources','broker','runtimeAcl'].every(key=>receipt[key]===true))fail('installer_verification_failed');
|
||||
if(!same(stage.identity,await readIdentity(stage.directory)))fail('installer_identity_changed');
|
||||
const produced=await stat(installerPath);
|
||||
if(!produced||!produced.isFile()||produced.isSymbolicLink()||produced.size<1024||produced.size>4294967295||previous&&previous.mtimeMs===produced.mtimeMs&&previous.ctimeMs===produced.ctimeMs&&previous.size===produced.size)fail('installer_artifact_invalid');
|
||||
const file=await open(installerPath,'r');
|
||||
try{
|
||||
const magic=Buffer.alloc(2);await file.read(magic,0,2,0);if(magic.toString('ascii')!=='MZ')fail('installer_artifact_invalid');
|
||||
const hash=createHash('sha256');for await(const chunk of file.createReadStream({start:0,autoClose:false}))hash.update(chunk);
|
||||
const after=await file.stat();if(after.size!==produced.size||after.mtimeMs!==produced.mtimeMs||after.ctimeMs!==produced.ctimeMs)fail('installer_artifact_changed');
|
||||
if(!same(stage.identity,await readIdentity(stage.directory)))fail('installer_identity_changed');
|
||||
const final=await file.stat();if(final.size!==after.size||final.mtimeMs!==after.mtimeMs||final.ctimeMs!==after.ctimeMs)fail('installer_artifact_changed');
|
||||
return Object.freeze({path:installerPath,bytes:after.size,sha256:hash.digest('hex'),identity:stage.identity});
|
||||
}finally{await file.close();}
|
||||
}
|
||||
Reference in new issue
Block a user