Files
jlinc-server/backend/modules/core/index.js
2026-08-20 15:08:32 +00:00

236 lines
9.4 KiB
JavaScript

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,
};