addition of new dashboard

This commit is contained in:
2026-08-20 15:08:32 +00:00
parent 0622018d95
commit bf59249ed7
161 changed files with 13170 additions and 119 deletions

View File

@@ -0,0 +1,259 @@
import { getPool } from "../../../db/index.js";
import { agreement } from "./agreement.js";
import { event } from "./event.js";
import { stringify, configure } from "safe-stable-stringify";
import { createHash } from "crypto";
import { entity } from "./entity.js";
import sodium from "sodium-native";
function splitJws(jws) {
const sections = jws.split('.');
if (sections.length !== 3) {
throw ('Input must be a JWS.');
}
const jwt = JSON.parse(Buffer.from(sections[0], 'base64url').toString());
if (jwt.alg !== 'EdDSA') {
throw ('JWT does not indicate EdDSA');
}
const payload = JSON.parse(Buffer.from(sections[1], 'base64url').toString());
const wasSigned = Buffer.from(sections[0] + '.' + sections[1]);
const signature = Buffer.from(sections[2], 'base64url');
return {
jwt,
payload,
wasSigned,
signature,
}
}
function verifyJws(input) {
let ret = false;
try {
if (!input.jws) {
throw ('No JWS provided.');
}
if (!input.publicKey) {
throw ('No publicKey provided.');
}
const publicKey = Buffer.from(input.publicKey, 'base64url');
if (publicKey.length !== sodium.crypto_sign_PUBLICKEYBYTES) {
throw ('publicKey length must be crypto_sign_PUBLICKEYBYTES (32).');
}
const providedPublicKey = Buffer.from(input.jws.jwt.jwk.x, 'base64url');
if (publicKey.compare(providedPublicKey) !== 0) {
ret = false;
} else {
ret = sodium.crypto_sign_verify_detached(input.jws.signature, input.jws.wasSigned, Buffer.from(input.publicKey, 'base64url'));
}
} catch (e) {
console.error(e);
}
return ret;
};
function validateSignatures(item, signatures, didDocs) {
let res = false;
try {
for (const signature of signatures) {
const didDoc = didDocs.find((didDoc) => didDoc.id === signature.id);
if (!didDoc) throw ('DID Document not provided');
const vmCreatedDate = new Date(didDoc.verificationMethod[0].created);
const signDate = new Date(signature.signedOn)
const vmDeactivatedDate = didDoc.verificationMethod[0].deactivated ? new Date(didDoc.verificationMethod[0].deactivated) : null;
const validDate = signDate >= vmCreatedDate && (!vmDeactivatedDate || vmDeactivatedDate >= signDate);
if (!validDate) throw ('Signature is not valid due to key dates');
const split = splitJws(signature.jws);
if (stringify(item) !== stringify(split.payload)) throw ('Payload does not match');
const validJws = verifyJws({
jws: split,
publicKey: didDoc.verificationMethod[0].key,
});
if (!validJws) throw ('Signature is not valid');
res = true;
}
} catch (e) {
console.error(e);
}
return res;
}
function validateSignedBefore(item, signatures) {
let res = false;
try {
let issue = false;
for (const signature of signatures) {
if (signature.signedOn >= item.created) {
issue = true;
break;
}
}
res = !issue;
} catch (e) {
console.error(e);
}
return res;
}
function validateDidsMatch(auditSigs, targetSigs) {
let match = true;
for (const asig of auditSigs) {
let found = false;
for (const tsig of targetSigs) {
if (tsig.id === asig.id) {
found = true;
break;
}
}
if (!found) {
match = false;
}
}
return match;
}
function generateDigest(content, length) {
if (typeof content === 'object') {
content = stringify(content);
}
const hash = createHash('sha256')
.update(content)
.digest('hex')
.slice(0, length);
return hash;
}
async function verify(input, userId) {
let response = {
success: false,
error: 'Unknown error',
};
const client = await getPool();
try {
const data = {
valid: [],
invalid: [],
};
if (!input.didDocs) {
input.didDocs = [];
for (const shortName of input.shortNames || []) {
input.didDocs.push((await entity.getEntity(client, userId, shortName)).didDoc)
}
}
delete input.shortNames;
const organizedById = [];
for (const item of input.audits) {
const found = organizedById.find((obi) =>
item.audit.agreementId && obi.agreementId === item.audit.agreementId ||
item.audit.eventId && obi.eventId === item.audit.eventId
);
if (!found) {
const newItem = item.audit.agreementId
? {
agreementId: item.audit.agreementId,
auditRecords: [item],
}
: {
eventId: item.audit.eventId,
auditRecords: [item],
}
organizedById.push(newItem)
} else {
found.auditRecords.push(item);
}
}
for (const item of organizedById) {
const existingItem = item.eventId
? await event.getEvent(client, userId, item.eventId, true)
: await agreement.getAgreement(client, userId, item.agreementId)
const existingSignatures = item.eventId
? await event.getSignatures(client, userId, item.eventId)
: await agreement.getSignatures(client, userId, item.agreementId)
// Does the agreement/event signature verify?
let validSignature = false;
if (validateSignatures(existingItem, existingSignatures, input.didDocs)) {
validSignature = true;
}
for (const auditRecord of item.auditRecords) {
const res = {
audit: auditRecord,
results: {
validId: false,
validSignature,
validAuditHash: false,
validAuditSignature: false,
}
}
// Do the agreement/event IDs match?
if (
(item.agreementId !== null && auditRecord.audit.agreementId === item.agreementId) ||
(item.eventId !== null && auditRecord.audit.eventId === item.eventId)
)
res.results.validId = true;
// Do DID IDs match between audit and target object?
res.results.validMatchingDids = validateDidsMatch(auditRecord.signatures, existingSignatures);
// Does the audit hash match?
// The digest was created from whichever signatures this audit record has
const signatures = [];
for (const s of auditRecord.signatures) {
const existingSignature = existingSignatures.find((es) => es.id === s.id);
if (existingSignature) {
signatures.push(existingSignature)
}
}
const check = item.eventId
? {
event: existingItem,
signatures,
}
: {
agreement: existingItem,
signatures,
}
const digest = generateDigest(check);
if (digest === auditRecord.audit.digest)
res.results.validAuditHash = true;
// Does the audit signature verify?
if (validateSignatures(auditRecord.audit, auditRecord.signatures, input.didDocs)) {
res.results.validAuditSignature = true;
}
const isValid =
res.results.validId === true &&
res.results.validSignature === true &&
res.results.validAuditHash === true &&
res.results.validAuditSignature === true;
if (isValid) {
data.valid.push(res);
} else {
data.invalid.push(res);
}
// If an event, has the DID signed the agreement and is that signature valid?
if (existingItem.eventId !== null && existingItem.agreementId !== '00000000-0000-0000-0000-000000000000') {
const existingAgreement = await agreement.getAgreement(client, userId, existingItem.agreementId);
const existingAgreementSignatures = await agreement.getSignatures(client, userId, existingItem.agreementId);
res.results.validEventAgreement = validateDidsMatch(auditRecord.signatures, existingAgreementSignatures);
res.results.validEventAgreementSignature = false;
if (validateSignatures(existingAgreement, existingAgreementSignatures, input.didDocs) && validateSignedBefore(existingItem, existingAgreementSignatures)) {
res.results.validEventAgreementSignature = true;
}
} else {
res.results.validEventAgreement = true;
res.results.validEventAgreementSignature = true;
}
}
}
response = {
message: 'validation complete',
data,
};
} catch (e) {
console.error(e)
} finally {
await client.release();
}
return response;
}
export const audit = {
verify,
}