1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00

[PM-21644] Cannot retrieve attachment from bw serve (#14806)

* Modified saveAttachmenttofIle to implement callback attachment content decryption

* renamed parameter
This commit is contained in:
SmithThe4th
2025-05-22 09:15:30 -04:00
committed by GitHub
parent 068c63e891
commit 46a0b709fe
3 changed files with 28 additions and 16 deletions

View File

@@ -2,8 +2,6 @@
// @ts-strict-ignore // @ts-strict-ignore
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { Response } from "../models/response"; import { Response } from "../models/response";
import { FileResponse } from "../models/response/file.response"; import { FileResponse } from "../models/response/file.response";
@@ -25,15 +23,15 @@ export abstract class DownloadCommand {
/** /**
* Fetches an attachment via the url, decrypts it's content and saves it to a file * Fetches an attachment via the url, decrypts it's content and saves it to a file
* @param url - url used to retrieve the attachment * @param url - url used to retrieve the attachment
* @param key - SymmetricCryptoKey to decrypt the file contents
* @param fileName - filename used when written to disk * @param fileName - filename used when written to disk
* @param decrypt - Function used to decrypt the response
* @param output - If output is empty or `--raw` was passed to the initial command the content is output onto stdout * @param output - If output is empty or `--raw` was passed to the initial command the content is output onto stdout
* @returns Promise<FileResponse> * @returns Promise<FileResponse>
*/ */
protected async saveAttachmentToFile( protected async saveAttachmentToFile(
url: string, url: string,
key: SymmetricCryptoKey,
fileName: string, fileName: string,
decrypt: (resp: globalThis.Response) => Promise<Uint8Array>,
output?: string, output?: string,
) { ) {
const response = await this.apiService.nativeFetch( const response = await this.apiService.nativeFetch(
@@ -46,8 +44,7 @@ export abstract class DownloadCommand {
} }
try { try {
const encBuf = await EncArrayBuffer.fromResponse(response); const decBuf = await decrypt(response);
const decBuf = await this.encryptService.decryptFileData(encBuf, key);
if (process.env.BW_SERVE === "true") { if (process.env.BW_SERVE === "true") {
const res = new FileResponse(Buffer.from(decBuf), fileName); const res = new FileResponse(Buffer.from(decBuf), fileName);
return Response.success(res); return Response.success(res);

View File

@@ -27,7 +27,7 @@ import { ErrorResponse } from "@bitwarden/common/models/response/error.response"
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
import { OrganizationId } from "@bitwarden/common/types/guid"; import { CipherId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
@@ -345,12 +345,11 @@ export class GetCommand extends DownloadCommand {
return Response.multipleResults(attachments.map((a) => a.id)); return Response.multipleResults(attachments.map((a) => a.id));
} }
const account = await firstValueFrom(this.accountService.activeAccount$); const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
const canAccessPremium = await firstValueFrom( const canAccessPremium = await firstValueFrom(
this.accountProfileService.hasPremiumFromAnySource$(account.id), this.accountProfileService.hasPremiumFromAnySource$(activeUserId),
); );
if (!canAccessPremium) { if (!canAccessPremium) {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
const originalCipher = await this.cipherService.get(cipher.id, activeUserId); const originalCipher = await this.cipherService.get(cipher.id, activeUserId);
if (originalCipher == null || originalCipher.organizationId == null) { if (originalCipher == null || originalCipher.organizationId == null) {
return Response.error("Premium status is required to use this feature."); return Response.error("Premium status is required to use this feature.");
@@ -374,11 +373,20 @@ export class GetCommand extends DownloadCommand {
} }
} }
const key = const decryptBufferFn = (resp: globalThis.Response) =>
attachments[0].key != null this.cipherService.getDecryptedAttachmentBuffer(
? attachments[0].key cipher.id as CipherId,
: await this.keyService.getOrgKey(cipher.organizationId); attachments[0],
return await this.saveAttachmentToFile(url, key, attachments[0].fileName, options.output); resp,
activeUserId,
);
return await this.saveAttachmentToFile(
url,
attachments[0].fileName,
decryptBufferFn,
options.output,
);
} }
private async getFolder(id: string) { private async getFolder(id: string) {

View File

@@ -11,6 +11,7 @@ import { ErrorResponse } from "@bitwarden/common/models/response/error.response"
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
import { SendAccess } from "@bitwarden/common/tools/send/models/domain/send-access"; import { SendAccess } from "@bitwarden/common/tools/send/models/domain/send-access";
@@ -98,10 +99,16 @@ export class SendReceiveCommand extends DownloadCommand {
this.sendAccessRequest, this.sendAccessRequest,
apiUrl, apiUrl,
); );
const decryptBufferFn = async (resp: globalThis.Response) => {
const encBuf = await EncArrayBuffer.fromResponse(resp);
return this.encryptService.decryptFileData(encBuf, this.decKey);
};
return await this.saveAttachmentToFile( return await this.saveAttachmentToFile(
downloadData.url, downloadData.url,
this.decKey,
response?.file?.fileName, response?.file?.fileName,
decryptBufferFn,
options.output, options.output,
); );
} }