diff --git a/src/modules/file/file.controller.ts b/src/modules/file/file.controller.ts index 89f50e817..17de362d3 100644 --- a/src/modules/file/file.controller.ts +++ b/src/modules/file/file.controller.ts @@ -386,10 +386,6 @@ export class FileController { delete f.removed; delete f.removedAt; - if (!f.plainName) { - f.plainName = this.fileUseCases.decrypFileName(f).plainName; - } - return f; }); } diff --git a/src/modules/file/file.domain.ts b/src/modules/file/file.domain.ts index 82f3ea7e5..4b904f4fc 100644 --- a/src/modules/file/file.domain.ts +++ b/src/modules/file/file.domain.ts @@ -109,7 +109,6 @@ export class File implements FileAttributes { this.fileId = fileId; this.folderId = folderId; this.setFolder(folder); - this.name = name; this.setType(type); this.size = size; this.bucket = bucket; @@ -130,6 +129,7 @@ export class File implements FileAttributes { this.status = status; this.thumbnails = thumbnails; this.sharings = sharings; + this.name = this.plainName; } static build(file: FileAttributes): File { diff --git a/src/modules/file/file.model.ts b/src/modules/file/file.model.ts index 3da05d074..f1427c62c 100644 --- a/src/modules/file/file.model.ts +++ b/src/modules/file/file.model.ts @@ -46,12 +46,7 @@ export class FileModel extends Model implements FileAttributes { @Column(DataType.VIRTUAL) get name(): string { const plainName = this.getDataValue('plainName'); - const folderId = this.getDataValue('folderId'); - if (!plainName || !folderId) return plainName ?? null; - return new AesService(process.env.CRYPTO_SECRET2).encrypt( - plainName, - folderId, - ); + return plainName; } @Index diff --git a/src/modules/file/file.usecase.spec.ts b/src/modules/file/file.usecase.spec.ts index 29f33bc37..ae5ed73d9 100644 --- a/src/modules/file/file.usecase.spec.ts +++ b/src/modules/file/file.usecase.spec.ts @@ -328,101 +328,6 @@ describe('FileUseCases', () => { }); }); - describe('decrypt file name', () => { - const fileAttributes: FileAttributes = { - id: 0, - fileId: '4fda5d98-e5b4-56da-a4f2-000084ac0678', - name: 'Myanmar', - type: 'type', - size: BigInt(60), - bucket: 'bucket', - folderId, - folder: null, - encryptVersion: 'aes-2', - deleted: false, - deletedAt: new Date('2022-09-21T11:11:30.742Z'), - userId: 3431709237, - user: null, - creationTime: new Date('2022-09-21T11:11:30.742Z'), - modificationTime: new Date('2022-09-21T11:11:30.742Z'), - createdAt: new Date('2022-09-21T11:11:30.742Z'), - updatedAt: new Date('2022-09-21T11:11:30.742Z'), - uuid: '', - folderUuid: '', - removed: false, - removedAt: undefined, - plainName: 'Myanmar', - status: FileStatus.EXISTS, - }; - - it('returns a file with the name decrypted', () => { - const folderId = 523; - - const encryptedName = cryptoService.encryptName( - fileAttributes['name'], - folderId, - ); - - const file = { - ...fileAttributes, - name: encryptedName, - folderId, - plainName: null, - }; - - const decryptedName = 'decryptedName'; - jest.spyOn(cryptoService, 'decryptName').mockReturnValue(decryptedName); - - delete fileAttributes['user']; - - const result = service.decrypFileName(file as File); - - expect(cryptoService.decryptName).toHaveBeenCalledWith( - file.name, - file.folderId, - ); - expect(result).toEqual( - File.build({ - ...file, - name: decryptedName, - plainName: decryptedName, - }), - ); - }); - - it('When the file has a plain name, then the plain name is returned', () => { - const file = File.build({ - ...fileAttributes, - plainName: 'plain name', - }); - - const result = service.decrypFileName(file); - expect(result).toEqual( - File.build({ - ...file, - name: 'plain name', - plainName: 'plain name', - }), - ); - }); - - it('fails when name is not encrypted', () => { - const decyptedName = 'not encrypted name'; - - const file = File.build({ - ...fileAttributes, - name: decyptedName, - }); - - try { - service.decrypFileName(file); - } catch (err: any) { - expect(err).toBeInstanceOf(Error); - expect(err.message).toBe('Unable to decrypt file name'); - } - }); - }); - describe('move file', () => { const file = newFile({ attributes: { userId: userMocked.id } }); const destinationFolder = newFolder({ @@ -433,7 +338,6 @@ describe('FileUseCases', () => { const expectedFile = newFile({ attributes: { ...file, - name: 'newencrypted-' + file.name, folderId: destinationFolder.id, folderUuid: destinationFolder.uuid, status: FileStatus.EXISTS, @@ -445,10 +349,6 @@ describe('FileUseCases', () => { .spyOn(folderUseCases, 'getFolderByUuid') .mockResolvedValueOnce(destinationFolder); - jest - .spyOn(cryptoService, 'encryptName') - .mockReturnValueOnce(expectedFile.name); - jest .spyOn(fileRepository, 'findByPlainNameAndFolderId') .mockResolvedValueOnce(null); @@ -469,7 +369,7 @@ describe('FileUseCases', () => { { folderId: destinationFolder.id, folderUuid: destinationFolder.uuid, - name: expectedFile.name, + name: expectedFile.plainName, status: FileStatus.EXISTS, plainName: expectedFile.plainName, type: expectedFile.type, @@ -593,6 +493,7 @@ describe('FileUseCases', () => { folderUuid: destinationFolder.uuid, status: FileStatus.EXISTS, plainName: newAttributes.name, + name: newAttributes.name, type: newAttributes.type, }, }); @@ -633,7 +534,7 @@ describe('FileUseCases', () => { { folderId: destinationFolder.id, folderUuid: destinationFolder.uuid, - name: expectedFile.name, + name: expectedFile.plainName, status: FileStatus.EXISTS, plainName: expectedFile.plainName, type: expectedFile.type, @@ -665,6 +566,7 @@ describe('FileUseCases', () => { folderUuid: destinationFolder.uuid, status: FileStatus.EXISTS, plainName: newAttributes.name, + name: newAttributes.name, type: newAttributes.type, }, }); @@ -701,7 +603,7 @@ describe('FileUseCases', () => { { folderId: expectedFile.folderId, folderUuid: expectedFile.folderUuid, - name: expectedFile.name, + name: expectedFile.plainName, status: FileStatus.EXISTS, plainName: expectedFile.plainName, type: expectedFile.type, @@ -733,10 +635,6 @@ describe('FileUseCases', () => { .spyOn(folderUseCases, 'getFolderByUuid') .mockResolvedValueOnce(destinationFolder); - jest - .spyOn(cryptoService, 'encryptName') - .mockReturnValueOnce(fileToBeRenamed.name); - jest .spyOn(fileRepository, 'findByPlainNameAndFolderId') .mockResolvedValueOnce(null); @@ -1618,7 +1516,7 @@ describe('FileUseCases', () => { attributes: { ...mockFile, plainName: newFileMeta.plainName, - name: encryptedName, + name: newFileMeta.plainName, }, }); @@ -1651,15 +1549,16 @@ describe('FileUseCases', () => { userMocked.id, expect.objectContaining({ plainName: newFileMeta.plainName, - name: encryptedName, }), ); const { modificationTime: resultFileModificationTime, + name: resultFilePlainName, ...resultWithoutModificationTime } = result; const { modificationTime: updatedFileModificationTime, + name: updatedFilePlainName, ...updatedFileWithoutModificationTime } = updatedFile; @@ -1687,7 +1586,6 @@ describe('FileUseCases', () => { jest .spyOn(fileRepository, 'findByPlainNameAndFolderId') .mockResolvedValueOnce(null); - jest.spyOn(cryptoService, 'encryptName').mockReturnValue(mockFile.name); const result = await service.updateFileMetaData( userMocked, @@ -1712,7 +1610,6 @@ describe('FileUseCases', () => { userMocked.id, expect.objectContaining({ plainName: mockFile.plainName, - name: mockFile.name, type: newTypeFileMeta.type, }), ); @@ -1783,27 +1680,6 @@ describe('FileUseCases', () => { ); }); - it('When files have no plainName, then it should decrypt them', async () => { - const encryptedFile = newFile({ - attributes: { plainName: null, thumbnails: [], sharings: [] }, - }); - - jest - .spyOn(fileRepository, 'findTrashedNotExpired') - .mockResolvedValue([encryptedFile]); - - const decryptSpy = jest - .spyOn(service, 'decrypFileName' as any) - .mockReturnValue({ ...encryptedFile, plainName: 'decrypted' }); - - await service.getTrashedFiles(userId, null, { - limit: 20, - offset: 0, - }); - - expect(decryptSpy).toHaveBeenCalledTimes(1); - }); - it('When files already have plainName, then it should not decrypt them', async () => { const decryptedFile = newFile({ attributes: { plainName: 'my-file', thumbnails: [], sharings: [] }, @@ -1964,27 +1840,6 @@ describe('FileUseCases', () => { expect(decryptSpy).not.toHaveBeenCalled(); }); - - it('When files have no plainName, then it should decrypt them', async () => { - const encryptedFile = newFile({ - attributes: { plainName: null, thumbnails: [], sharings: [] }, - }); - - jest - .spyOn(fileRepository, 'findTrashedNotExpiredInWorkspace') - .mockResolvedValue([encryptedFile]); - - const decryptSpy = jest - .spyOn(service as any, 'decrypFileName') - .mockReturnValue({ ...encryptedFile, plainName: 'decrypted' }); - - await service.getTrashedFilesInWorkspace(createdBy, workspace.id, null, { - limit: 20, - offset: 0, - }); - - expect(decryptSpy).toHaveBeenCalledTimes(1); - }); }); describe('getWorkspaceFilesSizeSumByStatuses', () => { @@ -2439,16 +2294,10 @@ describe('FileUseCases', () => { it('When file exists, then it should return the file', async () => { const mockFile = newFile({ owner: userMocked }); jest.spyOn(fileRepository, 'findByUuid').mockResolvedValue(mockFile); - jest.spyOn(cryptoService, 'decryptName').mockReturnValue(''); const result = await service.getFileMetadata(userMocked, mockFile.uuid); - expect(result).toEqual( - File.build({ - ...mockFile, - name: mockFile.plainName, - }), - ); + expect(result).toEqual(mockFile); expect(fileRepository.findByUuid).toHaveBeenCalledWith( mockFile.uuid, userMocked.id, diff --git a/src/modules/file/file.usecase.ts b/src/modules/file/file.usecase.ts index ce7b24d03..f27a4ad9c 100644 --- a/src/modules/file/file.usecase.ts +++ b/src/modules/file/file.usecase.ts @@ -252,7 +252,7 @@ export class FileUseCases { throw new NotFoundException('File not found'); } - return this.decrypFileName(file); + return file; } async getFileVersions( @@ -306,11 +306,6 @@ export class FileUseCases { throw new ForbiddenException('Folder is not yours'); } - const cryptoFileName = this.cryptoService.encryptName( - newFileDto.plainName, - folder.id, - ); - const exists = await this.fileRepository.findByPlainNameAndFolderId( user.id, newFileDto.plainName, @@ -339,7 +334,7 @@ export class FileUseCases { const newFile = await this.fileRepository.create({ uuid: v4(), - name: cryptoFileName, + name: newFileDto.plainName, plainName: newFileDto.plainName, type: newFileDto.type, size: newFileDto.size, @@ -447,18 +442,12 @@ export class FileUseCases { throw new ForbiddenException('This file is not yours'); } - const plainName = - newFileMetadata.plainName ?? - file.plainName ?? - this.cryptoService.decryptName(file.name, file.folderId); - const cryptoFileName = newFileMetadata.plainName - ? this.cryptoService.encryptName(newFileMetadata.plainName, file.folderId) - : file.name; + const plainName = newFileMetadata.plainName ?? file.plainName; const type = newFileMetadata.type ?? file.type; const updatedFile = File.build({ ...file, - name: cryptoFileName, + name: plainName, plainName, type, }); @@ -479,7 +468,6 @@ export class FileUseCases { await this.fileRepository.updateByUuidAndUserId(updatedFile.uuid, user.id, { plainName: updatedFile.plainName, - name: updatedFile.name, type: updatedFile.type, modificationTime: modificationTime, }); @@ -640,9 +628,7 @@ export class FileUseCases { const filesModified = files.map((file) => this.addOldAttributes(file)); - return filesModified.map((file) => - file.plainName ? file : this.decrypFileName(file), - ); + return filesModified; } async getFiles( @@ -679,9 +665,7 @@ export class FileUseCases { this.addOldAttributes(file), ); - return filesWithThumbnailsModified.map((file) => - file.plainName ? file : this.decrypFileName(file), - ); + return filesWithThumbnailsModified; } async getTrashedFiles( @@ -706,9 +690,7 @@ export class FileUseCases { this.addOldAttributes(file), ); - return filesModified.map((file) => - file.plainName ? file : this.decrypFileName(file), - ); + return filesModified; } async getTrashedFilesInWorkspace( @@ -735,9 +717,7 @@ export class FileUseCases { this.addOldAttributes(file), ); - return filesModified.map((file) => - file.plainName ? file : this.decrypFileName(file), - ); + return filesModified; } async getWorkspaceFilesSizeSumByStatuses( @@ -792,9 +772,7 @@ export class FileUseCases { this.addOldAttributes(file), ); - return filesWithThumbnailsModified.map((file) => - file.plainName ? file : this.decrypFileName(file), - ); + return filesWithThumbnailsModified; } async getFilesNotDeleted( @@ -1040,10 +1018,7 @@ export class FileUseCases { ); } - const plainName = - destinationData.name ?? - file.plainName ?? - this.cryptoService.decryptName(file.name, file.folderId); + const plainName = destinationData.name ?? file.plainName; const type = destinationData.type ?? file.type; file.setPlainName(plainName); @@ -1072,22 +1047,15 @@ export class FileUseCases { ); } - const destinationEncryptedName = this.cryptoService.encryptName( - file.plainName, - destinationFolder.id, - ); - const updateData: Partial = { folderId: destinationFolder.id, folderUuid: destinationFolder.uuid, - name: destinationEncryptedName, + name: plainName, status: FileStatus.EXISTS, plainName: file.plainName, type: file.type, }; - const wasTrashed = file.status === FileStatus.TRASHED; - await this.fileRepository.updateByUuidAndUserId( fileUuid, user.id, @@ -1098,18 +1066,14 @@ export class FileUseCases { } decrypFileName(file: File): any { - const decryptedName = - file.plainName ?? - this.cryptoService.decryptName(file.name, file.folderId); - - if (decryptedName === '') { + if (file.plainName === '') { return File.build(file); } return File.build({ ...file, - name: decryptedName, - plainName: decryptedName, + name: file.plainName, + plainName: file.plainName, }); } diff --git a/src/modules/folder/folder.e2e-spec.ts b/src/modules/folder/folder.e2e-spec.ts index 46ef2393c..8b600433c 100644 --- a/src/modules/folder/folder.e2e-spec.ts +++ b/src/modules/folder/folder.e2e-spec.ts @@ -13,7 +13,6 @@ import { type TestUserContext, } from '../../../test/helpers/user.helper'; import { createTestApp } from '../../../test/helpers/test-app.helper'; -import { AesService } from '../../externals/crypto/aes'; describe('Folder module', () => { let app: NestExpressApplication; @@ -116,11 +115,7 @@ describe('Folder module', () => { type: file.type, }); - const aes = new AesService(process.env.CRYPTO_SECRET2); - const decryptedName = aes.decrypt( - response.body.files[0].name, - response.body.files[0].folderId, - ); + const decryptedName = response.body.files[0].name; expect(decryptedName).toEqual(file.plainName); }); diff --git a/src/modules/sharing/sharing.service.ts b/src/modules/sharing/sharing.service.ts index 1ddd7a400..b465635cc 100644 --- a/src/modules/sharing/sharing.service.ts +++ b/src/modules/sharing/sharing.service.ts @@ -26,8 +26,12 @@ import { type CreateInviteDto } from './dto/create-invite.dto'; import { SequelizeSharingRepository } from './sharing.repository'; import { FileUseCases } from '../file/file.usecase'; import { FolderUseCases } from '../folder/folder.usecase'; -import { File, type FileAttributes, FileStatus } from '../file/file.domain'; -import { type Folder } from '../folder/folder.domain'; +import { + type File, + type FileAttributes, + FileStatus, +} from '../file/file.domain'; +import { Folder } from '../folder/folder.domain'; import { UserNotFoundError, UserUseCases } from '../user/user.usecase'; import { type AcceptInviteDto } from './dto/accept-invite.dto'; import { type UpdateSharingRoleDto } from './dto/update-sharing-role.dto'; @@ -266,11 +270,7 @@ export class SharingService { } if (!item.plainName) { - if (sharing.itemType === 'file') { - item.plainName = this.fileUsecases.decrypFileName( - item as File, - ).plainName; - } else { + if (sharing.itemType === 'folder') { item.plainName = this.folderUsecases.decryptFolderName( item as Folder, ).plainName; @@ -308,12 +308,8 @@ export class SharingService { } } - if (!item.plainName) { - if (item instanceof File) { - item.plainName = this.fileUsecases.decrypFileName(item).plainName; - } else { - item.plainName = this.folderUsecases.decryptFolderName(item).plainName; - } + if (!item.plainName && item instanceof Folder) { + item.plainName = this.folderUsecases.decryptFolderName(item).plainName; } return { plainName: item.plainName, @@ -1694,9 +1690,7 @@ export class SharingService { return { ...fileInfo, - plainName: - fileInfo.plainName || - this.fileUsecases.decrypFileName(fileInfo).plainName, + plainName: fileInfo.plainName, encryptionKey: sharingInfo.encryptionKey, dateShared: sharingInfo.createdAt, sharedWithMe: user.uuid !== fileInfo.user.uuid,