mirror of
https://github.com/bitwarden/browser
synced 2026-02-09 13:10:17 +00:00
Fix exporting cipher attachments with the same filename
In case a cipher has 2 attachments with the same filename, they were overwritten within the zip export This appends an underscore as a separator and the attachmentId to truly distinguish the files by name
This commit is contained in:
@@ -379,6 +379,43 @@ describe("VaultExportService", () => {
|
||||
const attachment = await zip.file("attachments/mock-id/mock-file-name")?.async("blob");
|
||||
expect(attachment).toBeDefined();
|
||||
});
|
||||
|
||||
it("If a ciphers attachments filename is already present in the zipfile then append underscore and attachmentId for the new filename", async () => {
|
||||
const cipherData = new CipherData();
|
||||
cipherData.id = "mock-id";
|
||||
const cipherView = new CipherView(new Cipher(cipherData));
|
||||
// Create 1st attachment with the same filename for the cipher
|
||||
const attachmentView = new AttachmentView(new Attachment(new AttachmentData()));
|
||||
attachmentView.id = "id-of-file-1";
|
||||
attachmentView.fileName = "mock-file-name";
|
||||
// Create 2nd attachment with the same filename for the cipher
|
||||
const attachmentView2 = new AttachmentView(new Attachment(new AttachmentData()));
|
||||
attachmentView2.id = "id-of-file-2";
|
||||
attachmentView2.fileName = "mock-file-name";
|
||||
cipherView.attachments = [attachmentView, attachmentView2];
|
||||
cipherService.getAllDecrypted.mockResolvedValue([cipherView]);
|
||||
folderService.getAllDecryptedFromState.mockResolvedValue([]);
|
||||
encryptService.decryptToBytes.mockResolvedValue(new Uint8Array(255));
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
status: 200,
|
||||
arrayBuffer: () => Promise.resolve(new ArrayBuffer(255)),
|
||||
}),
|
||||
) as any;
|
||||
global.Request = jest.fn(() => {}) as any;
|
||||
|
||||
const exportedVault = await exportService.getExport("zip");
|
||||
|
||||
expect(exportedVault.type).toBe("application/zip");
|
||||
const exportZip = exportedVault as ExportedVaultAsBlob;
|
||||
const zip = await JSZip.loadAsync(exportZip.data);
|
||||
const attachment = await zip.file("attachments/mock-id/mock-file-name")?.async("blob");
|
||||
expect(attachment).toBeDefined();
|
||||
const attachment2 = await zip
|
||||
.file("attachments/mock-id/mock-file-name_id-of-file-2")
|
||||
?.async("blob");
|
||||
expect(attachment2).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("password protected export", () => {
|
||||
|
||||
@@ -117,6 +117,12 @@ export class IndividualVaultExportService
|
||||
for (const attachment of cipher.attachments) {
|
||||
const response = await this.downloadAttachment(cipher.id, attachment.id);
|
||||
const decBuf = await this.decryptAttachment(cipher, attachment, response);
|
||||
|
||||
// To prevent files with the same name from overwriting each other, we append the attachment id to the file name,
|
||||
// if a file with the same name already exists in the folder
|
||||
if (cipherFolder.file(attachment.fileName) != null) {
|
||||
attachment.fileName += `_${attachment.id}`;
|
||||
}
|
||||
cipherFolder.file(attachment.fileName, decBuf);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user