From f3af6a813aa7ae7ec3c0581609af0f0c2e81146c Mon Sep 17 00:00:00 2001 From: Nik Gilmore Date: Thu, 9 Oct 2025 10:46:20 -0700 Subject: [PATCH] [PM-26096] Bugfix: Decryption errors for folders prevent vault access (#16796) * Handle scenario where folders fail to decrypt * Add comment explaining the folderViews$ filter check (cherry picked from commit 4d2106a7c04b6fb01c54e51916f0569d7ef3e91a) --- .../src/vault/services/folder/folder.service.ts | 15 ++++++++++----- .../default-cipher-form-config.service.ts | 9 ++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libs/common/src/vault/services/folder/folder.service.ts b/libs/common/src/vault/services/folder/folder.service.ts index 2d440adeb29..e95f39aad85 100644 --- a/libs/common/src/vault/services/folder/folder.service.ts +++ b/libs/common/src/vault/services/folder/folder.service.ts @@ -272,11 +272,16 @@ export class FolderService implements InternalFolderServiceAbstraction { return []; } - const decryptFolderPromises = folders.map((f) => - f.decryptWithKey(userKey, this.encryptService), - ); - const decryptedFolders = await Promise.all(decryptFolderPromises); - decryptedFolders.sort(Utils.getSortFunction(this.i18nService, "name")); + const decryptFolderPromises = folders.map(async (f) => { + try { + return await f.decryptWithKey(userKey, this.encryptService); + } catch { + return null; + } + }); + const decryptedFolders = (await Promise.all(decryptFolderPromises)) + .filter((p) => p !== null) + .sort(Utils.getSortFunction(this.i18nService, "name")); const noneFolder = new FolderView(); noneFolder.name = this.i18nService.t("noneFolder"); diff --git a/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts index 04a2bb957ec..558235f2c7f 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts @@ -59,9 +59,12 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService { this.organizationDataOwnershipDisabled$, this.folderService.folders$(activeUserId).pipe( switchMap((f) => - this.folderService.folderViews$(activeUserId).pipe( - filter((d) => d.length - 1 === f.length), // -1 for "No Folder" in folderViews$ - ), + this.folderService + .folderViews$(activeUserId) + // Ensure the folders have decrypted. f.length === 0 indicates we don't have any + // folders to wait for, and d.length > 0 indicates that `folderViews` has emitted the + // array, which includes the "No Folder" default folder. + .pipe(filter((d) => d.length > 0 || f.length === 0)), ), ), this.getCipher(activeUserId, cipherId),