import {generateKeyPairSync} from 'node:crypto'; import channel from '../../packages/core/policy-channel.cjs'; export function installPolicyChannel(app,store,device){ let keys=store.get('channelSigningKeys'); if(!keys){const pair=generateKeyPairSync('ml-dsa-87');keys={privateKey:pair.privateKey.export({type:'pkcs8',format:'pem'}),publicKey:pair.publicKey.export({type:'spki',format:'pem'})};store.put('channelSigningKeys',keys);} const ed=store.get('keys').privateKey,identity=channel.identity(ed,keys.privateKey,keys.publicKey),pending=new Map(); app.get('/api/device/channel/identity',device,(_req,res)=>res.json(identity)); app.post('/api/device/channel/challenge',device,(req,res)=>{ for(const [id,item] of pending)if(item.bundle.expiresAt<=Date.now()||item.bundle.deviceId===req.device.id)pending.delete(id); if(pending.size>=10000)return res.status(503).json({error:'Protected management channel unavailable'}); const item=channel.challenge(req.device.id,ed,keys.privateKey);pending.set(item.bundle.id,item);res.json(item.bundle); }); app.post('/api/device/channel/policy',device,(req,res)=>{ const item=pending.get(req.body?.id); if(!item||item.bundle.deviceId!==req.device.id)return res.status(403).json({error:'Protected management channel refused'}); // Consume before processing: every challenge is one use, including failed ciphertext. pending.delete(item.bundle.id);let context; try{context=channel.receive(req.body,item.bundle,item.privateKey);res.json(channel.response(store.envelope(req.device.id),item.bundle,context));} catch{return res.status(403).json({error:'Protected management channel refused'});} finally{context?.responseKey.fill(0);} }); return identity; }