@cooperation/vc-storage 1.0.1 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
  }