import { PLANES, parseAddress } from './subjects.js'; /** * Default-deny. Each access plane may only touch listed internal prefixes. * Internal workers (poller, WORM, account-balance) are not planes; they * already sit on the private bus. This policy gates *ingress*. */ export const POLICY = Object.freeze({ zapier: { title: 'Zapier Platform (HTTPS only; never a NATS client)', allow: [ 'verae.zapier.jobs.watch', 'verae.zapier.jobs.events', 'verae.zapier.webhooks.deliver', 'verae.billing.usage.recorded', ], }, web: { title: 'Direct customer web (portal browser)', allow: [ 'verae.billing.statement.get', 'verae.billing.balance.adjust', 'verae.billing.payment.recorded', ], adjustKinds: ['payment', 'reload'], }, api: { title: 'Direct customer API (x-api-key, not Zapier)', allow: ['verae.billing.statement.get', 'verae.billing.usage.recorded', 'verae.zapier.jobs.watch'], }, leaf: { title: 'Server-to-server NATS leaf / mTLS', allow: [ 'verae.archive.put', 'verae.archive.query', 'verae.archive.reply.', 'verae.zapier.jobs.watch', 'verae.zapier.jobs.events', 'verae.zapier.webhooks.deliver', ], }, staff: { title: 'CS / sales / admin / accounting web', allow: [ 'verae.billing.statement.get', 'verae.billing.balance.get', 'verae.billing.balance.adjust', 'verae.billing.credit.applied', 'verae.billing.payment.recorded', ], }, }); function prefixAllowed(allow, subject) { return allow.some((p) => (p.endsWith('.') ? subject.startsWith(p) : subject === p || subject.startsWith(`${p}.`))); } /** * @param {{ plane: string, subject: string, kind?: string, principal?: string }} req */ export function authorize(req) { const plane = String(req?.plane || ''); const parsed = parseAddress(req?.subject, plane); if (parsed.authz) { return deny(plane, req?.subject, 'authz subjects are not forwardable'); } if (!PLANES.includes(plane)) { return deny(plane, parsed.internal, `unknown access plane`); } if (parsed.plane && parsed.plane !== plane) { return deny(plane, parsed.internal, `plane mismatch (address is ${parsed.plane})`); } const internal = parsed.internal; if (!internal.startsWith('verae.') || internal.startsWith('verae.access.')) { return deny(plane, internal, 'not an internal verae.* subject'); } const rule = POLICY[plane]; if (!prefixAllowed(rule.allow, internal)) { return deny(plane, internal, `${plane} cannot reach ${internal}`); } if (internal === 'verae.billing.balance.adjust' && rule.adjustKinds) { const kind = req?.kind || req?.payload?.kind; if (kind && !rule.adjustKinds.includes(kind)) { return deny(plane, internal, `${plane} cannot adjust kind=${kind}`); } } return { allow: true, plane, subject: internal, principal: req?.principal || null, veraeUserId: req?.veraeUserId || req?.payload?.veraeUserId || null, traceId: req?.traceId || req?.payload?.traceId || null, reason: 'ok', }; } function deny(plane, subject, reason) { return { allow: false, plane: plane || null, subject: subject || null, reason }; }