diff --git a/apps/web/src/app/auth/migrate-encryption/migrate-legacy-encryption.component.ts b/apps/web/src/app/auth/migrate-encryption/migrate-legacy-encryption.component.ts index 68eaae618f..6c894f4fa8 100644 --- a/apps/web/src/app/auth/migrate-encryption/migrate-legacy-encryption.component.ts +++ b/apps/web/src/app/auth/migrate-encryption/migrate-legacy-encryption.component.ts @@ -7,9 +7,9 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { ToastService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { SharedModule } from "../../shared"; import { UserKeyRotationModule } from "../key-rotation/user-key-rotation.module"; @@ -31,12 +31,13 @@ export class MigrateFromLegacyEncryptionComponent { private accountService: AccountService, private keyRotationService: UserKeyRotationService, private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, private cryptoService: CryptoService, private messagingService: MessagingService, private logService: LogService, private syncService: SyncService, private toastService: ToastService, + private dialogService: DialogService, + private folderApiService: FolderApiServiceAbstraction, ) {} submit = async () => { @@ -69,6 +70,23 @@ export class MigrateFromLegacyEncryptionComponent { }); this.messagingService.send("logout"); } catch (e) { + // If the error is due to missing folders, we can delete all folders and try again + if (e.message === "All existing folders must be included in the rotation.") { + const deleteFolders = await this.dialogService.openSimpleDialog({ + type: "warning", + title: { key: "encryptionKeyUpdateCannotProceed" }, + content: { key: "keyUpdateFoldersFailed" }, + acceptButtonText: { key: "ok" }, + cancelButtonText: { key: "cancel" }, + }); + + if (deleteFolders) { + await this.folderApiService.deleteAll(); + await this.syncService.fullSync(true, true); + await this.submit(); + return; + } + } this.logService.error(e); throw e; } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index ffb82cd816..c74fd3386a 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3894,6 +3894,12 @@ } } }, + "encryptionKeyUpdateCannotProceed": { + "message": "Encryption key update cannot proceed" + }, + "keyUpdateFoldersFailed": { + "message": "When updating your encryption key, your folders could not be decrypted. To continue with the update, your folders must be deleted. No vault items will be deleted if you proceed." + }, "keyUpdated": { "message": "Key updated" }, diff --git a/libs/common/src/vault/abstractions/folder/folder-api.service.abstraction.ts b/libs/common/src/vault/abstractions/folder/folder-api.service.abstraction.ts index d29ff71290..1762400b3d 100644 --- a/libs/common/src/vault/abstractions/folder/folder-api.service.abstraction.ts +++ b/libs/common/src/vault/abstractions/folder/folder-api.service.abstraction.ts @@ -5,4 +5,5 @@ export class FolderApiServiceAbstraction { save: (folder: Folder) => Promise; delete: (id: string) => Promise; get: (id: string) => Promise; + deleteAll: () => Promise; } diff --git a/libs/common/src/vault/services/folder/folder-api.service.ts b/libs/common/src/vault/services/folder/folder-api.service.ts index c618c95872..e46df37c17 100644 --- a/libs/common/src/vault/services/folder/folder-api.service.ts +++ b/libs/common/src/vault/services/folder/folder-api.service.ts @@ -32,6 +32,11 @@ export class FolderApiService implements FolderApiServiceAbstraction { await this.folderService.delete(id); } + async deleteAll(): Promise { + await this.apiService.send("DELETE", "/folders/all", null, true, false); + await this.folderService.clear(); + } + async get(id: string): Promise { const r = await this.apiService.send("GET", "/folders/" + id, null, true, true); return new FolderResponse(r);