@letterblack/lbe-sdk 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/engine.js ADDED
@@ -0,0 +1,78 @@
1
+ import l from'fs';import t from'path';import{fileURLToPath as f}from'url';
2
+ var D=t.dirname(f(import.meta.url)),w=t.join(D,'../runtime/lbe_engine.wasm');
3
+ var POLICY_MSGS={0:{allowed:true,reason:null,message:'Policy check passed'},1:{allowed:false,reason:'POLICY_NOT_CONFIGURED',message:'No policy configured'},2:{allowed:false,reason:'REQUESTER_NOT_ALLOWED',message:'Requester not in policy'},3:{allowed:false,reason:'COMMAND_NOT_ALLOWED',message:'Command not allowed for requester'},4:{allowed:false,reason:'ADAPTER_NOT_ALLOWED',message:'Adapter not allowed'},5:{allowed:false,reason:'NO_FILESYSTEM_ROOTS_DEFINED',message:'No filesystem roots defined for requester'},6:{allowed:false,reason:'CWD_OUTSIDE_ALLOWED_ROOT',message:'Path not under allowed roots'},7:{allowed:false,reason:'PATH_DENIED_BY_PATTERN',message:'Path matches deny pattern'},8:{allowed:false,reason:'SHELL_CMD_DENIED',message:'Shell command not allowed'}};
4
+ var SCHEMA_MSGS={0:{valid:true,error:null},1:{valid:false,error:'Missing required field: id'},2:{valid:false,error:'Missing required field: commandId'},3:{valid:false,error:'Missing required field: requesterId'},4:{valid:false,error:'Missing required field: sessionId'},5:{valid:false,error:'Missing required field: timestamp'},6:{valid:false,error:'Missing required field: nonce'},7:{valid:false,error:'Missing required field: requires'},8:{valid:false,error:'Missing required field: payload'},9:{valid:false,error:'Missing required field: signature'},10:{valid:false,error:"Field 'id' is invalid"},11:{valid:false,error:"Field 'commandId' is invalid"},12:{valid:false,error:"Field 'requesterId' is invalid"},13:{valid:false,error:"Field 'sessionId' is invalid"},14:{valid:false,error:"Field 'timestamp' is invalid"},15:{valid:false,error:"Field 'nonce' is invalid"},16:{valid:false,error:"Field 'requires' is invalid"},17:{valid:false,error:'payload: missing required field: adapter'},18:{valid:false,error:"payload: field 'adapter' is invalid"},19:{valid:false,error:'signature: missing required field: alg'},20:{valid:false,error:'signature: missing required field: keyId'},21:{valid:false,error:'signature: missing required field: sig'},22:{valid:false,error:"signature: field 'alg' must be ed25519"},23:{valid:false,error:"signature: field 'sig' is invalid"},24:{valid:false,error:"Field 'risk' is invalid"}};
5
+ var KEY_REASONS={1:'KEY_ID_INVALID',2:'KEY_NOT_TRUSTED',3:'KEY_DEPRECATED',4:'KEY_REQUESTER_MISMATCH',5:'KEY_LIFECYCLE_INVALID',6:'KEY_NOT_YET_VALID',7:'KEY_EXPIRED'};
6
+ var PIPELINE_STAGES={0:'schema',1:'timestamp',2:'key',3:'signature',4:'rate_limit',5:'nonce',6:'policy',255:'ok'};
7
+ var RISK_LABELS=['LOW','MEDIUM','HIGH','CRITICAL'];
8
+ var CMD_TYPE={ECHO:0,READ_FILE:1,WRITE_FILE:2,PATCH_FILE:3,DELETE_FILE:4,RUN_SHELL:5};
9
+ var _inst=null;
10
+ function wasm(){if(_inst)return _inst;if(!l.existsSync(w))throw new Error(`LBE engine missing: ${w}`);_inst=new WebAssembly.Instance(new WebAssembly.Module(l.readFileSync(w)),{});return _inst}
11
+ function mem(){return new Uint8Array(wasm().exports.memory.buffer)}
12
+ function inPtr(){return wasm().exports.lbe_in_ptr()}
13
+ function outPtr(){return wasm().exports.lbe_out_ptr()}
14
+ function bufSz(){return wasm().exports.lbe_buf_size()}
15
+ function writeIn(s){let e=new TextEncoder().encode(s),m=mem(),p=inPtr();m.set(e,p);m[p+e.length]=0}
16
+ function readOut(){let m=mem(),p=outPtr(),e=p;while(m[e]!==0&&e-p<bufSz())e++;return new TextDecoder().decode(m.slice(p,e))}
17
+ function writeInBin(a,b){let m=mem(),p=inPtr(),i=p;for(let x=0;x<a.length;x++)m[i++]=a[x];m[i++]=0;for(let x=0;x<b.length;x++)m[i++]=b[x];m[i]=0}
18
+ function writePipeIn(fields){let m=mem(),p=inPtr(),v=new DataView(m.buffer,p);fields.forEach((f,i)=>v.setUint32(i*4,f>>>0,true))}
19
+ function readPipeOut(){let m=mem(),p=outPtr(),v=new DataView(m.buffer,p);return{stage:v.getUint32(0,true),code:v.getUint32(4,true)}}
20
+ export function getRuntimeInfo(){return{mode:'wasm',available:l.existsSync(w),wasmPath:w,localFirst:true}}
21
+ export async function loadWasmEngine(){return{ok:true,mode:'wasm',version:wasm().exports.lbe_engine_version()}}
22
+ export function runValidationPipeline(flags){
23
+ writePipeIn([
24
+ flags.hasId?1:0,flags.idValid?1:0,flags.hasCommandId?1:0,flags.commandIdValid?1:0,
25
+ flags.hasRequesterId?1:0,flags.requesterIdValid?1:0,flags.hasSessionId?1:0,flags.sessionIdValid?1:0,
26
+ flags.hasTimestamp?1:0,flags.timestampValid?1:0,flags.hasNonce?1:0,flags.nonceValid?1:0,
27
+ flags.hasRequires?1:0,flags.requiresValid?1:0,flags.hasPayload?1:0,
28
+ flags.hasPayloadAdapter?1:0,flags.payloadAdapterValid?1:0,flags.hasSignature?1:0,
29
+ flags.hasSignatureAlg?1:0,flags.signatureAlgValid?1:0,flags.hasSignatureKeyId?1:0,
30
+ flags.hasSignatureSig?1:0,flags.signatureSigValid?1:0,flags.hasRisk?1:0,flags.riskValid?1:0,
31
+ flags.cmdTimestamp>>>0,flags.nowSec>>>0,flags.maxClockSkewSec>>>0,
32
+ flags.keyIdFormatValid?1:0,flags.keyFound?1:0,flags.keyNotDeprecated?1:0,
33
+ flags.keyRequesterMatches?1:0,flags.keyNotBeforeOk?1:0,flags.keyNotExpired?1:0,
34
+ flags.keyLifecycleFieldsPresent?1:0,flags.signatureValid?1:0,
35
+ flags.rateLimitOk?1:0,flags.rateLimitRetryAfterSec>>>0,flags.nonceOk?1:0,
36
+ flags.policyConfigured?1:0,flags.requesterConfigured?1:0,flags.commandAllowed?1:0,
37
+ flags.adapterAllowed?1:0,flags.filesystemRequired?1:0,flags.filesystemRootsDefined?1:0,
38
+ flags.filesystemOk?1:0,flags.pathDenied?1:0,flags.shellRequired?1:0,flags.shellCommandOk?1:0,
39
+ ]);
40
+ wasm().exports.lbe_validate_pipeline();
41
+ let{stage,code}=readPipeOut(),ok=stage===255;
42
+ return{ok,stage,stageLabel:PIPELINE_STAGES[stage]||'unknown',code,
43
+ schemaError:stage===0?(SCHEMA_MSGS[code]?.error||'Schema invalid'):null,
44
+ keyReason:stage===2?(KEY_REASONS[code]||'KEY_ERROR'):null,
45
+ policyResult:stage===6?{...(POLICY_MSGS[code]||POLICY_MSGS[1]),code}:null,
46
+ retryAfterSec:stage===4?code:0,skewSec:stage===1?code:0}
47
+ }
48
+ export function checkNonce({ttlSec,nowSec,newKey,existingEntries}){
49
+ writeIn([`${ttlSec}:${nowSec}`,newKey,...existingEntries].join('\n')+'\n');
50
+ let isReplay=wasm().exports.lbe_nonce_check()!==0;
51
+ if(isReplay)return{ok:false,updatedEntriesText:null};
52
+ let out=readOut();
53
+ return{ok:true,updatedEntriesText:out.startsWith('OK\n')?out.slice(3):out}
54
+ }
55
+ export function checkRateLimit({windowSec,maxRequests,nowSec,requesterId,existingEntries}){
56
+ writeIn([`${windowSec}:${maxRequests}:${nowSec}`,requesterId,...existingEntries].join('\n')+'\n');
57
+ let exceeded=wasm().exports.lbe_rate_check()!==0,out=readOut();
58
+ if(exceeded){let r=parseInt(out.match(/^EXCEEDED:(\d+)/)?.[1]??'1',10);return{ok:false,retryAfterSec:r,updatedEntriesText:out.replace(/^EXCEEDED:\d+\n/,'')}}
59
+ return{ok:true,retryAfterSec:0,updatedEntriesText:out.startsWith('OK\n')?out.slice(3):out}
60
+ }
61
+ export function computeAuditHash(prevHash,entryJson){
62
+ let enc=new TextEncoder();writeInBin(enc.encode(prevHash),enc.encode(entryJson));
63
+ wasm().exports.lbe_audit_hash();return readOut().slice(0,64)
64
+ }
65
+ export function classifyRisk(commandId,shellCmdIsRm=false){
66
+ return RISK_LABELS[wasm().exports.lbe_classify_risk(CMD_TYPE[commandId]??0,shellCmdIsRm?1:0)]??'LOW'
67
+ }
68
+ export function shouldRollback({execFailed,postCheckFailed,backupExists,rollbackEnabled}){
69
+ return wasm().exports.lbe_rollback_decision(execFailed?1:0,postCheckFailed?1:0,backupExists?1:0,rollbackEnabled?1:0)===1
70
+ }
71
+ export function evaluatePolicyDecision(input){
72
+ let c=wasm().exports.lbe_policy_decision(input.policyConfigured?1:0,input.requesterConfigured?1:0,input.commandAllowed?1:0,input.adapterAllowed?1:0,input.filesystemRequired?1:0,input.filesystemRootsDefined?1:0,input.filesystemOk?1:0,input.pathDenied?1:0,input.shellRequired?1:0,input.shellCommandOk?1:0);
73
+ return{...(POLICY_MSGS[c]||POLICY_MSGS[1]),code:c}
74
+ }
75
+ export function evaluateSchemaDecision(input){
76
+ let c=wasm().exports.lbe_schema_decision(input.hasId?1:0,input.idValid?1:0,input.hasCommandId?1:0,input.commandIdValid?1:0,input.hasRequesterId?1:0,input.requesterIdValid?1:0,input.hasSessionId?1:0,input.sessionIdValid?1:0,input.hasTimestamp?1:0,input.timestampValid?1:0,input.hasNonce?1:0,input.nonceValid?1:0,input.hasRequires?1:0,input.requiresValid?1:0,input.hasPayload?1:0,input.hasPayloadAdapter?1:0,input.payloadAdapterValid?1:0,input.hasSignature?1:0,input.hasSignatureAlg?1:0,input.signatureAlgValid?1:0,input.hasSignatureKeyId?1:0,input.hasSignatureSig?1:0,input.signatureSigValid?1:0,input.hasRisk?1:0,input.riskValid?1:0);
77
+ return{...(SCHEMA_MSGS[c]||SCHEMA_MSGS[10]),code:c}
78
+ }