@cooperation/vc-storage 1.0.13 → 1.0.14

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@ export * from './models/GoogleDriveStorage.js';
2
2
  export * from './models/CredentialEngine.js';
3
3
  export * from './utils/google.js';
4
4
  export * from './utils/presentation.js';
5
+ export * from './models/Resume.js';
@@ -51,6 +51,22 @@ export class GoogleDriveStorage {
51
51
  throw error;
52
52
  }
53
53
  }
54
+ async getFileContent(fileId) {
55
+ const url = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`;
56
+ try {
57
+ const response = await this.fetcher({
58
+ method: 'GET',
59
+ headers: {}, // Add additional headers if required
60
+ url,
61
+ });
62
+ console.log(`Content fetched for file ID: ${fileId}`);
63
+ return response; // This could be text, JSON, or binary, depending on the file type
64
+ }
65
+ catch (error) {
66
+ console.error(`Error fetching content for file ID: ${fileId}:`, error.message);
67
+ throw new Error(`Failed to fetch content for file ID: ${fileId}`);
68
+ }
69
+ }
54
70
  async searchFiles(query) {
55
71
  const result = await this.fetcher({
56
72
  method: 'GET',
@@ -63,11 +79,14 @@ export class GoogleDriveStorage {
63
79
  }
64
80
  return result.files;
65
81
  }
66
- async createFolder(folderName, parentFolderId) {
82
+ async createFolder({ folderName, parentFolderId }) {
83
+ if (!parentFolderId) {
84
+ throw new Error(`Parent folder ID must be provided when creating folder "${folderName}".`);
85
+ }
67
86
  const metadata = {
68
87
  name: folderName,
69
88
  mimeType: 'application/vnd.google-apps.folder',
70
- parents: parentFolderId ? [parentFolderId] : [],
89
+ parents: [parentFolderId], // Explicitly associate with the parent folder
71
90
  };
72
91
  const folder = await this.fetcher({
73
92
  method: 'POST',
@@ -75,22 +94,35 @@ export class GoogleDriveStorage {
75
94
  body: JSON.stringify(metadata),
76
95
  url: 'https://www.googleapis.com/drive/v3/files',
77
96
  });
78
- console.log('Folder ID:', folder.id);
79
- return folder.id;
97
+ console.log(`Folder created: "${folderName}" with ID: ${folder.id}, Parent: ${parentFolderId}`);
98
+ return folder;
80
99
  }
81
100
  async saveFile({ data, folderId }) {
82
101
  try {
102
+ if (!folderId) {
103
+ throw new Error('Folder ID is required to save a file.');
104
+ }
83
105
  // Define file metadata, ensure correct folder is assigned
84
106
  const fileMetadata = {
85
107
  name: data.fileName,
86
108
  parents: [folderId], // Specify the folder ID
87
- mimeType: data.mimeType,
109
+ mimeType: data.mimeType || 'application/json',
88
110
  };
111
+ // make sure the parentId is not in trash
112
+ const folder = await this.fetcher({
113
+ method: 'GET',
114
+ headers: {},
115
+ url: `https://www.googleapis.com/drive/v3/files/${folderId}?fields=trashed`,
116
+ });
117
+ if (folder.trashed) {
118
+ throw new Error('Parent folder is in trash');
119
+ }
89
120
  let uploadUrl = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart';
90
121
  const formData = new FormData();
91
122
  formData.append('metadata', new Blob([JSON.stringify(fileMetadata)], { type: 'application/json' }));
92
123
  formData.append('file', new Blob([data.body], { type: fileMetadata.mimeType })); // Set file data and MIME type
93
124
  // Upload file to Google Drive
125
+ console.log('Uploading file...');
94
126
  const file = await this.fetcher({
95
127
  method: 'POST',
96
128
  headers: {},
@@ -109,8 +141,6 @@ export class GoogleDriveStorage {
109
141
  headers: {},
110
142
  body: JSON.stringify(permissionData),
111
143
  });
112
- console.log('Permission set to public for file:', file.id);
113
- console.log('Parent folder IDs:', file.parents);
114
144
  return file;
115
145
  }
116
146
  catch (error) {
@@ -283,18 +313,6 @@ export class GoogleDriveStorage {
283
313
  return await this.retrieve(file.id);
284
314
  }));
285
315
  }));
286
- // for (const folder of vcSubfolders) {
287
- // const files = await this.findFilesUnderFolder(folder.id);
288
- // // Fetch the content of each file
289
- // for (const file of files) {
290
- // try {
291
- // const content = await this.retrieve(file.id);
292
- // fileContents.push(content);
293
- // } catch (error) {
294
- // console.error(`Error retrieving content for file ${file.id}:`, error);
295
- // }
296
- // }
297
- // }
298
316
  return fileContents;
299
317
  }
300
318
  // Step 3: Generic handling for other types
@@ -358,8 +376,24 @@ export class GoogleDriveStorage {
358
376
  if (!folderId)
359
377
  throw new Error('Folder ID is required');
360
378
  console.log('🚀 ~ GoogleDriveStorage ~ findFilesUnderFolder ~ folderId', folderId);
379
+ // Fetch files under the folder
361
380
  const files = await this.searchFiles(`'${folderId}' in parents`);
362
- return files;
381
+ if (files.length === 0) {
382
+ console.log('No files found in the folder.');
383
+ return [];
384
+ }
385
+ // Fetch content for each file
386
+ const filesWithContent = await Promise.all(files.map(async (file) => {
387
+ try {
388
+ const content = await this.getFileContent(file.id);
389
+ return { ...file, content }; // Merge file metadata with its content
390
+ }
391
+ catch (error) {
392
+ console.error(`Error fetching content for file "${file.name}" (ID: ${file.id}):`, error);
393
+ return { ...file, content: null }; // Handle errors gracefully
394
+ }
395
+ }));
396
+ return filesWithContent;
363
397
  }
364
398
  async updateFileData(fileId, data) {
365
399
  const fileMetadata = {
@@ -0,0 +1,134 @@
1
+ export const resumeFolderTypes = {
2
+ root: 'RESUMES_AUTHOR',
3
+ nonSigned: 'NON_SIGNED_RESUMES',
4
+ signed: 'SIGNED_RESUMES',
5
+ };
6
+ export class StorageHandler {
7
+ storage;
8
+ constructor(storage) {
9
+ this.storage = storage;
10
+ }
11
+ async getOrCreateFolder(folderName, parentId) {
12
+ console.log(`Searching for folder: "${folderName}", Parent ID: ${parentId}`);
13
+ const folders = await this.storage.findFolders(parentId); // Fetch all child folders of the parent
14
+ let folder = folders.find((folder) => {
15
+ console.log('🚀 ~ StorageHandler ~ getOrCreateFolder ~ folder:', folder);
16
+ return folder.name === folderName;
17
+ });
18
+ if (folder && folder.name === 'RESUMES_AUTHOR') {
19
+ console.log('🚀 ~ StorageHandler ~ getOrCreateFolder ~ folder:', folder);
20
+ }
21
+ if (!folder) {
22
+ console.log(`Folder "${folderName}" not found. Creating under parent: ${parentId}`);
23
+ folder = await this.storage.createFolder({
24
+ folderName,
25
+ parentFolderId: parentId,
26
+ });
27
+ }
28
+ console.log(`Resolved folder: "${folderName}" with ID: ${folder.id}`);
29
+ return folder;
30
+ }
31
+ async findFilesInFolder(folderName) {
32
+ const folders = await this.storage.findFolders();
33
+ const folder = folders.find((folder) => folder.name === folderName);
34
+ if (!folder) {
35
+ throw new Error(`${folderName} folder not found`);
36
+ }
37
+ return this.storage.findFilesUnderFolder(folder.id);
38
+ }
39
+ }
40
+ export class Resume extends StorageHandler {
41
+ constructor(storage) {
42
+ super(storage);
43
+ }
44
+ signResume({ resume }) {
45
+ // genetrate unsingned resume
46
+ // sign resume
47
+ }
48
+ async saveResume({ resume, type }) {
49
+ try {
50
+ // Get or create the root folder
51
+ console.log('Checking for root folder...');
52
+ const rootFolders = await this.storage.findFolders();
53
+ let rootFolder = rootFolders.find((folder) => folder.name === resumeFolderTypes.root);
54
+ if (!rootFolder) {
55
+ console.log('Root folder not found. Creating...');
56
+ rootFolder = await this.storage.createFolder({ folderName: resumeFolderTypes.root, parentFolderId: 'root' });
57
+ }
58
+ console.log('🚀 Root folder resolved:', rootFolder);
59
+ // Get or create the subfolder
60
+ const subFolderName = type === 'sign' ? resumeFolderTypes.signed : resumeFolderTypes.nonSigned;
61
+ const subFolder = await this.getOrCreateFolder(subFolderName, rootFolder.id);
62
+ console.log(`🚀 Subfolder resolved for type "${type}":`, subFolder);
63
+ // Save the file in the subfolder
64
+ console.log(`Saving file in subfolder "${subFolderName}"...`);
65
+ const savedResume = await this.storage.saveFile({
66
+ folderId: subFolder.id, // Ensure this points to the subfolder
67
+ data: resume,
68
+ });
69
+ console.log(`🚀 File saved in folder "${subFolderName}" (ID: ${subFolder.id}):`, savedResume);
70
+ return savedResume;
71
+ }
72
+ catch (error) {
73
+ throw new Error(`Error while saving ${type} resume: ${error.message}`);
74
+ }
75
+ }
76
+ async find() {
77
+ try {
78
+ const signedResumes = await this.getSignedResumes();
79
+ const nonSignedResumes = await this.getNonSignedResumes();
80
+ return {
81
+ signed: signedResumes,
82
+ nonSigned: nonSignedResumes,
83
+ };
84
+ }
85
+ catch (error) {
86
+ throw new Error('Error while fetching resume: ' + error.message);
87
+ }
88
+ }
89
+ async getSignedResumes() {
90
+ try {
91
+ // Find the root folder first
92
+ const rootFolder = await this.findRootFolder();
93
+ // Find or create the signed resumes folder
94
+ const signedFolder = await this.getOrCreateFolder(resumeFolderTypes.signed, rootFolder.id);
95
+ // Retrieve all files from the signed folder
96
+ const files = await this.storage.findFilesUnderFolder(signedFolder.id);
97
+ console.log(`Files found in "SIGNED_RESUMES":`, files);
98
+ return files;
99
+ }
100
+ catch (error) {
101
+ throw new Error('Error while fetching signed resumes: ' + error.message);
102
+ }
103
+ }
104
+ async getNonSignedResumes() {
105
+ try {
106
+ // Find the root folder first
107
+ const rootFolder = await this.findRootFolder();
108
+ console.log('🚀 ~ Resume ~ getNonSignedResumes ~ rootFolder:', rootFolder);
109
+ // Find or create the non-signed resumes folder
110
+ const nonSignedFolder = await this.getOrCreateFolder(resumeFolderTypes.nonSigned, rootFolder.id);
111
+ console.log('🚀 ~ Resume ~ getNonSignedResumes ~ nonSignedFolder:', nonSignedFolder);
112
+ // Retrieve all files from the non-signed folder
113
+ const files = await this.storage.findFilesUnderFolder(nonSignedFolder.id);
114
+ console.log(`Files found in "NON_SIGNED_RESUMES":`, files);
115
+ return files;
116
+ }
117
+ catch (error) {
118
+ throw new Error('Error while fetching non-signed resumes: ' + error.message);
119
+ }
120
+ }
121
+ async findRootFolder() {
122
+ console.log('Searching for the root folder...');
123
+ const rootFolders = await this.storage.findFolders(); // Fetch all root-level folders
124
+ const rootFolder = rootFolders.find((folder) => folder.name === resumeFolderTypes.root);
125
+ if (!rootFolder) {
126
+ throw new Error(`Root folder "${resumeFolderTypes.root}" not found in the root directory.`);
127
+ }
128
+ console.log('Root folder found:', rootFolder);
129
+ return rootFolder;
130
+ }
131
+ generarteUnsignedResume() { }
132
+ isResumeFolderExist() { }
133
+ }
134
+ export default Resume;
@@ -2,3 +2,4 @@ export * from './models/GoogleDriveStorage.js';
2
2
  export * from './models/CredentialEngine.js';
3
3
  export * from './utils/google.js';
4
4
  export * from './utils/presentation.js';
5
+ export * from './models/Resume.js';
@@ -1,4 +1,4 @@
1
- import { DataToSaveI, FilesType } from '../../types';
1
+ import { DataToSaveI } from '../../types';
2
2
  interface FileContent {
3
3
  name: string;
4
4
  content: any;
@@ -23,10 +23,19 @@ export declare class GoogleDriveStorage {
23
23
  private accessToken;
24
24
  constructor(accessToken: string);
25
25
  private fetcher;
26
+ private getFileContent;
26
27
  private searchFiles;
27
- createFolder(folderName: string, parentFolderId?: string): Promise<string>;
28
+ createFolder({ folderName, parentFolderId }: {
29
+ folderName: string;
30
+ parentFolderId: string;
31
+ }): Promise<{
32
+ id: string;
33
+ name: string;
34
+ mimeType: string;
35
+ parents: string[];
36
+ }>;
28
37
  saveFile({ data, folderId }: {
29
- data: DataToSaveI;
38
+ data: any;
30
39
  folderId: string;
31
40
  }): Promise<any>;
32
41
  /**
@@ -64,7 +73,7 @@ export declare class GoogleDriveStorage {
64
73
  * @returns The updated file metadata, including the new name
65
74
  */
66
75
  updateFileName(fileId: string, newFileName: string): Promise<any>;
67
- findFileByName(name: FilesType): Promise<any>;
76
+ findFileByName(name: string): Promise<any>;
68
77
  findFilesUnderFolder(folderId: string): Promise<any[]>;
69
78
  updateFileData(fileId: string, data: DataToSaveI): Promise<any>;
70
79
  getFileParents(fileId: string): Promise<any>;
@@ -0,0 +1,32 @@
1
+ import { GoogleDriveStorage } from './GoogleDriveStorage';
2
+ export declare const resumeFolderTypes: {
3
+ root: string;
4
+ nonSigned: string;
5
+ signed: string;
6
+ };
7
+ export declare class StorageHandler {
8
+ protected storage: GoogleDriveStorage;
9
+ constructor(storage: GoogleDriveStorage);
10
+ protected getOrCreateFolder(folderName: string, parentId: string): Promise<any>;
11
+ protected findFilesInFolder(folderName: string): Promise<any[]>;
12
+ }
13
+ export declare class Resume extends StorageHandler {
14
+ constructor(storage: GoogleDriveStorage);
15
+ signResume({ resume }: {
16
+ resume: any;
17
+ }): void;
18
+ saveResume({ resume, type }: {
19
+ resume: any;
20
+ type: 'sign' | 'unsigned';
21
+ }): Promise<any>;
22
+ find(): Promise<{
23
+ signed: any[];
24
+ nonSigned: any[];
25
+ }>;
26
+ getSignedResumes(): Promise<any[]>;
27
+ getNonSignedResumes(): Promise<any[]>;
28
+ private findRootFolder;
29
+ private generarteUnsignedResume;
30
+ private isResumeFolderExist;
31
+ }
32
+ export default Resume;
@@ -1,6 +1,6 @@
1
1
  import { Ed25519VerificationKey2020 } from '@digitalbazaar/ed25519-verification-key-2020';
2
- import crypto from 'crypto';
3
2
  import { v4 as uuidv4 } from 'uuid';
3
+ import CryptoJS from 'crypto-js';
4
4
  /**
5
5
  * Utility function to generate a hashed ID for a credential.
6
6
  * Excludes the `id` field when hashing.
@@ -11,7 +11,7 @@ function generateHashedId(credential) {
11
11
  // Exclude the `id` field from the hash
12
12
  const credentialWithoutId = { ...credential, id: undefined };
13
13
  const serialized = JSON.stringify(credentialWithoutId);
14
- return crypto.createHash('sha256').update(serialized).digest('hex');
14
+ return CryptoJS.SHA256(serialized).toString(CryptoJS.enc.Hex);
15
15
  }
16
16
  /**
17
17
  * Create a DID document using the provided key pair.
@@ -34,26 +34,22 @@ export async function saveToGoogleDrive({ storage, data, type }) {
34
34
  let credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
35
35
  let credentialsFolderId;
36
36
  if (!credentialsFolder) {
37
- credentialsFolderId = await storage.createFolder('Credentials');
38
- }
39
- else {
40
- credentialsFolderId = credentialsFolder.id;
37
+ credentialsFolder = await storage.createFolder({ folderName: 'Credentials', parentFolderId: 'root' });
41
38
  }
39
+ credentialsFolderId = credentialsFolder.id;
42
40
  // Get subfolders within the "Credentials" folder
43
41
  const subfolders = await storage.findFolders(credentialsFolderId);
44
42
  // Find or create the specific subfolder (DIDs or VCs)
45
43
  let typeFolder = subfolders.find((f) => f.name === `${type}s`);
46
44
  let typeFolderId;
47
45
  if (!typeFolder) {
48
- typeFolderId = await storage.createFolder(`${type}s`, credentialsFolderId);
49
- }
50
- else {
51
- typeFolderId = typeFolder.id;
46
+ typeFolder = await storage.createFolder({ folderName: `${type}s`, parentFolderId: credentialsFolderId });
52
47
  }
48
+ typeFolderId = typeFolder.id;
53
49
  if (type === 'VC') {
54
50
  // save the data in Credentials/VCs/VC-timestamp/vc.json
55
- const vcFolderId = await storage.createFolder(`${fileData.fileName}-${Date.now()}`, typeFolderId);
56
- const file = await storage.saveFile({ data: fileData, folderId: vcFolderId });
51
+ const vcFolder = await storage.createFolder({ folderName: `${fileData.fileName}-${Date.now()}`, parentFolderId: typeFolderId });
52
+ const file = await storage.saveFile({ data: fileData, folderId: vcFolder.id });
57
53
  console.log(`File uploaded: ${file?.id} under ${fileData.fileName} folder in VCs folder`);
58
54
  return file;
59
55
  }
@@ -78,22 +74,17 @@ export async function uploadImageToGoogleDrive(storage, imageFile) {
78
74
  try {
79
75
  const rootFolders = await storage.findFolders();
80
76
  let credentialsFolder = rootFolders.find((f) => f.name === 'Credentials');
81
- let credentialsFolderId;
82
77
  if (!credentialsFolder) {
83
- credentialsFolderId = await storage.createFolder('Credentials');
78
+ console.log('Credentials folder not found. Creating...');
79
+ credentialsFolder = await storage.createFolder({ folderName: 'Credentials', parentFolderId: 'root' });
84
80
  }
85
- else {
86
- credentialsFolderId = credentialsFolder.id;
87
- }
88
- const subfolders = await storage.findFolders(credentialsFolderId);
81
+ const credentialsFolderId = credentialsFolder.id;
82
+ const subfolders = await storage.findFolders(credentialsFolder.id);
89
83
  let mediasFolder = subfolders.find((f) => f.name === 'MEDIAs');
90
- let mediasFolderId;
91
84
  if (!mediasFolder) {
92
- mediasFolderId = await storage.createFolder('MEDIAs', credentialsFolderId);
93
- }
94
- else {
95
- mediasFolderId = mediasFolder.id;
85
+ mediasFolder = await storage.createFolder({ folderName: 'MEDIAs', parentFolderId: credentialsFolderId });
96
86
  }
87
+ const mediasFolderId = mediasFolder.id;
97
88
  // Prepare the image file data
98
89
  const imageData = {
99
90
  fileName: imageFile.name,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cooperation/vc-storage",
3
3
  "type": "module",
4
- "version": "1.0.13",
4
+ "version": "1.0.14",
5
5
  "description": "Sign and store your verifiable credentials.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/types/index.d.ts",
@@ -20,6 +20,7 @@
20
20
  "@digitalbazaar/ed25519-signature-2020": "^5.3.0",
21
21
  "@digitalbazaar/ed25519-verification-key-2020": "^4.1.0",
22
22
  "@digitalbazaar/vc": "^6.3.0",
23
+ "crypto-js": "^4.2.0",
23
24
  "ethers": "^6.13.2",
24
25
  "ts-node": "^10.9.2",
25
26
  "tsc": "^2.0.4",