From 1fee6760d6cf39d471510edaa9465abbad850c28 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:23:28 +0200 Subject: [PATCH 1/4] extend VerifiableCredentialEntity with sigCount and instanceId counters for batch issuance scenarios --- src/entities/VerifiableCredential.entity.ts | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/entities/VerifiableCredential.entity.ts b/src/entities/VerifiableCredential.entity.ts index b316bbb..c990a0f 100644 --- a/src/entities/VerifiableCredential.entity.ts +++ b/src/entities/VerifiableCredential.entity.ts @@ -28,6 +28,12 @@ export class VerifiableCredentialEntity { @Column({ type: "varchar", nullable: false, default: "" }) credentialIssuerIdentifier: string = ""; + + @Column({ type: "smallint", nullable: false, default: 0 }) + instanceId: number = 0; + + @Column({ type: "smallint", nullable: false, default: 0 }) + sigCount: number = 0; } @@ -68,6 +74,24 @@ async function createVerifiableCredential(createVc: Partial) { + try { + console.log("Updating VC...") + await AppDataSource + .createQueryBuilder() + .update(VerifiableCredentialEntity) + .set({ ...credential }) + .where("credentialIdentifier = :cred_id and instanceId = :instance_id", { cred_id: credential.credentialIdentifier, instance_id: credential.instanceId }) + .execute(); + return Ok({}); + } + catch(e) { + console.log(e); + return Err(CreateVerifiableCredentialErr.DB_ERR); + } +} + async function deleteVerifiableCredential(holderDID:string, credentialId: string) { try { console.log("Deleting VPs containing the VC", credentialId); @@ -162,6 +186,7 @@ export { DeleteVerifiableCredentialErr, getAllVerifiableCredentials, createVerifiableCredential, + updateVerifiableCredential, deleteVerifiableCredential, getVerifiableCredentialByCredentialIdentifier, deleteAllCredentialsWithHolderDID From 7194cc29da62d7001a14ead04dcc2d9f1c822d9f Mon Sep 17 00:00:00 2001 From: kkmanos Date: Mon, 18 Nov 2024 14:24:04 +0200 Subject: [PATCH 2/4] storeCredentials in batch and export the update credential endpoint --- src/routers/storage.router.ts | 56 +++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/src/routers/storage.router.ts b/src/routers/storage.router.ts index 3af8db9..ad4a222 100644 --- a/src/routers/storage.router.ts +++ b/src/routers/storage.router.ts @@ -1,5 +1,5 @@ import express, { Request, Response, Router } from "express"; -import { getAllVerifiableCredentials, getVerifiableCredentialByCredentialIdentifier, deleteVerifiableCredential, createVerifiableCredential } from "../entities/VerifiableCredential.entity"; +import { getAllVerifiableCredentials, getVerifiableCredentialByCredentialIdentifier, deleteVerifiableCredential, createVerifiableCredential, updateVerifiableCredential, VerifiableCredentialEntity } from "../entities/VerifiableCredential.entity"; import { createVerifiablePresentation, deletePresentationsByCredentialId, getAllVerifiablePresentations, getPresentationByIdentifier } from "../entities/VerifiablePresentation.entity"; import { sendPushNotification } from "../lib/firebase"; import { getUser } from "../entities/user.entity"; @@ -7,7 +7,9 @@ import { getUser } from "../entities/user.entity"; const storageRouter: Router = express.Router(); -storageRouter.post('/vc', storeCredential); +storageRouter.post('/vc', storeCredentials); +storageRouter.post('/vc/update', updateCredential); + storageRouter.get('/vc', getAllVerifiableCredentialsController); storageRouter.get('/vc/:credential_identifier', getVerifiableCredentialByCredentialIdentifierController); storageRouter.delete('/vc/:credential_identifier', deleteVerifiableCredentialController); @@ -16,20 +18,23 @@ storageRouter.get('/vp', getAllVerifiablePresentationsController); storageRouter.get('/vp/:presentation_identifier', getPresentationByPresentationIdentifierController); -async function storeCredential(req: Request, res: Response) { - createVerifiableCredential({ - holderDID: req.user.did, - issuanceDate: new Date(), - ...req.body, - }).then(async () => { - // inform all installed instances of the wallet that a credential has been received - - const u = await getUser(req.user.id); - if (u.err) { - return res.send({}); - } +async function storeCredentials(req: Request, res: Response) { + const u = await getUser(req.user.id); + if (u.err) { + return res.status(400).send({ error: "Unauthenticated user" }); + } + const user = u.unwrap(); - const user = u.unwrap(); + if (!req.body.credentials || !(req.body.credentials instanceof Array)) { + return res.status(400).send({ error: "Missing or invalid 'credentials' body param" }); + } + Promise.all(req.body.credentials.map(async (storableCredential) => { + createVerifiableCredential({ + holderDID: req.user.did, + issuanceDate: new Date(), + ...storableCredential, + }); + })).then(() => { if (user.fcmTokenList) { for (const fcmToken of user.fcmTokenList) { sendPushNotification(fcmToken.value, "New Credential", "A new verifiable credential is in your wallet").catch(err => { @@ -38,10 +43,29 @@ async function storeCredential(req: Request, res: Response) { }); } } - }) + }); res.send({}); } +async function updateCredential(req: Request, res: Response) { + try { + const u = await getUser(req.user.id); + if (u.err) { + return res.status(400).send({ error: "Unauthenticated user" }); + } + const user = u.unwrap(); + if (!req.body.credential) { + return res.status(400).send({ error: "Missing or invalid 'credential' body param" }); + } + await updateVerifiableCredential(req.body.credential); + return res.status(200).send({}); + } + catch(err) { + console.error(err); + return res.status(400).send({ error: JSON.stringify(err) }); + } +} + async function getAllVerifiableCredentialsController(req: Request, res: Response) { const holderDID = req.user.did; console.log("Holder did", holderDID) From fb2891f142a999d92010fc1b324570629059a066 Mon Sep 17 00:00:00 2001 From: kkmanos Date: Wed, 20 Nov 2024 11:44:42 +0200 Subject: [PATCH 3/4] formatting fix --- src/routers/storage.router.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routers/storage.router.ts b/src/routers/storage.router.ts index ad4a222..c4bdc5b 100644 --- a/src/routers/storage.router.ts +++ b/src/routers/storage.router.ts @@ -57,10 +57,10 @@ async function updateCredential(req: Request, res: Response) { if (!req.body.credential) { return res.status(400).send({ error: "Missing or invalid 'credential' body param" }); } - await updateVerifiableCredential(req.body.credential); + await updateVerifiableCredential(req.body.credential); return res.status(200).send({}); } - catch(err) { + catch (err) { console.error(err); return res.status(400).send({ error: JSON.stringify(err) }); } From cdf14f53d5f6457ed9585d591c9b9f2511ab4dcd Mon Sep 17 00:00:00 2001 From: kkmanos Date: Fri, 22 Nov 2024 14:29:12 +0200 Subject: [PATCH 4/4] changed UserEntity.privateData column datatype from blob to mediumblob --- src/entities/user.entity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/user.entity.ts b/src/entities/user.entity.ts index ea0d077..494502a 100644 --- a/src/entities/user.entity.ts +++ b/src/entities/user.entity.ts @@ -107,7 +107,7 @@ class UserEntity { @Column({ type: "bool", default: false }) isAdmin: boolean = false; - @Column({ type: "blob", nullable: false }) + @Column({ type: "mediumblob", nullable: false }) privateData: Buffer;