From 97954d0e207b0c0a87d53906af3113898e02f364 Mon Sep 17 00:00:00 2001 From: Bobo Date: Thu, 20 Mar 2025 10:07:45 +0100 Subject: [PATCH 1/2] Gradually remove base64 data from a dApp developer object --- src/services/FirebaseService.ts | 70 ++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/src/services/FirebaseService.ts b/src/services/FirebaseService.ts index 51105c3..6c0f0f4 100644 --- a/src/services/FirebaseService.ts +++ b/src/services/FirebaseService.ts @@ -79,6 +79,9 @@ export class FirebaseService implements IFirebaseService { dapp.images = images.filter((x) => x !== null) as FileInfo[]; } + // Check if developer images are stored as base64 and fix them. + await this.fixImages(dapp, collectionKey); + dapp.description = this.decode(dapp.description); dapp.shortDescription = this.decode(dapp.shortDescription ?? ''); return dapp; @@ -105,6 +108,14 @@ export class FirebaseService implements IFirebaseService { } } + // upload developer images + for (const [index, dev] of dapp.developers.entries()) { + if (dev?.iconFile && dev.iconFile.startsWith('data:')) { + const imageInfo = this.createFileInfo(dev.iconFile, `developer-${index + 1}`); + dev.iconFile = await this.uploadImage(imageInfo, collectionKey, dapp.address); + } + } + //upload document const firebasePayload = { name: dapp.name, @@ -160,12 +171,28 @@ export class FirebaseService implements IFirebaseService { } private async uploadImage(fileInfo: FileInfo, collectionKey: string, contractAddress: string): Promise { + return await this.uploadEncodedImage( + fileInfo.base64content, + fileInfo.contentType, + fileInfo.name, + collectionKey, + contractAddress, + ); + } + + private async uploadEncodedImage( + base64content: string, + contentType: string, + fileName: string, + collectionKey: string, + contractAddress: string, + ): Promise { const file = admin .storage() .bucket(functions.config().extfirebase.bucket) - .file(`${collectionKey}/${contractAddress}_${fileInfo.name}`); - const buffer = Buffer.from(this.decode(fileInfo.base64content), 'base64'); - await file.save(buffer, { contentType: this.decode(fileInfo.contentType) }); + .file(`${collectionKey}/${contractAddress}_${fileName}`); + const buffer = Buffer.from(this.decode(base64content), 'base64'); + await file.save(buffer, { contentType: this.decode(contentType) }); file.makePublic(); return file.publicUrl(); @@ -222,6 +249,16 @@ export class FirebaseService implements IFirebaseService { } } + private createFileInfo(encodedContent: string, fileNameWithoutExtension: string): FileInfo { + const decoded = this.decode(encodedContent); + const parts = decoded.split(';base64,'); + return { + name: `${fileNameWithoutExtension}.${parts[0].split('/')[1]}`, + contentType: parts[0].split(':')[1], + base64content: parts[1], + }; + } + /** * Firebase encodes '/' as / before storing to the db, becasue '/' is special caracter, * so we need to fix this before sending to a client. @@ -235,7 +272,7 @@ export class FirebaseService implements IFirebaseService { const data = await query.orderBy('name').get(); const result: DappItem[] = []; - data.forEach((x) => { + for (const x of data.docs) { const data = x.data() as DappItem; data.creationTime = x.createTime.seconds; if (data.description) { @@ -243,8 +280,31 @@ export class FirebaseService implements IFirebaseService { } data.shortDescription = this.decode(data.shortDescription ?? ''); result.push(data); - }); + } return result; } + + /** + * Fixes base64 images stored in JSON + * @param dapp to fix images for + * @param collectionKey collection key + * @returns value indicating if + */ + private async fixImages(dapp: DappItem, collectionKey: string): Promise { + let hasBase64 = false; + for (const [index, dev] of dapp.developers.entries()) { + if (dev.iconFile && dev.iconFile.startsWith('data:')) { + const imageInfo = this.createFileInfo(dev.iconFile, `developer-${index + 1}`); + dev.iconFile = dev.iconFile = await this.uploadImage(imageInfo, collectionKey, dapp.address); + hasBase64 = true; + } + } + + if (hasBase64) { + await admin.firestore().collection(collectionKey).doc(dapp.address).set(dapp); + } + + return hasBase64; + } } From 66ef159629a4df6573e971df7d857dc97ce25f2e Mon Sep 17 00:00:00 2001 From: Bobo Date: Thu, 20 Mar 2025 10:54:51 +0100 Subject: [PATCH 2/2] Fixes and refactoring. --- src/services/FirebaseService.ts | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/services/FirebaseService.ts b/src/services/FirebaseService.ts index 6c0f0f4..8ec9603 100644 --- a/src/services/FirebaseService.ts +++ b/src/services/FirebaseService.ts @@ -80,7 +80,7 @@ export class FirebaseService implements IFirebaseService { } // Check if developer images are stored as base64 and fix them. - await this.fixImages(dapp, collectionKey); + await this.fixImages(dapp, collectionKey, true); dapp.description = this.decode(dapp.description); dapp.shortDescription = this.decode(dapp.shortDescription ?? ''); @@ -108,13 +108,8 @@ export class FirebaseService implements IFirebaseService { } } - // upload developer images - for (const [index, dev] of dapp.developers.entries()) { - if (dev?.iconFile && dev.iconFile.startsWith('data:')) { - const imageInfo = this.createFileInfo(dev.iconFile, `developer-${index + 1}`); - dev.iconFile = await this.uploadImage(imageInfo, collectionKey, dapp.address); - } - } + // Upload developer images if needed + await this.fixImages(dapp, collectionKey); //upload document const firebasePayload = { @@ -289,19 +284,21 @@ export class FirebaseService implements IFirebaseService { * Fixes base64 images stored in JSON * @param dapp to fix images for * @param collectionKey collection key - * @returns value indicating if + * @returns value indicating if some images are fixed and the dApp was updated in Firebase. */ - private async fixImages(dapp: DappItem, collectionKey: string): Promise { + private async fixImages(dapp: DappItem, collectionKey: string, updateDappIfNeeded = false): Promise { let hasBase64 = false; - for (const [index, dev] of dapp.developers.entries()) { - if (dev.iconFile && dev.iconFile.startsWith('data:')) { - const imageInfo = this.createFileInfo(dev.iconFile, `developer-${index + 1}`); - dev.iconFile = dev.iconFile = await this.uploadImage(imageInfo, collectionKey, dapp.address); - hasBase64 = true; + if (dapp?.developers) { + for (const [index, dev] of dapp.developers.entries()) { + if (dev?.iconFile && dev.iconFile.startsWith('data:')) { + const imageInfo = this.createFileInfo(dev.iconFile, `developer-${index + 1}`); + dev.iconFile = await this.uploadImage(imageInfo, collectionKey, dapp.address); + hasBase64 = true; + } } } - if (hasBase64) { + if (hasBase64 && updateDappIfNeeded) { await admin.firestore().collection(collectionKey).doc(dapp.address).set(dapp); }