@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 +2 -1
- package/dist/models/CredentialEngine.js +161 -134
- package/dist/models/GoogleDriveStorage.js +183 -61
- package/dist/types/index.d.ts +2 -1
- package/dist/types/models/CredentialEngine.d.ts +44 -20
- package/dist/types/models/GoogleDriveStorage.d.ts +61 -3
- package/dist/types/utils/credential.d.ts +23 -0
- package/dist/types/utils/digitalbazaar.d.ts +1 -0
- package/dist/types/utils/google.d.ts +14 -0
- package/dist/types/utils/presentation.d.ts +10 -0
- package/dist/types/utils/saveToGoogle.d.ts +4 -4
- package/dist/utils/credential.js +172 -0
- package/dist/utils/digitalbazaar.js +37 -0
- package/dist/utils/google.js +79 -0
- package/dist/utils/presentation.js +48 -0
- package/dist/utils/saveToGoogle.js +12 -0
- package/package.json +5 -2
- package/dist/models/CredentialVerefier.js +0 -36
- package/dist/types/models/CredentialVerefier.d.ts +0 -9
package/dist/index.js
CHANGED
@@ -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
|
3
|
+
import * as vc from '@digitalbazaar/vc';
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
5
|
-
import {
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
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
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
*
|
102
|
-
* @param {
|
103
|
-
* @param {string}
|
104
|
-
* @
|
105
|
-
* @
|
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
|
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
|
110
|
-
|
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
|
129
|
+
console.error('Error signing VC:', error);
|
165
130
|
throw error;
|
166
131
|
}
|
167
132
|
}
|
168
133
|
/**
|
169
|
-
*
|
170
|
-
* @param {object} credential - The
|
171
|
-
* @
|
172
|
-
* @
|
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
|
176
|
-
const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
|
139
|
+
async verifyCredential(credential) {
|
177
140
|
try {
|
178
|
-
const
|
179
|
-
|
180
|
-
|
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('
|
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
|
}
|