import { did } from "./did.js"; import { agreement } from "./agreement.js"; import { event } from "./event.js"; import { audit } from "./audit.js"; import { data } from "./data/index.js"; import { archive } from "./archive.js"; import { trackUsage } from "./usage.js"; import { getConfig } from "../../common/config.js"; import { dashboard } from "../dashboard/index.js"; import { evaluate } from "../pep/index.js"; // The event/agreement UUIDs a request touched, so a usage row can link back to // them. Checks the known request/response shapes in priority order; non-core // calls (DID ops, etc.) have neither and fall through to null. function pickUsageIds(input, response) { const eventId = input?.eventId ?? response?.eventId ?? response?.event?.eventId ?? response?.created?.eventId ?? null; const agreementId = input?.agreementId ?? response?.agreementId ?? response?.agreement?.agreementId ?? response?.event?.agreementId ?? response?.created?.agreementId ?? null; return { eventId, agreementId }; } async function post(req, res) { let response = { success: false, error: 'Unknown error', }; let errorCode = 400; let type; const prefix = `${req.method} ${req.url}`; let evaluation = false; try { const input = req.body; if (input.auth) { evaluation = await evaluate(input.auth); } else { evaluation = true; } const config = getConfig(); if (Object.keys(config.appModules).includes('core')) { switch (req.url) { case '/api/v1/auth': evaluation = await evaluate(input); if (evaluation) response = { data: { decision: true }, message: 'Authorization allowed' }; type = 'core'; break; case '/api/v1/did/create': if (evaluation) response = await did.create(input); type = 'core'; break; case '/api/v1/did/rotate': if (evaluation) response = await did.rotate(input); type = 'core'; break; case '/api/v1/did/updateServices': if (evaluation) response = await did.updateServices(input); type = 'core'; break; case '/api/v1/did/send': if (evaluation) response = await did.send(input); type = 'core'; break; case '/api/v1/did/resolve': if (evaluation) response = await did.resolve(input); type = 'core'; break; case '/api/v1/agreement/create': if (evaluation) response = await agreement.create(input); type = 'core'; break; case '/api/v1/agreement/sign': if (evaluation) response = await agreement.sign(input); type = 'core'; break; case '/api/v1/agreement/send': if (evaluation) response = await agreement.send(input); type = 'core'; break; case '/api/v1/event/create': if (evaluation) response = await event.create(input); type = 'core'; break; case '/api/v1/event/sign': if (evaluation) response = await event.sign(input); type = 'core'; break; case '/api/v1/event/send': if (evaluation) response = await event.send(input); type = 'core'; break; case '/api/v1/audit/create': if (evaluation) response = await audit.create(input); type = 'core'; break; case '/api/v1/audit/sign': if (evaluation) response = await audit.sign(input); type = 'core'; break; case '/api/v1/audit/send': if (evaluation) response = await audit.send(input); type = 'core'; break; case '/api/v1/data/entity/get': if (evaluation) response = await data.entity.get(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/entity/domains/get': if (evaluation) response = await data.entity.getDomains(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/entity/create': if (evaluation) response = await data.entity.create(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/agreement/get': if (evaluation) response = await data.agreement.get(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/agreement/create': if (evaluation) response = await data.agreement.create(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/agreement/process': if (evaluation) response = await data.agreement.process(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/agreement/produce': if (evaluation) response = await data.agreement.produce(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/event/get': if (evaluation) response = await data.event.get(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/event/create': if (evaluation) response = await data.event.create(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/event/process': if (evaluation) response = await data.event.process(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/event/produce': if (evaluation) response = await data.event.produce(input, req.session.user_id); type = 'core'; break; case '/api/v1/data/audit/verify': if (evaluation) response = await data.audit.verify(input, req.session.user_id); type = 'core'; break; } if (Object.keys(config.appModules).includes('archive')) { switch (req.url) { case '/api/v1/audit/put': if (evaluation) response = await archive.put(input); type = 'archive'; break; case '/api/v1/audit/get': if (evaluation) response = await archive.get(input); type = 'archive'; break; } } } // Dashboard is its own app module: read-only console data, dispatched // separately from core and typed 'dashboard' so it never counts as usage. if (evaluation && !type && Object.keys(config.appModules).includes('dashboard')) { const dashboardResponse = await dashboard.dispatch(req.url, input, req.session.user_id); if (dashboardResponse) { response = dashboardResponse; type = 'dashboard'; } } if (evaluation && !type) { response.error = 'Page not found'; errorCode = 404; } } catch (e) { console.error(e); response.error = e.message; } finally { if (evaluation) { if (response?.message) { req.apiMessage = response.message; } else if (response?.data?.error) { req.apiMessage = `ERROR: ${response.data.error}`; } else { req.apiMessage = `ERROR: unknown error`; } if (response?.data) response = response.data; res.status(response?.error ? errorCode : 200).json(response); } else { response = { data: { decision: false }, message: 'Authorization denied' } req.apiMessage = response.message; res.status(200).json(response.data); } // Dashboard calls are console reads, not billable API usage — don't track them. if (type !== 'dashboard') { const { eventId, agreementId } = pickUsageIds(req.body, response); await trackUsage(req.session.user_id, req.url, type, response?.error ? false : true, eventId, agreementId); } } } export const core = { did, agreement, event, audit, archive, post, };