Skip to content

Commit

Permalink
Update SdJwtVCDM in order to render the svg template on issuers pages
Browse files Browse the repository at this point in the history
  • Loading branch information
gkatrakazas committed Oct 8, 2024
1 parent 438e40b commit 9d41e6b
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { config } from "../../../config";
import { VerifiableCredentialFormat } from "../../types/oid4vci";
import { CategorizedRawCredentialView, CategorizedRawCredentialViewRow } from "../../openid4vci/Metadata";
import { VCDMSupportedCredentialProtocol } from "../../lib/CredentialIssuerConfig/SupportedCredentialProtocol";
import { formatDateDDMMYYYY } from "../../lib/formatDate";
import { generateDataUriFromSvg } from "../../lib/generateDataUriFromSvg";
import { AuthorizationServerState } from "../../entities/AuthorizationServerState.entity";
import { CredentialView } from "../../authorization/types";
import { issuerSigner } from "../issuerSigner";
Expand All @@ -10,14 +13,14 @@ import { parseDiplomaData } from "../datasetParser";
import path from "path";
import { randomUUID } from "crypto";
import { Request } from "express";

import fs from 'fs';

parseDiplomaData(path.join(__dirname, "../../../../dataset/diploma-dataset.xlsx"));

export class EdiplomasBlueprintSdJwtVCDM implements VCDMSupportedCredentialProtocol {


constructor() { }
constructor() { }


getId(): string {
Expand All @@ -31,60 +34,66 @@ export class EdiplomasBlueprintSdJwtVCDM implements VCDMSupportedCredentialProto
return issuerSigner;
}

getFormat(): VerifiableCredentialFormat {
return VerifiableCredentialFormat.VC_SD_JWT;
}
getTypes(): string[] {
return ["VerifiableCredential", "VerifiableAttestation", "Bachelor", this.getId()];
}
getDisplay() {
getFormat(): VerifiableCredentialFormat {
return VerifiableCredentialFormat.VC_SD_JWT;
}
getTypes(): string[] {
return ["VerifiableCredential", "VerifiableAttestation", "Bachelor", this.getId()];
}
getDisplay() {
return {
name: "Bachelor Diploma",
description: "This is a Bachelor Diploma verifiable credential issued by the well-known eDiplomas",
background_image: { uri: config.url + "/images/EuropassUoaCard.png" },
background_color: "#4CC3DD",
locale: 'en-US',
}
}
}


async getProfile(userSession: AuthorizationServerState): Promise<CredentialView | null> {
async getProfile(userSession: AuthorizationServerState): Promise<CredentialView | null> {
if (!userSession?.document_number) {
console.log("Cannot generate credential: (document_number) is missing");
return null;
}


const diplomaEntries = parseDiplomaData(path.join(__dirname, "../../../../dataset/diploma-dataset.xlsx"));
if (!diplomaEntries || diplomaEntries.length == 0) {
throw new Error("No diploma entries found");
}
const diplomaEntry = diplomaEntries.filter((diploma) =>
const diplomaEntry = diplomaEntries.filter((diploma) =>
String(diploma.vid_document_number) == userSession.document_number
)[0];
if (!diplomaEntry) {
console.error("Possibly raw data not found")
throw new Error("Could not generate credential response");
}

const credentialView: CredentialView = {
credential_id: diplomaEntry.certificateId,
credential_image: "",
credential_supported_object: this.exportCredentialSupportedObject(),
view: {
rows: [
{ name: "Given Name", value: diplomaEntry.given_name },
{ name: "Family Name", value: diplomaEntry.family_name },
{ name: "Title", value: diplomaEntry.title },
{ name: "Grade", value: diplomaEntry.grade },
{ name: "Graduation date", value: diplomaEntry.graduation_date },
{ name: "Blueprint ID", value: "#" + diplomaEntry.blueprint_id },
const svgText = fs.readFileSync(path.join(__dirname, "../../../../public/images/diplomaTemplate.svg"), 'utf-8');

]
}
};
return credentialView;
}
const credentialViews: CredentialView[] = diplomaEntries
.map((diplomaEntry) => {
const rows: CategorizedRawCredentialViewRow[] = [
{ name: "given_name", value: diplomaEntry.given_name },
{ name: "family_name", value: diplomaEntry.family_name },
{ name: "title", value: diplomaEntry.title },
{ name: "grade", value: diplomaEntry.grade },
{ name: "graduation_date", value: formatDateDDMMYYYY(diplomaEntry.graduation_date) },
{ name: "blueprint_id", value: "#" + diplomaEntry.blueprint_id },
];
const rowsObject: CategorizedRawCredentialView = { rows };
const dataUri = generateDataUriFromSvg(svgText, rows);

return {
credential_id: diplomaEntry.certificateId,
credential_supported_object: this.exportCredentialSupportedObject(),
view: rowsObject,
credential_image: dataUri,
}
})
return credentialViews[0];
}

async generateCredentialResponse(userSession: AuthorizationServerState, request: Request, holderPublicKeyJwk: JWK): Promise<{ format: VerifiableCredentialFormat; credential: any; }> {
if (!userSession?.document_number) {
Expand All @@ -95,7 +104,7 @@ export class EdiplomasBlueprintSdJwtVCDM implements VCDMSupportedCredentialProto
if (!diplomaEntries || diplomaEntries.length == 0) {
throw new Error("No diploma entries found");
}
const diplomaEntry = diplomaEntries.filter((diploma) =>
const diplomaEntry = diplomaEntries.filter((diploma) =>
String(diploma.vid_document_number) == userSession.document_number
)[0];

Expand All @@ -120,7 +129,7 @@ export class EdiplomasBlueprintSdJwtVCDM implements VCDMSupportedCredentialProto
"title": diplomaEntry.title,
"grade": String(diplomaEntry.grade),
"eqf_level": String(diplomaEntry.eqf_level),
"graduation_date": diplomaEntry.graduation_date,
"graduation_date": new Date(diplomaEntry.graduation_date).toISOString()
};

const disclosureFrame = {
Expand All @@ -133,13 +142,13 @@ export class EdiplomasBlueprintSdJwtVCDM implements VCDMSupportedCredentialProto
const { jws } = await this.getCredentialSigner()
.sign(payload, { typ: "JWT", vctm: this.metadata() }, disclosureFrame);

const response = {
format: this.getFormat(),
credential: jws
};
const response = {
format: this.getFormat(),
credential: jws
};

return response;
}
}

public metadata(): any {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { config } from "../../../config";
import { CategorizedRawCredentialView, CategorizedRawCredentialViewRow } from "../../openid4vci/Metadata";
import { VerifiableCredentialFormat } from "../../types/oid4vci";
import { VCDMSupportedCredentialProtocol } from "../../lib/CredentialIssuerConfig/SupportedCredentialProtocol";
import { formatDateDDMMYYYY } from "../../lib/formatDate";
import { generateDataUriFromSvg } from "../../lib/generateDataUriFromSvg";
import { AuthorizationServerState } from "../../entities/AuthorizationServerState.entity";
import { CredentialView } from "../../authorization/types";
import { randomUUID } from "node:crypto";
Expand All @@ -11,7 +13,7 @@ import { Request } from "express";
import { parseEhicData } from "../datasetParser";
import path from "node:path";
import { issuerSigner } from "../issuerSigner";

import fs from 'fs';

parseEhicData(path.join(__dirname, "../../../../dataset/ehic-dataset.xlsx")) // test parse

Expand Down Expand Up @@ -67,21 +69,24 @@ export class EHICSupportedCredentialSdJwtVCDM implements VCDMSupportedCredential
new Date(ehic.birth_date).toISOString() == new Date(userSession.birth_date as string).toISOString()
);
console.log("Ehic = ", ehics)
const svgText = fs.readFileSync(path.join(__dirname, "../../../../public/images/ehicTemplate.svg"), 'utf-8');
const credentialViews: CredentialView[] = ehics
.map((ehic) => {
const rows: CategorizedRawCredentialViewRow[] = [
{ name: "Family Name", value: ehic.family_name },
{ name: "Given Name", value: ehic.given_name },
{ name: "SSN", value: String(ehic.ssn) },
{ name: "Date of Birth", value: ehic.birth_date },
{ name: "family_name", value: ehic.family_name },
{ name: "given_name", value: ehic.given_name },
{ name: "ssn", value: String(ehic.ssn) },
{ name: "birth_date", value: formatDateDDMMYYYY(ehic.birth_date) },
{ name: "expiry_date", value: formatDateDDMMYYYY(ehic.expiry_date) },
];
const rowsObject: CategorizedRawCredentialView = { rows };
const dataUri = generateDataUriFromSvg(svgText, rows);

return {
credential_id: this.getId(),
credential_supported_object: this.exportCredentialSupportedObject(),
view: rowsObject,
credential_image: "",
credential_image: dataUri,
}
})
return credentialViews[0];
Expand Down Expand Up @@ -119,7 +124,7 @@ export class EHICSupportedCredentialSdJwtVCDM implements VCDMSupportedCredential
family_name: ehicEntry.family_name,
given_name: ehicEntry.given_name,
ssn: ehicEntry.ssn,
birth_date: ehicEntry.birth_date
birth_date: new Date(ehicEntry.birth_date).toISOString()
};

const payload = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { config } from "../../../config";
import { CategorizedRawCredentialView, CategorizedRawCredentialViewRow } from "../../openid4vci/Metadata";
import { VerifiableCredentialFormat } from "../../types/oid4vci";
import { VCDMSupportedCredentialProtocol } from "../../lib/CredentialIssuerConfig/SupportedCredentialProtocol";
import { formatDateDDMMYYYY } from "../../lib/formatDate";
import { generateDataUriFromSvg } from "../../lib/generateDataUriFromSvg";
import { AuthorizationServerState } from "../../entities/AuthorizationServerState.entity";
import { CredentialView } from "../../authorization/types";
import { randomUUID } from "node:crypto";
Expand All @@ -11,7 +13,7 @@ import { Request } from "express";
import { issuerSigner } from "../issuerSigner";
import { parsePidData } from "../datasetParser";
import path from "node:path";

import fs from 'fs';

parsePidData(path.join(__dirname, "../../../../dataset/vid-dataset.xlsx")) // test parse

Expand Down Expand Up @@ -59,22 +61,26 @@ export class VIDSupportedCredentialSdJwtVCDM implements VCDMSupportedCredentialP
return null;
}

const svgText = fs.readFileSync(path.join(__dirname, "../../../../public/images/idTemplate.svg"), 'utf-8');
const vids = users.filter(u => String(u.pid_id) == userSession?.pid_id);
const credentialViews: CredentialView[] = vids
.map((vid) => {
const rows: CategorizedRawCredentialViewRow[] = [
{ name: "Family Name", value: vid.family_name },
{ name: "Given Name", value: vid.given_name },
{ name: "Document number", value: vid.document_number },
{ name: "Date of Birth", value: vid.birth_date },
{ name: "family_name", value: vid.family_name },
{ name: "given_name", value: vid.given_name },
{ name: "document_number", value: vid.document_number },
{ name: "birth_date", value: formatDateDDMMYYYY(vid.birth_date) },
{ name: "issuance_date", value: formatDateDDMMYYYY(vid.issuance_date) },
{ name: "expiry_date", value: formatDateDDMMYYYY(vid.expiry_date) },
];
const rowsObject: CategorizedRawCredentialView = { rows };
const dataUri = generateDataUriFromSvg(svgText, rows);

return {
credential_id: this.getId(),
credential_supported_object: this.exportCredentialSupportedObject(),
view: rowsObject,
credential_image: ""
credential_image: dataUri,
}
})
return credentialViews[0];
Expand Down Expand Up @@ -106,7 +112,7 @@ export class VIDSupportedCredentialSdJwtVCDM implements VCDMSupportedCredentialP
const vid = {
family_name: vidEntry.family_name,
given_name: vidEntry.given_name,
birth_date: vidEntry.birth_date,
birth_date: new Date(vidEntry.birth_date).toISOString(),
issuing_authority: vidEntry.issuing_authority,
issuing_country: vidEntry.issuing_country,
document_number: String(vidEntry.document_number),
Expand Down Expand Up @@ -161,7 +167,7 @@ export class VIDSupportedCredentialSdJwtVCDM implements VCDMSupportedCredentialP
"text_color": "#FFFFFF"
},
"svg_templates": {
"uri": config.url + "/images/idTemplate.svg",
"uri": config.url + "/images/idTemplate.svg",
},
}
}
Expand Down

0 comments on commit 9d41e6b

Please sign in to comment.