@cooperation/vc-storage 1.0.1 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './models/GoogleDriveStorage.js';
2
2
  export * from './models/CredentialEngine.js';
3
- export { saveToGoogleDrive } from './utils/saveToGoogle.js';
3
+ export * from './utils/google.js';
4
+ export * from './utils/presentation.js';
@@ -1,62 +1,71 @@
1
1
  import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
2
2
  import { Ed25519Signature2020 } from '@digitalbazaar/ed25519-signature-2020';
3
- import { defaultDocumentLoader, issue } from '@digitalbazaar/vc';
3
+ import * as vc from '@digitalbazaar/vc';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
- import { localOBContext, localED25519Context } from '../utils/context.js';
6
- // Custom document loader
7
- export const customDocumentLoader = async (url) => {
8
- const contextMap = {
9
- 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json': localOBContext,
10
- 'https://w3id.org/security/suites/ed25519-2020/v1': localED25519Context,
11
- };
12
- if (contextMap[url]) {
13
- return {
14
- contextUrl: null,
15
- documentUrl: url,
16
- document: contextMap[url],
17
- };
18
- }
19
- return defaultDocumentLoader(url); // Fallback to default loader for unknown URLs
20
- };
5
+ import { extractKeyPairFromCredential, generateDIDSchema, generateUnsignedRecommendation, generateUnsignedVC, } from '../utils/credential.js';
6
+ import { customDocumentLoader } from '../utils/digitalbazaar.js';
7
+ import { saveToGoogleDrive } from '../utils/google.js';
8
+ import { GoogleDriveStorage } from './GoogleDriveStorage.js';
9
+ /**
10
+ * Class representing the Credential Engine.
11
+ * @class CredentialEngine
12
+ * @param {string} accessToken - The access token for the user.
13
+ * @classdesc Credential Engine class to create DIDs and VCs.
14
+ * @method createDID - Create a new DID with Digital Bazaar's Ed25519VerificationKey2020 key pair.
15
+ * @method createWalletDID - Create a new DID with user metamask address as controller.
16
+ * @method signVC - Sign a Verifiable Credential (VC).
17
+ * @method verifyCredential - Verify a Verifiable Credential (VC).
18
+ * @method createPresentation - Create a Verifiable Presentation (VP).
19
+ * @method signPresentation - Sign a Verifiable Presentation (VP).
20
+ */
21
21
  export class CredentialEngine {
22
- /**
23
- * Create a DID document using the provided key pair.
24
- * @param {object} keyPair - The key pair used to create the DID document.
25
- * @returns {Promise<object>} The created DID document.
26
- */
27
- async generateDIDSchema(keyPair) {
28
- try {
29
- const DID = keyPair.controller;
30
- const didDocument = {
31
- '@context': ['https://www.w3.org/ns/did/v1'],
32
- id: DID,
33
- publicKey: [
34
- {
35
- id: keyPair.id,
36
- type: 'Ed25519VerificationKey2020',
37
- controller: DID,
38
- publicKeyMultibase: keyPair.publicKeyMultibase,
39
- },
40
- ],
41
- authentication: [keyPair.id],
42
- assertionMethod: [keyPair.id],
43
- capabilityDelegation: [keyPair.id],
44
- capabilityInvocation: [keyPair.id],
45
- keyAgreement: [
46
- {
47
- id: `${keyPair.id}-keyAgreement`,
48
- type: 'X25519KeyAgreementKey2020',
49
- controller: DID,
50
- publicKeyMultibase: keyPair.publicKeyMultibase,
51
- },
52
- ],
53
- };
54
- return didDocument;
22
+ uuid;
23
+ storage;
24
+ keyPair;
25
+ constructor(accessToken) {
26
+ this.uuid = uuidv4();
27
+ this.storage = new GoogleDriveStorage(accessToken);
28
+ }
29
+ async getKeyPair(vc) {
30
+ // Fetch all stored key pairs
31
+ const keyPairs = await this.storage.getAllFilesByType('KEYPAIRs');
32
+ if (!keyPairs || keyPairs.length === 0) {
33
+ throw new Error('No key pairs found in storage.');
55
34
  }
56
- catch (error) {
57
- console.error('Error creating DID document:', error);
58
- throw error;
35
+ // Extract UUID from VC ID
36
+ const vcIdParts = vc.id.split(':');
37
+ if (vcIdParts.length < 3) {
38
+ throw new Error('Invalid Verifiable Credential ID format.');
59
39
  }
40
+ const uuidFromVC = vcIdParts[2];
41
+ // Match UUID with key pair files
42
+ const matchingKeyPairFile = keyPairs.find((key) => {
43
+ const [uuidPart] = key.name.split('_');
44
+ return uuidPart === uuidFromVC;
45
+ });
46
+ if (!matchingKeyPairFile) {
47
+ throw new Error('No matching key pair found for the Verifiable Credential ID.');
48
+ }
49
+ // Return the key pair content
50
+ const key = matchingKeyPairFile.content;
51
+ this.keyPair = key;
52
+ return key;
53
+ }
54
+ generateKeyPair = async (address) => {
55
+ const keyPair = await Ed25519VerificationKey2020.generate();
56
+ const a = address || keyPair.publicKeyMultibase;
57
+ keyPair.controller = `did:key:${a}`;
58
+ keyPair.id = `${keyPair.controller}#${a}`;
59
+ keyPair.revoked = false;
60
+ return keyPair;
61
+ };
62
+ async verifyCreds(creds) {
63
+ await Promise.all(creds.map((cred) => {
64
+ const res = this.verifyCredential(cred);
65
+ if (!res)
66
+ return false;
67
+ }));
68
+ return true;
60
69
  }
61
70
  /**
62
71
  * Create a new DID with Digital Bazaar's Ed25519VerificationKey2020 key pair.
@@ -65,11 +74,10 @@ export class CredentialEngine {
65
74
  */
66
75
  async createDID() {
67
76
  try {
68
- const keyPair = await Ed25519VerificationKey2020.generate();
69
- keyPair.controller = `did:key:${keyPair.publicKeyMultibase}`;
70
- keyPair.id = `${keyPair.controller}#${keyPair.publicKeyMultibase}`;
71
- keyPair.revoked = false;
72
- const didDocument = await this.generateDIDSchema(keyPair);
77
+ const keyPair = await this.generateKeyPair();
78
+ const keyFile = await saveToGoogleDrive(this.storage, keyPair, 'KEYPAIR', this.uuid);
79
+ console.log('🚀 ~ CredentialEngine ~ createDID ~ keyFile:', keyFile);
80
+ const didDocument = await generateDIDSchema(keyPair);
73
81
  return { didDocument, keyPair };
74
82
  }
75
83
  catch (error) {
@@ -85,11 +93,10 @@ export class CredentialEngine {
85
93
  */
86
94
  async createWalletDID(walletrAddress) {
87
95
  try {
88
- const keyPair = await Ed25519VerificationKey2020.generate();
89
- keyPair.controler = walletrAddress; // Using the MetaMask address as controller
90
- keyPair.id = `${keyPair.controller}#${keyPair.fingerprint()}`;
91
- keyPair.revoked = false;
92
- const didDocument = await this.generateDIDSchema(keyPair);
96
+ const keyPair = await this.generateKeyPair(walletrAddress);
97
+ const keyFile = await saveToGoogleDrive(this.storage, keyPair, 'KEYPAIR', this.uuid);
98
+ console.log('🚀 ~ CredentialEngine ~ createWalletDID ~ keyFile:', keyFile);
99
+ const didDocument = await generateDIDSchema(keyPair);
93
100
  return { didDocument, keyPair };
94
101
  }
95
102
  catch (error) {
@@ -98,89 +105,109 @@ export class CredentialEngine {
98
105
  }
99
106
  }
100
107
  /**
101
- * Create an unsigned Verifiable Credential (VC)
102
- * @param {object} formData - The form data to include in the VC.
103
- * @param {string} issuerDid - The DID of the issuer.
104
- * @returns {Promise<object>} The created unsigned VC.
105
- * @throws Will throw an error if unsigned VC creation fails.
108
+ * Sign a Verifiable Credential (VC)
109
+ * @param {'VC' | 'RECOMMENDATION'} type - The signature type.
110
+ * @param {string} issuerId - The ID of the issuer [currently we put it as the did id]
111
+ * @param {KeyPair} keyPair - The key pair to use for signing.
112
+ * @returns {Promise<Credential>} The signed VC.
113
+ * @throws Will throw an error if VC signing fails.
106
114
  */
107
- async createUnsignedVC(formData, issuerDid) {
115
+ async signVC(formData, type, keyPair, issuerId) {
116
+ let credential;
117
+ if (type == 'VC') {
118
+ credential = generateUnsignedVC(formData, issuerId, this.uuid);
119
+ }
120
+ else if (type == 'RECOMMENDATION') {
121
+ credential = generateUnsignedRecommendation(formData, issuerId);
122
+ }
123
+ const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
108
124
  try {
109
- const issuanceDate = new Date().toISOString();
110
- if (issuanceDate > formData.expirationDate)
111
- throw Error('issuanceDate cannot be after expirationDate');
112
- const unsignedCredential = {
113
- '@context': [
114
- 'https://www.w3.org/2018/credentials/v1',
115
- 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
116
- {
117
- duration: 'https://schema.org/duration',
118
- fullName: 'https://schema.org/name',
119
- portfolio: 'https://schema.org/portfolio',
120
- evidenceLink: 'https://schema.org/evidenceLink',
121
- evidenceDescription: 'https://schema.org/evidenceDescription',
122
- credentialType: 'https://schema.org/credentialType',
123
- },
124
- ],
125
- id: `urn:uuid:${uuidv4()}`, // Add the id property
126
- type: ['VerifiableCredential', 'OpenBadgeCredential'],
127
- issuer: {
128
- id: issuerDid,
129
- type: ['Profile'],
130
- },
131
- issuanceDate,
132
- expirationDate: formData.expirationDate,
133
- credentialSubject: {
134
- type: ['AchievementSubject'],
135
- name: formData.fullName,
136
- portfolio: formData.portfolio,
137
- evidenceLink: formData.evidenceLink,
138
- evidenceDescription: formData.achievementDescription,
139
- duration: formData.duration,
140
- credentialType: formData.credentialType,
141
- achievement: [
142
- {
143
- id: `urn:uuid:${uuidv4()}`,
144
- type: ['Achievement'],
145
- criteria: {
146
- narrative: formData.criteriaNarrative,
147
- },
148
- description: formData.achievementDescription,
149
- name: formData.achievementName,
150
- image: formData.evidenceLink
151
- ? {
152
- id: formData.evidenceLink,
153
- type: 'Image',
154
- }
155
- : undefined,
156
- },
157
- ],
158
- },
159
- };
160
- console.log('Successfully created Unsigned Credentials', unsignedCredential);
161
- return unsignedCredential;
125
+ const signedVC = await vc.issue({ credential, suite, documentLoader: customDocumentLoader });
126
+ return signedVC;
162
127
  }
163
128
  catch (error) {
164
- console.error('Error creating unsigned VC', error);
129
+ console.error('Error signing VC:', error);
165
130
  throw error;
166
131
  }
167
132
  }
168
133
  /**
169
- * Sign a Verifiable Credential (VC)
170
- * @param {object} credential - The credential to sign.
171
- * @param {object} keyPair - The key pair to use for signing.
172
- * @returns {Promise<object>} The signed VC.
173
- * @throws Will throw an error if VC signing fails.
134
+ * Verify a Verifiable Credential (VC)
135
+ * @param {object} credential - The Verifiable Credential to verify.
136
+ * @returns {Promise<boolean>} The verification result.
137
+ * @throws Will throw an error if VC verification fails.
174
138
  */
175
- async signVC(credential, keyPair) {
176
- const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
139
+ async verifyCredential(credential) {
177
140
  try {
178
- const signedVC = await issue({ credential, suite, documentLoader: customDocumentLoader });
179
- console.log('Successfully created Signed VC', signedVC);
180
- return signedVC;
141
+ const keyPair = await extractKeyPairFromCredential(credential);
142
+ const suite = new Ed25519Signature2020({
143
+ key: keyPair,
144
+ verificationMethod: keyPair.id,
145
+ });
146
+ const result = await vc.verifyCredential({
147
+ credential,
148
+ suite,
149
+ documentLoader: customDocumentLoader,
150
+ });
151
+ console.log(JSON.stringify(result));
152
+ return result;
181
153
  }
182
154
  catch (error) {
183
- console.error('Error signing VC:', error);
155
+ console.error('Verification failed:', error);
156
+ throw error;
157
+ }
158
+ }
159
+ /**
160
+ * Create a Verifiable Presentation (VP)
161
+ * @param verifiableCredential
162
+ * @returns
163
+ */
164
+ async createPresentation(verifiableCredential) {
165
+ try {
166
+ const res = await this.verifyCreds(verifiableCredential);
167
+ if (!res)
168
+ throw new Error('Some credentials failed verification');
169
+ const id = `urn:uuid:${uuidv4()}`;
170
+ const keyPair = await this.getKeyPair(verifiableCredential[0]);
171
+ console.log('🚀 ~ CredentialEngine ~ createPresentation ~ keyPair:', keyPair);
172
+ const VP = await vc.createPresentation({ verifiableCredential, id, holder: keyPair.controller });
173
+ return VP;
174
+ }
175
+ catch (error) {
176
+ console.error('Error creating presentation:', error);
177
+ throw error;
178
+ }
179
+ }
180
+ /**
181
+ * Sign a Verifiable Presentation (VP)
182
+ * @param presentation
183
+ * @returns
184
+ */
185
+ async signPresentation(presentation) {
186
+ try {
187
+ // Wrap the keyPair into an Ed25519VerificationKey2020 that includes the signer method
188
+ const signingKey = new Ed25519VerificationKey2020({
189
+ id: this.keyPair.id,
190
+ controller: this.keyPair.controller,
191
+ type: this.keyPair.type,
192
+ publicKeyMultibase: this.keyPair.publicKeyMultibase,
193
+ privateKeyMultibase: this.keyPair.privateKeyMultibase,
194
+ });
195
+ // Create the Ed25519Signature2020 suite with the wrapped key that includes the signer
196
+ const suite = new Ed25519Signature2020({
197
+ key: signingKey,
198
+ verificationMethod: this.keyPair.id,
199
+ });
200
+ // Sign the presentation
201
+ const signedVP = await vc.signPresentation({
202
+ presentation,
203
+ suite,
204
+ documentLoader: customDocumentLoader,
205
+ challenge: '', // Provide the challenge if required
206
+ });
207
+ return signedVP;
208
+ }
209
+ catch (error) {
210
+ console.error('Error signing presentation:', error);
184
211
  throw error;
185
212
  }
186
213
  }