'use strict'; const {createPublicKey,createHash,randomBytes}=require('node:crypto'); const {assertPolicyAssignment}=require('../browser/policy-assignment.cjs'); class PolicyAuthorityError extends Error { constructor(code){super(code);this.name='PolicyAuthorityError';this.code=code;} } function freeze(value){if(value&&typeof value==='object'){for(const item of Object.values(value))freeze(item);Object.freeze(value);}return value;} /** Trusted bootstrap pins enrollment key/device/minimum version. No policy * enabling, network requests or fixture classifiers are performed here. * Persist the accepted minimum version in protected enrollment storage when * wiring production; this instance cannot supply durable anti-rollback alone. */ async function createPolicyAuthority({publicKey,deviceId,minimumVersion=0}) { let pinned; try { if(typeof publicKey!=='string'||publicKey.length>16384||typeof deviceId!=='string'||!/^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/.test(deviceId)||!Number.isSafeInteger(minimumVersion)||minimumVersion<0)throw Error('invalid'); pinned=createPublicKey(publicKey).export({type:'spki',format:'pem'}); } catch {throw new PolicyAuthorityError('policy-bootstrap-invalid');} const {verifyPolicy}=await import('../../packages/core/policy.mjs'); const namespace=randomBytes(16).toString('hex'); let generation=0,active=null,floor=minimumVersion,lastDigest=null,lastVersion=null; const revoke=()=>{generation++;active=null;}; const current=token=>typeof token==='string'&&active!==null&&token===active.token&&Date.parse(active.policy.expiresAt)>Date.now(); function accept(envelope) { try { if(!envelope||typeof envelope!=='object'||Array.isArray(envelope)||Object.keys(envelope).sort().join(',')!=='payload,signature'||typeof envelope.payload!=='string'||!envelope.payload||envelope.payload.length>2097152||!/^[A-Za-z0-9_-]+$/.test(envelope.payload)||typeof envelope.signature!=='string'||!envelope.signature||envelope.signature.length>16384||!/^[A-Za-z0-9_-]+$/.test(envelope.signature))throw Error('invalid-envelope'); const policy=assertPolicyAssignment(verifyPolicy({payload:envelope.payload,signature:envelope.signature},pinned,floor),deviceId); const digest=createHash('sha256').update(envelope.payload).digest('hex'); if(lastVersion===policy.version&&lastDigest!==digest)throw Error('version-equivocation'); generation++;floor=policy.version;lastVersion=policy.version;lastDigest=digest; active=Object.freeze({token:`${namespace}:${generation}`,generation,version:policy.version,policy:freeze(policy)}); return active; } catch {revoke();throw new PolicyAuthorityError('policy-rejected');} } return Object.freeze({accept,current,revoke,snapshot:()=>active&¤t(active.token)?active:null,status:()=>Object.freeze({generation,minimumVersion:floor,active:active!==null&¤t(active.token)})}); } module.exports={createPolicyAuthority,PolicyAuthorityError};