'use strict'; const {createHash,createPublicKey}=require('node:crypto'); const {TextDecoder}=require('node:util'); const {verifyServiceAcceptance}=require('./service-acceptance.cjs'); const {createServiceStoreClient}=require('./service-store-client.cjs'); const {createDnsPolicyRoute,assertSupportedDns}=require('./dns-policy-route.cjs'); const {createHttpsForwarder}=require('./https-forwarder.cjs'); const {createProxyForwarder}=require('./proxy-forwarder.cjs'); const {deploymentRoots}=require('./production-factory.cjs'); const {createWorkAdmission}=require('./work-admission.cjs'); const channel=require('../../packages/core/policy-channel.cjs'); const refused=()=>Error('broker-management-refused'); // The fixed native loader supplies device credentials from protected storage; // injected loaders are explicit trusted test/service adapters, never IPC fields. // There is no URL, token, method, header, file path or general fetch IPC surface. // Enrollment is deliberately unavailable until its own authenticated bootstrap // contract exists. Only an already durably accepted policy may use this leg. async function createManagementIdentityOperation({store=createServiceStoreClient(),policyEnvelope,loadCredential,credentialLoader,current,network,deadlineMs=10000}={}){ let authority,ownedLoader; try{ if(credentialLoader){if(loadCredential!==undefined||typeof credentialLoader.load!=='function')throw refused();loadCredential=credentialLoader.load.bind(credentialLoader);} if(loadCredential!==undefined&&typeof loadCredential!=='function'||typeof current!=='function'||!Number.isSafeInteger(deadlineMs)||deadlineMs<1||deadlineMs>30000)throw refused(); const snapshot=await store.snapshot(),files=await store.envelopes(); const plan=await verifyServiceAcceptance({...files,state:snapshot.acceptanceState,releaseAnchor:snapshot.releaseAnchor,authenticatedSid:snapshot.authenticatedSid,policyEnvelope}); if(plan.nextStateDigest!==plan.previousStateDigest)throw refused(); const {verifiedManagementBinding}=require('../../packages/core/windows-trust.cjs'),binding=verifiedManagementBinding(plan.deployment); const {createPolicyAuthority}=require('./policy-authority.cjs');authority=await createPolicyAuthority(plan.bootstrap);const accepted=authority.accept(policyEnvelope),policy=accepted.policy; const active=()=>{try{return current()===true&&authority.current(accepted.token)&&Date.now()!['mode','dns','ca','proxyCa','credentials'].includes(k)))throw refused(); assertSupportedDns(policy,network,{numericOriginSupported:true}); const security=await import('../../packages/core/security.mjs'),resolve=createDnsPolicyRoute({current:active,blocked:a=>security.dnsAddressBlocked(a,policy)}); const transport={authority:accepted.token,current:active,ca:deploymentRoots(network.ca)?.join('\n'),deadlineMs,maxRequestBytes:16384,maxResponseBytes:5242880}; const forward=network.mode==='fixed_servers'?createProxyForwarder({...transport,proxyPolicy:policy.proxy,proxyCa:deploymentRoots(network.proxyCa)?.join('\n'),credentials:network.credentials,resolveProxyRoute:resolve,resolveOriginRoute:policy.security?.dns?.enabled!==false&&policy.security?.dns?.blockedIPs?.length?resolve:undefined}):network.mode==='direct'?createHttpsForwarder({...transport,resolveRoute:resolve}):(()=>{throw refused();})(); let closing;const originals=new Set(),jobs=createWorkAdmission({maxJobs:1}),controllers=new Set(),credentialBinding=Object.freeze({origin:binding.origin,deviceId:plan.bootstrap.deviceId,policyVersion:plan.policyVersion,policyDigest:plan.policyDigest,policyKeySha256:createHash('sha256').update(createPublicKey(plan.bootstrap.publicKey).export({type:'spki',format:'der'})).digest('hex')}); if(loadCredential===undefined){const {createNativeManagementCredentialLoader}=require('./management-credential.cjs');ownedLoader=createNativeManagementCredentialLoader({expectedBinding:credentialBinding,current:active,deadlineMs});loadCredential=ownedLoader.load;} const close=()=>{if(closing)return closing;authority.revoke();jobs.close();for(const controller of controllers)controller.abort();closing=Promise.allSettled([...originals,ownedLoader?.close()]).then(()=>undefined);return closing;}; const operation=async(kind,input)=>{ if(input!==undefined||!active())throw refused(); const controller=new AbortController();controllers.add(controller);let timer; const cancelled=new Promise((_,reject)=>{controller.signal.addEventListener('abort',()=>reject(refused()),{once:true});timer=setTimeout(()=>controller.abort(),deadlineMs);}); const work=Promise.resolve().then(()=>jobs.run(async()=>{ let credentialCopy,ownedToken,context; try{ const credential=await loadCredential(credentialBinding,{signal:controller.signal}); // Buffer credentials are private one-use leases from the protected loader, // transferred to this operation, never a reusable backing-store buffer. ownedToken=Buffer.isBuffer(credential?.token)?credential.token:undefined; if(!active()||controller.signal.aborted||!credential||Object.keys(credential).sort().join(',')!=='deviceId,origin,token'||credential.deviceId!==credentialBinding.deviceId||credential.origin!==binding.origin)throw refused(); credentialCopy=Buffer.isBuffer(credential.token)?Buffer.from(credential.token):typeof credential.token==='string'?Buffer.from(credential.token):undefined; if(!credentialCopy||credentialCopy.length<16||credentialCopy.length>4096||! /^[A-Za-z0-9._~-]+$/.test(credentialCopy.toString('utf8')))throw refused(); const request=async(route,method,body,limit)=>{if(!active()||controller.signal.aborted)throw refused();const bytes=body===undefined?Buffer.alloc(0):Buffer.from(JSON.stringify(body));let result;try{result=await forward({request:{url:binding.origin+route,method,headers:{authorization:'Bearer '+credentialCopy.toString('utf8'),...(body===undefined?{}:{'content-type':'application/json'})}},body:bytes,signal:controller.signal,maxResponseBytes:limit});if(result.statusCode!==200||!active()||controller.signal.aborted)throw refused();return JSON.parse(new TextDecoder('utf-8',{fatal:true}).decode(result.body));}finally{bytes.fill(0);result?.body.fill(0);}}; if(kind==='identity'){const identity=await request('/api/device/channel/identity','GET',undefined,20000);channel.verifyIdentity(identity,plan.bootstrap.publicKey,binding.signatureKey);if(!active())throw refused();return Object.freeze(identity);} const challenge=await request('/api/device/channel/challenge','POST',{},20000);channel.verifyChallenge(challenge,plan.bootstrap.deviceId,plan.bootstrap.publicKey,binding.signatureKey);if(!active()||controller.signal.aborted)throw refused();context=channel.prepare(challenge); const response=await request('/api/device/channel/policy','POST',context.request,5242880),envelope=channel.finish(response,challenge,context); if(!envelope||Object.keys(envelope).sort().join(',')!=='payload,signature'||typeof envelope.payload!=='string'||typeof envelope.signature!=='string')throw refused(); const core=await import('../../packages/core/policy.mjs'),next=core.verifyPolicy(envelope,plan.bootstrap.publicKey,plan.policyVersion); if(next.assignment?.deviceId!==plan.bootstrap.deviceId||next.version===plan.policyVersion&&createHash('sha256').update(envelope.payload).digest('hex')!==plan.policyDigest||!active()||controller.signal.aborted)throw refused(); // Returned policy is verified but NOT activated or durably accepted here; // the privileged policy transition must commit its new floor separately. return Object.freeze({payload:envelope.payload,signature:envelope.signature}); }catch{throw refused();}finally{credentialCopy?.fill(0);ownedToken?.fill(0);context?.responseKey.fill(0);} })); originals.add(work);work.finally(()=>originals.delete(work)).catch(()=>{}); try{return await Promise.race([work,cancelled]);}catch{throw refused();}finally{clearTimeout(timer);controllers.delete(controller);} }; return Object.freeze({close,identity:input=>operation('identity',input),policy:input=>operation('policy',input)}); }catch{authority?.revoke();await ownedLoader?.close();throw refused();} } module.exports={createManagementIdentityOperation};