@cooperation/vc-storage 1.0.10 → 1.0.12
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/models/CredentialEngine.js +53 -18
- package/dist/models/GoogleDriveStorage.js +160 -128
- package/dist/types/models/CredentialEngine.d.ts +16 -3
- package/dist/types/models/GoogleDriveStorage.d.ts +18 -19
- package/dist/types/utils/credential.d.ts +29 -10
- package/dist/types/utils/google.d.ts +23 -5
- package/dist/utils/credential.js +131 -109
- package/dist/utils/google.js +31 -24
- package/dist/utils/presentation.js +26 -29
- package/package.json +1 -2
- package/dist/types/utils/saveToGoogle.d.ts +0 -10
- package/dist/utils/saveToGoogle.js +0 -65
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
|
2
2
|
import { Ed25519Signature2020 } from '@digitalbazaar/ed25519-signature-2020';
|
3
|
-
import * as
|
3
|
+
import * as dbVc from '@digitalbazaar/vc';
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
5
5
|
import { extractKeyPairFromCredential, generateDIDSchema, generateUnsignedRecommendation, generateUnsignedVC, } from '../utils/credential.js';
|
6
6
|
import { customDocumentLoader } from '../utils/digitalbazaar.js';
|
@@ -19,11 +19,9 @@ import { GoogleDriveStorage } from './GoogleDriveStorage.js';
|
|
19
19
|
* @method signPresentation - Sign a Verifiable Presentation (VP).
|
20
20
|
*/
|
21
21
|
export class CredentialEngine {
|
22
|
-
uuid;
|
23
22
|
storage;
|
24
23
|
keyPair;
|
25
24
|
constructor(accessToken) {
|
26
|
-
this.uuid = uuidv4();
|
27
25
|
this.storage = new GoogleDriveStorage(accessToken);
|
28
26
|
}
|
29
27
|
async getKeyPair(vc) {
|
@@ -75,8 +73,11 @@ export class CredentialEngine {
|
|
75
73
|
async createDID() {
|
76
74
|
try {
|
77
75
|
const keyPair = await this.generateKeyPair();
|
78
|
-
const keyFile = await saveToGoogleDrive(
|
79
|
-
|
76
|
+
const keyFile = await saveToGoogleDrive({
|
77
|
+
storage: this.storage,
|
78
|
+
data: keyPair,
|
79
|
+
type: 'KEYPAIR',
|
80
|
+
});
|
80
81
|
const didDocument = await generateDIDSchema(keyPair);
|
81
82
|
return { didDocument, keyPair };
|
82
83
|
}
|
@@ -85,6 +86,23 @@ export class CredentialEngine {
|
|
85
86
|
throw error;
|
86
87
|
}
|
87
88
|
}
|
89
|
+
async findKeysAndDIDs() {
|
90
|
+
// find the DID document for the current user
|
91
|
+
const keyPairs = (await this.storage.getAllFilesByType('KEYPAIRs'));
|
92
|
+
console.log('🚀 ~ CredentialEngine ~ findDid ~ keyPairs:', keyPairs[0].data);
|
93
|
+
const DIDs = (await this.storage.getAllFilesByType('DIDs'));
|
94
|
+
console.log('🚀 ~ CredentialEngine ~ findKeysAndDIDs ~ DIDs:', DIDs);
|
95
|
+
console.log('🚀 ~ CredentialEngine ~ findKeysAndDIDs ~ DIDs:', DIDs[0]);
|
96
|
+
if (DIDs.length === 0 || keyPairs.length === 0)
|
97
|
+
return null;
|
98
|
+
const keyPair = keyPairs[0].data;
|
99
|
+
const didDocument = DIDs[0].data.didDocument;
|
100
|
+
console.log('🚀 ~ CredentialEngine ~ findKeysAndDIDs ~ didDocument:', didDocument);
|
101
|
+
return {
|
102
|
+
didDocument,
|
103
|
+
keyPair,
|
104
|
+
};
|
105
|
+
}
|
88
106
|
/**
|
89
107
|
* Create a new DID with user metamask address as controller
|
90
108
|
* @param walletrAddress
|
@@ -94,7 +112,11 @@ export class CredentialEngine {
|
|
94
112
|
async createWalletDID(walletrAddress) {
|
95
113
|
try {
|
96
114
|
const keyPair = await this.generateKeyPair(walletrAddress);
|
97
|
-
const keyFile = await saveToGoogleDrive(
|
115
|
+
const keyFile = await saveToGoogleDrive({
|
116
|
+
storage: this.storage,
|
117
|
+
data: keyPair,
|
118
|
+
type: 'KEYPAIR',
|
119
|
+
});
|
98
120
|
console.log('🚀 ~ CredentialEngine ~ createWalletDID ~ keyFile:', keyFile);
|
99
121
|
const didDocument = await generateDIDSchema(keyPair);
|
100
122
|
return { didDocument, keyPair };
|
@@ -109,20 +131,33 @@ export class CredentialEngine {
|
|
109
131
|
* @param {'VC' | 'RECOMMENDATION'} type - The signature type.
|
110
132
|
* @param {string} issuerId - The ID of the issuer [currently we put it as the did id]
|
111
133
|
* @param {KeyPair} keyPair - The key pair to use for signing.
|
134
|
+
* @param {FormDataI | RecommendationFormDataI} formData - The form data to include in the VC.
|
135
|
+
* @param {string} VCId - The ID of the credential when the type is RECOMMENDATION
|
112
136
|
* @returns {Promise<Credential>} The signed VC.
|
113
137
|
* @throws Will throw an error if VC signing fails.
|
114
138
|
*/
|
115
|
-
async signVC(
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
139
|
+
async signVC({ data, type, keyPair, issuerId, vcFileId }) {
|
140
|
+
console.log('🚀 ~ CredentialEngine ~ signVC ~ { data, type, keyPair, issuerId, vcFileId }:', {
|
141
|
+
data,
|
142
|
+
type,
|
143
|
+
keyPair,
|
144
|
+
issuerId,
|
145
|
+
vcFileId,
|
146
|
+
});
|
147
|
+
let vc;
|
148
|
+
let credential = generateUnsignedVC({ formData: data, issuerDid: issuerId });
|
149
|
+
if (type == 'RECOMMENDATION' && vcFileId) {
|
150
|
+
console.log('WOW');
|
151
|
+
vc = (await this.storage.retrieve(vcFileId));
|
152
|
+
credential = generateUnsignedRecommendation({ vc, recommendation: data, issuerDid: issuerId });
|
122
153
|
}
|
123
|
-
const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
|
124
154
|
try {
|
125
|
-
|
155
|
+
console.log('🚀 ~ CredentialEngine ~ signVC ~ credential:', credential);
|
156
|
+
if (!credential)
|
157
|
+
throw new Error('Invalid credential type');
|
158
|
+
const suite = new Ed25519Signature2020({ key: keyPair, verificationMethod: keyPair.id });
|
159
|
+
console.log('before');
|
160
|
+
const signedVC = await dbVc.issue({ credential, suite, documentLoader: customDocumentLoader });
|
126
161
|
return signedVC;
|
127
162
|
}
|
128
163
|
catch (error) {
|
@@ -143,7 +178,7 @@ export class CredentialEngine {
|
|
143
178
|
key: keyPair,
|
144
179
|
verificationMethod: keyPair.id,
|
145
180
|
});
|
146
|
-
const result = await
|
181
|
+
const result = await dbVc.verifyCredential({
|
147
182
|
credential,
|
148
183
|
suite,
|
149
184
|
documentLoader: customDocumentLoader,
|
@@ -169,7 +204,7 @@ export class CredentialEngine {
|
|
169
204
|
const id = `urn:uuid:${uuidv4()}`;
|
170
205
|
const keyPair = await this.getKeyPair(verifiableCredential[0]);
|
171
206
|
console.log('🚀 ~ CredentialEngine ~ createPresentation ~ keyPair:', keyPair);
|
172
|
-
const VP = await
|
207
|
+
const VP = await dbVc.createPresentation({ verifiableCredential, id, holder: keyPair.controller });
|
173
208
|
return VP;
|
174
209
|
}
|
175
210
|
catch (error) {
|
@@ -198,7 +233,7 @@ export class CredentialEngine {
|
|
198
233
|
verificationMethod: this.keyPair.id,
|
199
234
|
});
|
200
235
|
// Sign the presentation
|
201
|
-
const signedVP = await
|
236
|
+
const signedVP = await dbVc.signPresentation({
|
202
237
|
presentation,
|
203
238
|
suite,
|
204
239
|
documentLoader: customDocumentLoader,
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import { generateViewLink } from '../utils/google.js';
|
2
1
|
/**
|
3
2
|
* @class GoogleDriveStorage
|
4
3
|
* @description Class to interact with Google Drive API
|
@@ -19,7 +18,6 @@ export class GoogleDriveStorage {
|
|
19
18
|
constructor(accessToken) {
|
20
19
|
this.accessToken = accessToken;
|
21
20
|
}
|
22
|
-
// Method to fetch data from Google Drive API
|
23
21
|
async fetcher({ method, headers, body, url }) {
|
24
22
|
try {
|
25
23
|
const res = await fetch(url, {
|
@@ -30,26 +28,39 @@ export class GoogleDriveStorage {
|
|
30
28
|
}),
|
31
29
|
body,
|
32
30
|
});
|
33
|
-
// Check
|
34
|
-
const
|
31
|
+
// Check the Content-Type to ensure it's JSON before parsing
|
32
|
+
const contentType = res.headers.get('Content-Type') || '';
|
33
|
+
let data;
|
34
|
+
if (contentType.includes('application/json')) {
|
35
|
+
data = await res.json();
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
const text = await res.text();
|
39
|
+
console.error('Unexpected Response Type:', text);
|
40
|
+
throw new Error(`Expected JSON response but got: ${contentType}`);
|
41
|
+
}
|
42
|
+
// Handle non-200 HTTP responses
|
35
43
|
if (!res.ok) {
|
36
44
|
console.error('Error Response:', JSON.stringify(data));
|
37
|
-
throw new Error(data
|
45
|
+
throw new Error(data?.error?.message || 'Unknown error occurred');
|
38
46
|
}
|
39
47
|
return data;
|
40
48
|
}
|
41
49
|
catch (error) {
|
42
|
-
console.error('Error fetching data:', error.message);
|
50
|
+
console.error('Error fetching data:', error.message || error);
|
43
51
|
throw error;
|
44
52
|
}
|
45
53
|
}
|
46
|
-
// Method to search for files in Google Drive by query
|
47
54
|
async searchFiles(query) {
|
48
55
|
const result = await this.fetcher({
|
49
56
|
method: 'GET',
|
50
57
|
headers: {},
|
51
58
|
url: `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&trashed=false&fields=files(id,name,mimeType,parents)`,
|
52
59
|
});
|
60
|
+
if (!result.files) {
|
61
|
+
console.error('No files found:', result);
|
62
|
+
return [];
|
63
|
+
}
|
53
64
|
return result.files;
|
54
65
|
}
|
55
66
|
async createFolder(folderName, parentFolderId) {
|
@@ -67,7 +78,7 @@ export class GoogleDriveStorage {
|
|
67
78
|
console.log('Folder ID:', folder.id);
|
68
79
|
return folder.id;
|
69
80
|
}
|
70
|
-
async
|
81
|
+
async saveFile({ data, folderId }) {
|
71
82
|
try {
|
72
83
|
// Define file metadata, ensure correct folder is assigned
|
73
84
|
const fileMetadata = {
|
@@ -79,86 +90,32 @@ export class GoogleDriveStorage {
|
|
79
90
|
const formData = new FormData();
|
80
91
|
formData.append('metadata', new Blob([JSON.stringify(fileMetadata)], { type: 'application/json' }));
|
81
92
|
formData.append('file', new Blob([data.body], { type: fileMetadata.mimeType })); // Set file data and MIME type
|
93
|
+
// Upload file to Google Drive
|
82
94
|
const file = await this.fetcher({
|
83
95
|
method: 'POST',
|
84
96
|
headers: {},
|
85
97
|
body: formData,
|
86
|
-
url: uploadUrl,
|
87
|
-
});
|
88
|
-
console.log('File uploaded successfully:', file.id);
|
89
|
-
return file;
|
90
|
-
}
|
91
|
-
catch (error) {
|
92
|
-
console.error('Error uploading file:', error.message);
|
93
|
-
return null;
|
94
|
-
}
|
95
|
-
}
|
96
|
-
/**
|
97
|
-
* Add comment to VC
|
98
|
-
* @param fileId - th id of VC file
|
99
|
-
* @returns
|
100
|
-
*/
|
101
|
-
async addCommentToFile(vcFileId, recommendationFileId) {
|
102
|
-
if (!recommendationFileId || !vcFileId || !this.accessToken) {
|
103
|
-
throw new Error('Missing required parameters: fileId, commentText, or accessToken');
|
104
|
-
}
|
105
|
-
const url = `https://www.googleapis.com/drive/v3/files/${vcFileId}/comments?fields=id,content,createdTime`;
|
106
|
-
const body = {
|
107
|
-
content: generateViewLink(recommendationFileId),
|
108
|
-
};
|
109
|
-
try {
|
110
|
-
const response = await fetch(url, {
|
111
|
-
method: 'POST',
|
112
|
-
headers: {
|
113
|
-
Authorization: `Bearer ${this.accessToken}`,
|
114
|
-
'Content-Type': 'application/json',
|
115
|
-
},
|
116
|
-
body: JSON.stringify(body),
|
98
|
+
url: `${uploadUrl}&fields=id,parents`, // Request the file ID and parent folder IDs
|
117
99
|
});
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
}
|
126
|
-
catch (error) {
|
127
|
-
console.error('Error adding comment to file:', error);
|
128
|
-
throw error;
|
129
|
-
}
|
130
|
-
}
|
131
|
-
/**
|
132
|
-
* Add commenter role to a file
|
133
|
-
* @param fileId
|
134
|
-
* @returns
|
135
|
-
*/
|
136
|
-
async addCommenterRoleToFile(fileId) {
|
137
|
-
const url = `https://www.googleapis.com/drive/v3/files/${fileId}/permissions`;
|
138
|
-
const body = {
|
139
|
-
role: 'commenter',
|
140
|
-
type: 'anyone',
|
141
|
-
};
|
142
|
-
try {
|
143
|
-
const response = await fetch(url, {
|
100
|
+
// Set the file permission to "Anyone with the link" can view
|
101
|
+
const permissionUrl = `https://www.googleapis.com/drive/v3/files/${file.id}/permissions`;
|
102
|
+
const permissionData = {
|
103
|
+
role: 'reader',
|
104
|
+
type: 'anyone', // Public access
|
105
|
+
};
|
106
|
+
await this.fetcher({
|
144
107
|
method: 'POST',
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
},
|
149
|
-
body: JSON.stringify(body),
|
108
|
+
url: permissionUrl,
|
109
|
+
headers: {},
|
110
|
+
body: JSON.stringify(permissionData),
|
150
111
|
});
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
}
|
155
|
-
const result = await response.json();
|
156
|
-
console.log('Permission added successfully:', result);
|
157
|
-
return result;
|
112
|
+
console.log('Permission set to public for file:', file.id);
|
113
|
+
console.log('Parent folder IDs:', file.parents);
|
114
|
+
return file;
|
158
115
|
}
|
159
116
|
catch (error) {
|
160
|
-
console.error('Error
|
161
|
-
|
117
|
+
console.error('Error uploading file or setting permission:', error.message);
|
118
|
+
return null;
|
162
119
|
}
|
163
120
|
}
|
164
121
|
/**
|
@@ -167,25 +124,24 @@ export class GoogleDriveStorage {
|
|
167
124
|
* @returns file content
|
168
125
|
*/
|
169
126
|
async retrieve(id) {
|
170
|
-
const metadataUrl = `https://www.googleapis.com/drive/v3/files/${id}?fields=name`;
|
127
|
+
const metadataUrl = `https://www.googleapis.com/drive/v3/files/${id}?fields=id,name`;
|
171
128
|
const dataUrl = `https://www.googleapis.com/drive/v3/files/${id}?alt=media`;
|
172
129
|
try {
|
173
|
-
|
174
|
-
|
175
|
-
const metadataResponse = await fetch(metadataUrl, {
|
130
|
+
// Initial "touch" request to ensure file accessibility for the current user
|
131
|
+
const touchResponse = await fetch(metadataUrl, {
|
176
132
|
method: 'GET',
|
177
133
|
headers: {
|
178
134
|
Authorization: `Bearer ${this.accessToken}`,
|
179
135
|
},
|
180
136
|
});
|
181
|
-
if (!
|
182
|
-
const errorData = await
|
183
|
-
console.error(`Failed to
|
137
|
+
if (!touchResponse.ok) {
|
138
|
+
const errorData = await touchResponse.json();
|
139
|
+
console.error(`Failed to "touch" file for accessibility with ID ${id}:`, errorData);
|
184
140
|
return null;
|
185
141
|
}
|
186
|
-
|
142
|
+
// Fetch file metadata to get the name
|
143
|
+
const metadata = await touchResponse.json();
|
187
144
|
const fileName = metadata.name;
|
188
|
-
console.log(`File name retrieved: ${fileName}`);
|
189
145
|
// Fetch actual file data
|
190
146
|
const dataResponse = await fetch(dataUrl, {
|
191
147
|
method: 'GET',
|
@@ -221,9 +177,8 @@ export class GoogleDriveStorage {
|
|
221
177
|
else {
|
222
178
|
fileData = await dataResponse.arrayBuffer(); // Fallback for other binary types
|
223
179
|
}
|
224
|
-
console.log('🚀 ~ GoogleDriveStorage ~ retrieve ~ fileData:', fileData);
|
225
180
|
// Return file ID, name, and data
|
226
|
-
return { id, name: fileName, data: fileData };
|
181
|
+
return { id: metadata.id, name: fileName, data: fileData };
|
227
182
|
}
|
228
183
|
catch (error) {
|
229
184
|
console.error(`Error retrieving file with ID ${id}:`, error.message);
|
@@ -232,7 +187,7 @@ export class GoogleDriveStorage {
|
|
232
187
|
}
|
233
188
|
/**
|
234
189
|
* Get folder by folderId, if folderId == null you will have them all
|
235
|
-
* @param
|
190
|
+
* @param folderId [Optional]
|
236
191
|
* @returns
|
237
192
|
*/
|
238
193
|
findFolders = async (folderId) => {
|
@@ -294,22 +249,6 @@ export class GoogleDriveStorage {
|
|
294
249
|
return null;
|
295
250
|
}
|
296
251
|
};
|
297
|
-
async getFileComments(fileId) {
|
298
|
-
try {
|
299
|
-
// Fetch comments on the file using Google Drive API
|
300
|
-
const commentsResponse = await this.fetcher({
|
301
|
-
method: 'GET',
|
302
|
-
headers: {},
|
303
|
-
url: `https://www.googleapis.com/drive/v3/files/${fileId}/comments?fields=comments(content,author/displayName,createdTime)`,
|
304
|
-
});
|
305
|
-
// Return the comments data if available
|
306
|
-
return commentsResponse.comments || []; // Return an empty array if no comments
|
307
|
-
}
|
308
|
-
catch (error) {
|
309
|
-
console.error(`Failed to fetch comments for file ID: ${fileId}`, error);
|
310
|
-
return []; // Handle errors by returning an empty array or some error indication
|
311
|
-
}
|
312
|
-
}
|
313
252
|
/**
|
314
253
|
* Get all files content for the specified type ('KEYPAIRs' | 'VCs' | 'SESSIONs' | 'DIDs' | 'RECOMMENDATIONs')
|
315
254
|
* @param type
|
@@ -317,42 +256,60 @@ export class GoogleDriveStorage {
|
|
317
256
|
*/
|
318
257
|
async getAllFilesByType(type) {
|
319
258
|
try {
|
320
|
-
// Step 1: Find
|
259
|
+
// Step 1: Find the root 'Credentials' folder
|
321
260
|
const rootFolders = await this.findFolders();
|
322
261
|
const credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
|
323
|
-
if (!credentialsFolder)
|
262
|
+
if (!credentialsFolder) {
|
263
|
+
console.error('Credentials folder not found.');
|
324
264
|
return [];
|
265
|
+
}
|
325
266
|
const credentialsFolderId = credentialsFolder.id;
|
326
|
-
// Step 2:
|
267
|
+
// Step 2: Handle special case for 'VCs'
|
268
|
+
if (type === 'VCs') {
|
269
|
+
// Find the 'VCs' folder under 'Credentials'
|
270
|
+
const subfolders = await this.findFolders(credentialsFolderId);
|
271
|
+
const targetFolder = subfolders.find((f) => f.name === 'VCs');
|
272
|
+
if (!targetFolder) {
|
273
|
+
console.error(`Folder for type ${type} not found.`);
|
274
|
+
return [];
|
275
|
+
}
|
276
|
+
const targetFolderId = targetFolder.id;
|
277
|
+
// Fetch all 'VC-timestamp' subfolders under 'VCs'
|
278
|
+
const vcSubfolders = await this.findFolders(targetFolderId);
|
279
|
+
// Retrieve all 'VC.json' files from each 'VC-timestamp' subfolder
|
280
|
+
const fileContents = [];
|
281
|
+
for (const folder of vcSubfolders) {
|
282
|
+
const files = await this.findFilesUnderFolder(folder.id);
|
283
|
+
// Fetch the content of each file
|
284
|
+
for (const file of files) {
|
285
|
+
try {
|
286
|
+
const content = await this.retrieve(file.id);
|
287
|
+
fileContents.push(content);
|
288
|
+
}
|
289
|
+
catch (error) {
|
290
|
+
console.error(`Error retrieving content for file ${file.id}:`, error);
|
291
|
+
}
|
292
|
+
}
|
293
|
+
}
|
294
|
+
return fileContents;
|
295
|
+
}
|
296
|
+
// Step 3: Generic handling for other types
|
327
297
|
const subfolders = await this.findFolders(credentialsFolderId);
|
328
298
|
const targetFolder = subfolders.find((f) => f.name === type);
|
329
|
-
if (!targetFolder)
|
299
|
+
if (!targetFolder) {
|
300
|
+
console.error(`Folder for type ${type} not found.`);
|
330
301
|
return [];
|
331
|
-
|
302
|
+
}
|
332
303
|
const filesResponse = await this.fetcher({
|
333
304
|
method: 'GET',
|
334
305
|
headers: {},
|
335
306
|
url: `https://www.googleapis.com/drive/v3/files?q='${targetFolder.id}' in parents and trashed=false&fields=files(id,name,mimeType,parents)`,
|
336
307
|
});
|
337
308
|
const files = filesResponse.files;
|
338
|
-
// Step 4: Fetch the content and comments of each file
|
339
309
|
const fileContents = await Promise.all(files.map(async (file) => {
|
340
|
-
|
341
|
-
const content = await this.fetcher({
|
342
|
-
method: 'GET',
|
343
|
-
headers: {},
|
344
|
-
url: `https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`,
|
345
|
-
});
|
346
|
-
// Fetch file comments (if applicable)
|
347
|
-
const comments = await this.getFileComments(file.id);
|
348
|
-
return {
|
349
|
-
id: file.id,
|
350
|
-
name: file.name,
|
351
|
-
content,
|
352
|
-
comments: comments.map((comment) => comment.content),
|
353
|
-
};
|
310
|
+
return await this.retrieve(file.id);
|
354
311
|
}));
|
355
|
-
return fileContents;
|
312
|
+
return fileContents;
|
356
313
|
}
|
357
314
|
catch (error) {
|
358
315
|
console.error(`Error getting files of type ${type}:`, error);
|
@@ -384,6 +341,81 @@ export class GoogleDriveStorage {
|
|
384
341
|
throw error;
|
385
342
|
}
|
386
343
|
}
|
344
|
+
async findFileByName(name) {
|
345
|
+
// find the file named under Credentials folder
|
346
|
+
const rootFolders = await this.findFolders();
|
347
|
+
const credentialsFolderId = rootFolders.find((f) => f.name === 'Credentials')?.id;
|
348
|
+
if (!credentialsFolderId)
|
349
|
+
throw new Error('Credentials folder not found');
|
350
|
+
const files = await this.searchFiles(`'${credentialsFolderId}' in parents and name='${name}'`);
|
351
|
+
return files[0];
|
352
|
+
}
|
353
|
+
async findFilesUnderFolder(folderId) {
|
354
|
+
if (!folderId)
|
355
|
+
throw new Error('Folder ID is required');
|
356
|
+
console.log('🚀 ~ GoogleDriveStorage ~ findFilesUnderFolder ~ folderId', folderId);
|
357
|
+
const files = await this.searchFiles(`'${folderId}' in parents`);
|
358
|
+
return files;
|
359
|
+
}
|
360
|
+
async updateFileData(fileId, data) {
|
361
|
+
const fileMetadata = {
|
362
|
+
name: data.fileName,
|
363
|
+
mimeType: data.mimeType,
|
364
|
+
};
|
365
|
+
let uploadUrl = `https://www.googleapis.com/upload/drive/v3/files/${fileId}?uploadType=multipart`;
|
366
|
+
const formData = new FormData();
|
367
|
+
formData.append('metadata', new Blob([JSON.stringify(fileMetadata)], { type: 'application/json' }));
|
368
|
+
formData.append('file', new Blob([data.body], { type: fileMetadata.mimeType }));
|
369
|
+
const updatedFile = await this.fetcher({
|
370
|
+
method: 'PATCH',
|
371
|
+
headers: {},
|
372
|
+
body: JSON.stringify(formData),
|
373
|
+
url: `${uploadUrl}&fields=id,parents`,
|
374
|
+
});
|
375
|
+
console.log('File updated:', updatedFile);
|
376
|
+
return updatedFile;
|
377
|
+
}
|
378
|
+
async getFileParents(fileId) {
|
379
|
+
console.log('🚀 ~ GoogleDriveStorage ~ getFileParents ~ fileId', fileId);
|
380
|
+
const file = await this.fetcher({
|
381
|
+
method: 'GET',
|
382
|
+
headers: {},
|
383
|
+
url: `https://www.googleapis.com/drive/v3/files/${fileId}?fields=parents`,
|
384
|
+
});
|
385
|
+
return file.parents;
|
386
|
+
}
|
387
|
+
async updateRelationsFile({ relationsFileId, recommendationFileId }) {
|
388
|
+
const relationsFileContent = await this.retrieve(relationsFileId);
|
389
|
+
const relationsData = relationsFileContent.data;
|
390
|
+
relationsData.recommendations.push(recommendationFileId);
|
391
|
+
const updatedContent = JSON.stringify(relationsData);
|
392
|
+
const updateResponse = await this.fetcher({
|
393
|
+
method: 'PATCH',
|
394
|
+
headers: {
|
395
|
+
'Content-Type': 'application/json',
|
396
|
+
},
|
397
|
+
body: updatedContent,
|
398
|
+
url: `https://www.googleapis.com/upload/drive/v3/files/${relationsFileId}?uploadType=media`,
|
399
|
+
});
|
400
|
+
console.log('🚀 ~ GoogleDriveStorage ~ updateRelationsFile ~ updateResponse:', updateResponse);
|
401
|
+
return updateResponse;
|
402
|
+
}
|
403
|
+
async createRelationsFile({ vcFolderId }) {
|
404
|
+
const files = await this.findFilesUnderFolder(vcFolderId);
|
405
|
+
const vcFile = files.find((file) => file.name === 'VC');
|
406
|
+
const relationsFile = await this.saveFile({
|
407
|
+
data: {
|
408
|
+
fileName: 'RELATIONS',
|
409
|
+
mimeType: 'application/json',
|
410
|
+
body: JSON.stringify({
|
411
|
+
vc_id: vcFile.id,
|
412
|
+
recommendations: [],
|
413
|
+
}),
|
414
|
+
},
|
415
|
+
folderId: vcFolderId,
|
416
|
+
});
|
417
|
+
return relationsFile;
|
418
|
+
}
|
387
419
|
/**
|
388
420
|
* Delete file by id
|
389
421
|
* @param id
|
@@ -1,4 +1,11 @@
|
|
1
|
-
import { DidDocument, KeyPair, VerifiableCredential } from '../../types/credential.js';
|
1
|
+
import { DidDocument, KeyPair, FormDataI, RecommendationFormDataI, VerifiableCredential } from '../../types/credential.js';
|
2
|
+
interface SignPropsI {
|
3
|
+
data: FormDataI | RecommendationFormDataI;
|
4
|
+
type: 'VC' | 'RECOMMENDATION';
|
5
|
+
keyPair: KeyPair;
|
6
|
+
issuerId: string;
|
7
|
+
vcFileId?: string;
|
8
|
+
}
|
2
9
|
/**
|
3
10
|
* Class representing the Credential Engine.
|
4
11
|
* @class CredentialEngine
|
@@ -12,7 +19,6 @@ import { DidDocument, KeyPair, VerifiableCredential } from '../../types/credenti
|
|
12
19
|
* @method signPresentation - Sign a Verifiable Presentation (VP).
|
13
20
|
*/
|
14
21
|
export declare class CredentialEngine {
|
15
|
-
private uuid;
|
16
22
|
private storage;
|
17
23
|
private keyPair;
|
18
24
|
constructor(accessToken: string);
|
@@ -28,6 +34,10 @@ export declare class CredentialEngine {
|
|
28
34
|
didDocument: DidDocument;
|
29
35
|
keyPair: KeyPair;
|
30
36
|
}>;
|
37
|
+
findKeysAndDIDs(): Promise<{
|
38
|
+
didDocument: any;
|
39
|
+
keyPair: any;
|
40
|
+
}>;
|
31
41
|
/**
|
32
42
|
* Create a new DID with user metamask address as controller
|
33
43
|
* @param walletrAddress
|
@@ -43,10 +53,12 @@ export declare class CredentialEngine {
|
|
43
53
|
* @param {'VC' | 'RECOMMENDATION'} type - The signature type.
|
44
54
|
* @param {string} issuerId - The ID of the issuer [currently we put it as the did id]
|
45
55
|
* @param {KeyPair} keyPair - The key pair to use for signing.
|
56
|
+
* @param {FormDataI | RecommendationFormDataI} formData - The form data to include in the VC.
|
57
|
+
* @param {string} VCId - The ID of the credential when the type is RECOMMENDATION
|
46
58
|
* @returns {Promise<Credential>} The signed VC.
|
47
59
|
* @throws Will throw an error if VC signing fails.
|
48
60
|
*/
|
49
|
-
signVC(
|
61
|
+
signVC({ data, type, keyPair, issuerId, vcFileId }: SignPropsI): Promise<any>;
|
50
62
|
/**
|
51
63
|
* Verify a Verifiable Credential (VC)
|
52
64
|
* @param {object} credential - The Verifiable Credential to verify.
|
@@ -67,3 +79,4 @@ export declare class CredentialEngine {
|
|
67
79
|
*/
|
68
80
|
signPresentation(presentation: any): Promise<any>;
|
69
81
|
}
|
82
|
+
export {};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { DataToSaveI } from '../../types';
|
1
|
+
import { DataToSaveI, FilesType } from '../../types';
|
2
2
|
interface FileContent {
|
3
3
|
name: string;
|
4
4
|
content: any;
|
@@ -25,34 +25,23 @@ export declare class GoogleDriveStorage {
|
|
25
25
|
private fetcher;
|
26
26
|
private searchFiles;
|
27
27
|
createFolder(folderName: string, parentFolderId?: string): Promise<string>;
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
* Add comment to VC
|
33
|
-
* @param fileId - th id of VC file
|
34
|
-
* @returns
|
35
|
-
*/
|
36
|
-
addCommentToFile(vcFileId: string, recommendationFileId: string): Promise<any>;
|
37
|
-
/**
|
38
|
-
* Add commenter role to a file
|
39
|
-
* @param fileId
|
40
|
-
* @returns
|
41
|
-
*/
|
42
|
-
addCommenterRoleToFile(fileId: string): Promise<any>;
|
28
|
+
saveFile({ data, folderId }: {
|
29
|
+
data: DataToSaveI;
|
30
|
+
folderId: string;
|
31
|
+
}): Promise<any>;
|
43
32
|
/**
|
44
33
|
* Get file from google drive by id
|
45
34
|
* @param id
|
46
35
|
* @returns file content
|
47
36
|
*/
|
48
37
|
retrieve(id: string): Promise<{
|
49
|
-
id: string;
|
50
38
|
name: string;
|
51
39
|
data: any;
|
40
|
+
id: string;
|
52
41
|
} | null>;
|
53
42
|
/**
|
54
43
|
* Get folder by folderId, if folderId == null you will have them all
|
55
|
-
* @param
|
44
|
+
* @param folderId [Optional]
|
56
45
|
* @returns
|
57
46
|
*/
|
58
47
|
findFolders: (folderId?: string) => Promise<any[]>;
|
@@ -62,7 +51,6 @@ export declare class GoogleDriveStorage {
|
|
62
51
|
* @returns last file content from folder by folderId
|
63
52
|
*/
|
64
53
|
findLastFile: (folderId: string) => Promise<any>;
|
65
|
-
getFileComments(fileId: string): Promise<any>;
|
66
54
|
/**
|
67
55
|
* Get all files content for the specified type ('KEYPAIRs' | 'VCs' | 'SESSIONs' | 'DIDs' | 'RECOMMENDATIONs')
|
68
56
|
* @param type
|
@@ -76,6 +64,17 @@ export declare class GoogleDriveStorage {
|
|
76
64
|
* @returns The updated file metadata, including the new name
|
77
65
|
*/
|
78
66
|
updateFileName(fileId: string, newFileName: string): Promise<any>;
|
67
|
+
findFileByName(name: FilesType): Promise<any>;
|
68
|
+
findFilesUnderFolder(folderId: string): Promise<any[]>;
|
69
|
+
updateFileData(fileId: string, data: DataToSaveI): Promise<any>;
|
70
|
+
getFileParents(fileId: string): Promise<any>;
|
71
|
+
updateRelationsFile({ relationsFileId, recommendationFileId }: {
|
72
|
+
relationsFileId: string;
|
73
|
+
recommendationFileId: string;
|
74
|
+
}): Promise<any>;
|
75
|
+
createRelationsFile({ vcFolderId }: {
|
76
|
+
vcFolderId: string;
|
77
|
+
}): Promise<any>;
|
79
78
|
/**
|
80
79
|
* Delete file by id
|
81
80
|
* @param id
|