@cooperation/vc-storage 1.0.1 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.js +2 -1
- package/dist/models/CredentialEngine.js +161 -134
- package/dist/models/GoogleDriveStorage.js +167 -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
|
}
|