diff --git a/.gitignore b/.gitignore index 94b12fe..0d41be4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ node_modules .env* testVc.js testresume.js -/dist \ No newline at end of file +/dist +/.yalc* +yalc* \ No newline at end of file diff --git a/package.json b/package.json index 48b16ab..02d1af5 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@digitalcredentials/ed25519-signature-2020": "^5.0.0", "@digitalcredentials/ed25519-verification-key-2020": "^5.0.0-beta.2", "@digitalcredentials/ezcap": "^5.1.0", + "@digitalcredentials/ssi": "^5.1.0", "@wallet.storage/fetch-client": "^1.2.0", "add": "^2.0.6", "bnid": "^3.0.0", diff --git a/src/utils/credential.ts b/src/utils/credential.ts index 911d4f5..b18cffe 100644 --- a/src/utils/credential.ts +++ b/src/utils/credential.ts @@ -6,11 +6,11 @@ import { RecommendationCredential, Credential, RecommendationFormDataI, - VerifiableCredential, EmploymentFormDataI, VolunteeringFormDataI, PerformanceReviewFormDataI, } from '../../types'; +import { IVerifiableCredential } from '@digitalcredentials/ssi'; import { v4 as uuidv4 } from 'uuid'; import CryptoJS from 'crypto-js'; import { employmentCredentialContext, volunteeringCredentialContext, performanceReviewCredentialContext } from './context.js'; @@ -74,10 +74,10 @@ export const generateDIDSchema = async (keyPair: KeyPair): Promise * @param {FormDataI} params * @param {string} params.FormData - The form dta to include in the VC. * @param {string} params.issuerDid - The DID of the issuer. - * @returns {Credential} The created unsigned VC. + * @returns {IVerifiableCredential} The created unsigned VC. * @throws Will throw an error if the VC creation fails or if issuance date exceeds expiration date. */ -export function generateUnsignedVC({ formData, issuerDid }: { formData: FormDataI; issuerDid: string }): Credential { +export function generateUnsignedVC({ formData, issuerDid }: { formData: FormDataI; issuerDid: string }): IVerifiableCredential { const issuanceDate = new Date().toISOString(); if (issuanceDate > formData.expirationDate) throw new Error('issuanceDate cannot be after expirationDate'); @@ -94,7 +94,7 @@ export function generateUnsignedVC({ formData, issuerDid }: { formData: FormData credentialType: 'https://schema.org/credentialType', }, ], - id: '', // Will be set after hashing + id: '', // Will be set after hashing type: ['VerifiableCredential', 'OpenBadgeCredential'], issuer: { id: issuerDid, @@ -137,16 +137,16 @@ export function generateUnsignedVC({ formData, issuerDid }: { formData: FormData // Generate the hashed ID unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential); - return unsignedCredential; + return unsignedCredential as IVerifiableCredential; } /** * Generate an unsigned Recommendation Credential. * Uses the hash of the VC to set the `id` for consistency. * @param {object} params - * @param {VerifiableCredential} params.vc - The Verifiable Credential to base the recommendation on. + * @param {IVerifiableCredential} params.vc - The Verifiable Credential to base the recommendation on. * @param {RecommendationFormDataI} params.recommendation - The recommendation form data. * @param {string} params.issuerDid - The DID of the issuer. - * @returns {RecommendationCredential} The created unsigned Recommendation Credential. + * @returns {IVerifiableCredential} The created unsigned Recommendation Credential. * @throws Will throw an error if the recommendation creation fails or if issuance date exceeds expiration date. */ export function generateUnsignedRecommendation({ @@ -157,7 +157,7 @@ export function generateUnsignedRecommendation({ vcId: string; recommendation: RecommendationFormDataI; issuerDid: string; -}): RecommendationCredential { +}): IVerifiableCredential { const issuanceDate = new Date().toISOString(); if (issuanceDate > recommendation.expirationDate) throw new Error('issuanceDate cannot be after expirationDate'); @@ -194,13 +194,13 @@ export function generateUnsignedRecommendation({ }, }; - return unsignedRecommendation; + return unsignedRecommendation as IVerifiableCredential; } /** * Generate an unsigned Employment Credential. */ -export function generateUnsignedEmployment({ formData, issuerDid }: { formData: EmploymentFormDataI; issuerDid: string }) { +export function generateUnsignedEmployment({ formData, issuerDid }: { formData: EmploymentFormDataI; issuerDid: string }): IVerifiableCredential { const issuanceDate = new Date().toISOString(); const unsignedCredential = { '@context': ['https://www.w3.org/2018/credentials/v1', employmentCredentialContext['@context']], @@ -223,13 +223,13 @@ export function generateUnsignedEmployment({ formData, issuerDid }: { formData: }, }; unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential); - return unsignedCredential; + return unsignedCredential as IVerifiableCredential; } /** * Generate an unsigned Volunteering Credential. */ -export function generateUnsignedVolunteering({ formData, issuerDid }: { formData: VolunteeringFormDataI; issuerDid: string }) { +export function generateUnsignedVolunteering({ formData, issuerDid }: { formData: VolunteeringFormDataI; issuerDid: string }): IVerifiableCredential { const issuanceDate = new Date().toISOString(); const unsignedCredential = { '@context': ['https://www.w3.org/2018/credentials/v1', volunteeringCredentialContext['@context']], @@ -253,13 +253,13 @@ export function generateUnsignedVolunteering({ formData, issuerDid }: { formData }, }; unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential); - return unsignedCredential; + return unsignedCredential as IVerifiableCredential; } /** * Generate an unsigned Performance Review Credential. */ -export function generateUnsignedPerformanceReview({ formData, issuerDid }: { formData: PerformanceReviewFormDataI; issuerDid: string }) { +export function generateUnsignedPerformanceReview({ formData, issuerDid }: { formData: PerformanceReviewFormDataI; issuerDid: string }): IVerifiableCredential { const issuanceDate = new Date().toISOString(); const unsignedCredential = { '@context': ['https://www.w3.org/2018/credentials/v1', performanceReviewCredentialContext['@context']], @@ -291,7 +291,7 @@ export function generateUnsignedPerformanceReview({ formData, issuerDid }: { for }, }; unsignedCredential.id = 'urn:' + generateHashedId(unsignedCredential); - return unsignedCredential; + return unsignedCredential as IVerifiableCredential; } /** @@ -299,9 +299,9 @@ export function generateUnsignedPerformanceReview({ formData, issuerDid }: { for * @param {Object} credential - The signed Verifiable Credential * @returns {Ed25519VerificationKey2020} keyPair - The generated keypair object */ -export async function extractKeyPairFromCredential(credential: VerifiableCredential): Promise { +export async function extractKeyPairFromCredential(credential: IVerifiableCredential): Promise { const verificationMethod: string = credential.proof.verificationMethod; - const issuer: string = credential.issuer.id; + const issuer: string = typeof credential.issuer === 'string' ? credential.issuer : credential.issuer.id; // Example of extracting the public key from the DID fragment (verification method) const publicKeyMultibase: string = verificationMethod.split('#')[1]; diff --git a/types/Credential.d.ts b/types/Credential.d.ts index 7795d5b..1158b4b 100644 --- a/types/Credential.d.ts +++ b/types/Credential.d.ts @@ -10,19 +10,10 @@ interface PortfolioItem { url: string; } -interface Achievement { - id: string; - type: string[]; - criteria: { - narrative: string; - }; - description: string; - name: string; - image?: { - id: string; - type: string; - }; -} +import type { IAchievement, IOpenBadgeSubject } from '@digitalcredentials/ssi'; + + export type Achievement = IAchievement; +export type OpenBadgeSubject = IOpenBadgeSubject; export interface KeyPair { id: string; @@ -119,19 +110,6 @@ export interface Proof { proofValue: string; } -// Define the structure of the Verifiable Credential (partial based on what was provided) -export interface VerifiableCredential { - '@context': string[]; - id: string; - type: string[]; - issuer: { id: string; type: string[] }; - issuanceDate: string; - expirationDate: string; - credentialSubject: { [key: string]: any }; - proof: Proof; -} - - /** * Employment form data */ diff --git a/yarn.lock b/yarn.lock index d1e733e..4a54a75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -473,7 +473,7 @@ "@noble/ed25519" "^1.7.5" base-x "^4.0.1" -"@digitalcredentials/ezcap@^7.1.0": +"@digitalcredentials/ezcap@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@digitalcredentials/ezcap/-/ezcap-5.1.0.tgz#18f9cf9904d0d88693dc21f3c4189f5a2fada457" integrity sha512-maF5y2MNC9c6q0Y5fjadHIEo9xthJc5ARnr4V85wNRbTdCB/G3ZWLcugIHNBWFcbYW6Rgf52e06BED7+ODZgKw== @@ -535,6 +535,9 @@ resolved "https://registry.yarnpkg.com/@digitalcredentials/ssi/-/ssi-3.0.5.tgz#a214fe4544b786bf85860851c635fc65575d108c" integrity sha512-V8Xuz3yWS2+EOwsfuJkpai+rIEs7Nvvl4r7FPcJYbmumB8DWefTCvATqRTMbF2CrT4It0Izs843qHdjWuPQIkg== +"@digitalcredentials/ssi@file:.yalc/@digitalcredentials/ssi": + version "5.0.0" + "@esbuild/aix-ppc64@0.24.2": version "0.24.2" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz#38848d3e25afe842a7943643cbcd387cc6e13461" @@ -3573,7 +3576,7 @@ ts-node@^10.9.2: tsc@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/tsc/-/tsc-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/tsc/-/tsc-2.0.4.tgz#5f6499146abea5dca4420b451fa4f2f9345238f5" integrity sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q== tslib@2.4.0: