From dc953b3945b0fa383c714b35bb3254b37dfc9ccb Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Tue, 2 Dec 2025 16:03:06 -0500 Subject: [PATCH 01/89] Revert using tooltip in appA11yTitle directive (#17787) * revert using tooltip in title directive * add back tooltip delay from revert * add back label to carousel buttons * fix documentation that does not need reverted * remove unnecessary label attr --- .../setup-extension.component.html | 2 +- .../src/a11y/a11y-title.directive.ts | 32 +++++-------------- .../src/tooltip/tooltip.directive.ts | 1 + 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html index a4b21915620..1976321b4ee 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html @@ -2,7 +2,7 @@ *ngIf="state === SetupExtensionState.Loading" class="bwi bwi-spinner bwi-spin bwi-3x tw-text-muted" aria-hidden="true" - [title]="'loading' | i18n" + [appA11yTitle]="'loading' | i18n" >
diff --git a/libs/components/src/a11y/a11y-title.directive.ts b/libs/components/src/a11y/a11y-title.directive.ts index 5864874b734..75c2967805f 100644 --- a/libs/components/src/a11y/a11y-title.directive.ts +++ b/libs/components/src/a11y/a11y-title.directive.ts @@ -1,38 +1,22 @@ -import { Directive, effect, ElementRef, inject } from "@angular/core"; - -import { TooltipDirective } from "../tooltip/tooltip.directive"; +import { Directive, effect, ElementRef, input } from "@angular/core"; import { setA11yTitleAndAriaLabel } from "./set-a11y-title-and-aria-label"; -/** - * @deprecated This function is deprecated in favor of `bitTooltip`. - * Please use `bitTooltip` instead. - * - * Directive that provides accessible tooltips by internally using TooltipDirective. - * This maintains the appA11yTitle API while leveraging the enhanced tooltip functionality. - */ @Directive({ selector: "[appA11yTitle]", - hostDirectives: [ - { - directive: TooltipDirective, - inputs: ["bitTooltip: appA11yTitle", "tooltipPosition"], - }, - ], }) export class A11yTitleDirective { - private readonly elementRef = inject(ElementRef); - private readonly tooltipDirective = inject(TooltipDirective); + readonly title = input.required({ alias: "appA11yTitle" }); - constructor() { - const originalAriaLabel = this.elementRef.nativeElement.getAttribute("aria-label"); + constructor(private el: ElementRef) { + const originalTitle = this.el.nativeElement.getAttribute("title"); + const originalAriaLabel = this.el.nativeElement.getAttribute("aria-label"); - // setting aria-label as a workaround for testing purposes. Should be removed once tests are updated to check element content. effect(() => { setA11yTitleAndAriaLabel({ - element: this.elementRef.nativeElement, - title: undefined, - label: originalAriaLabel ?? this.tooltipDirective.tooltipContent(), + element: this.el.nativeElement, + title: originalTitle ?? this.title(), + label: originalAriaLabel ?? this.title(), }); }); } diff --git a/libs/components/src/tooltip/tooltip.directive.ts b/libs/components/src/tooltip/tooltip.directive.ts index 12be865243e..cca52526c7d 100644 --- a/libs/components/src/tooltip/tooltip.directive.ts +++ b/libs/components/src/tooltip/tooltip.directive.ts @@ -17,6 +17,7 @@ import { TooltipPositionIdentifier, tooltipPositions } from "./tooltip-positions import { TooltipComponent, TOOLTIP_DATA } from "./tooltip.component"; export const TOOLTIP_DELAY_MS = 800; + /** * Directive to add a tooltip to any element. The tooltip content is provided via the `bitTooltip` input. * The position of the tooltip can be set via the `tooltipPosition` input. Default position is "above-center". From 6f9b25e98e18511dc1f9dc5330ad1476d8075de0 Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Tue, 2 Dec 2025 16:13:34 -0500 Subject: [PATCH 02/89] Prevented double decryption (#17768) --- .../abstractions/cipher-encryption.service.ts | 5 +- .../src/vault/services/cipher.service.spec.ts | 12 ++-- .../src/vault/services/cipher.service.ts | 14 ++-- .../default-cipher-encryption.service.spec.ts | 6 +- .../default-cipher-encryption.service.ts | 67 +++++++++++-------- 5 files changed, 63 insertions(+), 41 deletions(-) diff --git a/libs/common/src/vault/abstractions/cipher-encryption.service.ts b/libs/common/src/vault/abstractions/cipher-encryption.service.ts index 6057a91bae5..fdd42c0acf2 100644 --- a/libs/common/src/vault/abstractions/cipher-encryption.service.ts +++ b/libs/common/src/vault/abstractions/cipher-encryption.service.ts @@ -67,7 +67,10 @@ export abstract class CipherEncryptionService { * * @returns A promise that resolves to an array of decrypted cipher views */ - abstract decryptManyLegacy(ciphers: Cipher[], userId: UserId): Promise; + abstract decryptManyLegacy( + ciphers: Cipher[], + userId: UserId, + ): Promise<[CipherView[], CipherView[]]>; /** * Decrypts many ciphers using the SDK for the given userId, and returns a list of * failures. diff --git a/libs/common/src/vault/services/cipher.service.spec.ts b/libs/common/src/vault/services/cipher.service.spec.ts index 85ce8bd0423..fe2926144b8 100644 --- a/libs/common/src/vault/services/cipher.service.spec.ts +++ b/libs/common/src/vault/services/cipher.service.spec.ts @@ -807,7 +807,7 @@ describe("Cipher Service", () => { // Set up expected results const expectedSuccessCipherViews = [ - { id: mockCiphers[0].id, name: "Success 1" } as unknown as CipherListView, + { id: mockCiphers[0].id, name: "Success 1", decryptionFailure: false } as CipherView, ]; const expectedFailedCipher = new CipherView(mockCiphers[1]); @@ -815,6 +815,11 @@ describe("Cipher Service", () => { expectedFailedCipher.decryptionFailure = true; const expectedFailedCipherViews = [expectedFailedCipher]; + cipherEncryptionService.decryptManyLegacy.mockResolvedValue([ + expectedSuccessCipherViews, + expectedFailedCipherViews, + ]); + // Execute const [successes, failures] = await (cipherService as any).decryptCiphers( mockCiphers, @@ -822,10 +827,7 @@ describe("Cipher Service", () => { ); // Verify the SDK was used for decryption - expect(cipherEncryptionService.decryptManyWithFailures).toHaveBeenCalledWith( - mockCiphers, - userId, - ); + expect(cipherEncryptionService.decryptManyLegacy).toHaveBeenCalledWith(mockCiphers, userId); expect(successes).toEqual(expectedSuccessCipherViews); expect(failures).toEqual(expectedFailedCipherViews); diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index 72c1ca40913..b2c5ac8943c 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -2143,15 +2143,19 @@ export class CipherService implements CipherServiceAbstraction { userId: UserId, fullDecryption: boolean = true, ): Promise<[CipherViewLike[], CipherView[]]> { + if (fullDecryption) { + const [decryptedViews, failedViews] = await this.cipherEncryptionService.decryptManyLegacy( + ciphers, + userId, + ); + return [decryptedViews.sort(this.getLocaleSortingFunction()), failedViews]; + } + const [decrypted, failures] = await this.cipherEncryptionService.decryptManyWithFailures( ciphers, userId, ); - const decryptedViews = fullDecryption - ? await Promise.all(decrypted.map((c) => this.getFullCipherView(c))) - : decrypted; - const failedViews = failures.map((c) => { const cipher_view = new CipherView(c); cipher_view.name = "[error: cannot decrypt]"; @@ -2159,7 +2163,7 @@ export class CipherService implements CipherServiceAbstraction { return cipher_view; }); - return [decryptedViews.sort(this.getLocaleSortingFunction()), failedViews]; + return [decrypted.sort(this.getLocaleSortingFunction()), failedViews]; } /** Fetches the full `CipherView` when a `CipherListView` is passed. */ diff --git a/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts b/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts index 6d6341bd1fa..f54dfa17a38 100644 --- a/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts +++ b/libs/common/src/vault/services/default-cipher-encryption.service.spec.ts @@ -496,9 +496,11 @@ describe("DefaultCipherEncryptionService", () => { .mockReturnValueOnce(expectedViews[0]) .mockReturnValueOnce(expectedViews[1]); - const result = await cipherEncryptionService.decryptManyLegacy(ciphers, userId); + const [successfulDecryptions, failedDecryptions] = + await cipherEncryptionService.decryptManyLegacy(ciphers, userId); - expect(result).toEqual(expectedViews); + expect(successfulDecryptions).toEqual(expectedViews); + expect(failedDecryptions).toEqual([]); expect(mockSdkClient.vault().ciphers().decrypt).toHaveBeenCalledTimes(2); expect(CipherView.fromSdkCipherView).toHaveBeenCalledTimes(2); }); diff --git a/libs/common/src/vault/services/default-cipher-encryption.service.ts b/libs/common/src/vault/services/default-cipher-encryption.service.ts index 3f03e0f5e9e..f1b737ed50f 100644 --- a/libs/common/src/vault/services/default-cipher-encryption.service.ts +++ b/libs/common/src/vault/services/default-cipher-encryption.service.ts @@ -168,7 +168,7 @@ export class DefaultCipherEncryptionService implements CipherEncryptionService { ); } - decryptManyLegacy(ciphers: Cipher[], userId: UserId): Promise { + decryptManyLegacy(ciphers: Cipher[], userId: UserId): Promise<[CipherView[], CipherView[]]> { return firstValueFrom( this.sdkService.userClient$(userId).pipe( map((sdk) => { @@ -178,38 +178,49 @@ export class DefaultCipherEncryptionService implements CipherEncryptionService { using ref = sdk.take(); - return ciphers.map((cipher) => { - const sdkCipherView = ref.value.vault().ciphers().decrypt(cipher.toSdkCipher()); - const clientCipherView = CipherView.fromSdkCipherView(sdkCipherView)!; + const successful: CipherView[] = []; + const failed: CipherView[] = []; - // Handle FIDO2 credentials if present - if ( - clientCipherView.type === CipherType.Login && - sdkCipherView.login?.fido2Credentials?.length - ) { - const fido2CredentialViews = ref.value - .vault() - .ciphers() - .decrypt_fido2_credentials(sdkCipherView); + ciphers.forEach((cipher) => { + try { + const sdkCipherView = ref.value.vault().ciphers().decrypt(cipher.toSdkCipher()); + const clientCipherView = CipherView.fromSdkCipherView(sdkCipherView)!; - // TODO (PM-21259): Remove manual keyValue decryption for FIDO2 credentials. - // This is a temporary workaround until we can use the SDK for FIDO2 authentication. - const decryptedKeyValue = ref.value - .vault() - .ciphers() - .decrypt_fido2_private_key(sdkCipherView); + // Handle FIDO2 credentials if present + if ( + clientCipherView.type === CipherType.Login && + sdkCipherView.login?.fido2Credentials?.length + ) { + const fido2CredentialViews = ref.value + .vault() + .ciphers() + .decrypt_fido2_credentials(sdkCipherView); - clientCipherView.login.fido2Credentials = fido2CredentialViews - .map((f) => { - const view = Fido2CredentialView.fromSdkFido2CredentialView(f)!; - view.keyValue = decryptedKeyValue; - return view; - }) - .filter((view): view is Fido2CredentialView => view !== undefined); + const decryptedKeyValue = ref.value + .vault() + .ciphers() + .decrypt_fido2_private_key(sdkCipherView); + + clientCipherView.login.fido2Credentials = fido2CredentialViews + .map((f) => { + const view = Fido2CredentialView.fromSdkFido2CredentialView(f)!; + view.keyValue = decryptedKeyValue; + return view; + }) + .filter((view): view is Fido2CredentialView => view !== undefined); + } + + successful.push(clientCipherView); + } catch (error) { + this.logService.error(`Failed to decrypt cipher ${cipher.id}: ${error}`); + const failedView = new CipherView(cipher); + failedView.name = "[error: cannot decrypt]"; + failedView.decryptionFailure = true; + failed.push(failedView); } - - return clientCipherView; }); + + return [successful, failed] as [CipherView[], CipherView[]]; }), catchError((error: unknown) => { this.logService.error(`Failed to decrypt ciphers: ${error}`); From cf416388d7c1e52bba0b42e2fa8ad1617b57435f Mon Sep 17 00:00:00 2001 From: Jeffrey Holland <124393578+jholland-livefront@users.noreply.github.com> Date: Wed, 3 Dec 2025 09:46:40 +0100 Subject: [PATCH 03/89] Fix stale data issue in new login popout (#17307) * Fix stale data issue in new login popout * Update the comments * Address critical claude code bot suggestions * Clean out all stale data from pop up * Fix cached cipher issue * Fix caching issue between tab and overlay flow * Address claude comments --- .../add-edit/add-edit-v2.component.spec.ts | 84 +++++++++++++++++++ .../add-edit/add-edit-v2.component.ts | 50 ++++++++++- .../popup/utils/vault-popout-window.spec.ts | 40 +++++++++ .../vault/popup/utils/vault-popout-window.ts | 24 +++++- .../components/cipher-form.component.spec.ts | 13 ++- .../components/cipher-form.component.ts | 24 +++++- .../default-cipher-form-cache.service.ts | 8 +- 7 files changed, 232 insertions(+), 11 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.spec.ts index 1bffcd9ad51..f2c9d470816 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.spec.ts @@ -381,4 +381,88 @@ describe("AddEditV2Component", () => { expect(navigate).toHaveBeenCalledWith(["/tabs/vault"]); }); }); + + describe("reloadAddEditCipherData", () => { + beforeEach(fakeAsync(() => { + addEditCipherInfo$.next({ + cipher: { + name: "InitialName", + type: CipherType.Login, + login: { + password: "initialPassword", + username: "initialUsername", + uris: [{ uri: "https://initial.com" }], + }, + }, + } as AddEditCipherInfo); + queryParams$.next({}); + tick(); + + cipherServiceMock.setAddEditCipherInfo.mockClear(); + })); + + it("replaces all initialValues with new data, clearing stale fields", fakeAsync(() => { + const newCipherInfo = { + cipher: { + name: "UpdatedName", + type: CipherType.Login, + login: { + password: "updatedPassword", + uris: [{ uri: "https://updated.com" }], + }, + }, + } as AddEditCipherInfo; + + addEditCipherInfo$.next(newCipherInfo); + + const messageListener = component["messageListener"]; + messageListener({ command: "reloadAddEditCipherData" }); + tick(); + + expect(component.config.initialValues).toEqual({ + name: "UpdatedName", + password: "updatedPassword", + loginUri: "https://updated.com", + } as OptionalInitialValues); + + expect(cipherServiceMock.setAddEditCipherInfo).toHaveBeenCalledWith(null, "UserId"); + })); + + it("does not reload data if config is not set", fakeAsync(() => { + component.config = null; + + const messageListener = component["messageListener"]; + messageListener({ command: "reloadAddEditCipherData" }); + tick(); + + expect(cipherServiceMock.setAddEditCipherInfo).not.toHaveBeenCalled(); + })); + + it("does not reload data if latestCipherInfo is null", fakeAsync(() => { + addEditCipherInfo$.next(null); + + const messageListener = component["messageListener"]; + messageListener({ command: "reloadAddEditCipherData" }); + tick(); + + expect(component.config.initialValues).toEqual({ + name: "InitialName", + password: "initialPassword", + username: "initialUsername", + loginUri: "https://initial.com", + } as OptionalInitialValues); + + expect(cipherServiceMock.setAddEditCipherInfo).not.toHaveBeenCalled(); + })); + + it("ignores messages with different commands", fakeAsync(() => { + const initialValues = component.config.initialValues; + + const messageListener = component["messageListener"]; + messageListener({ command: "someOtherCommand" }); + tick(); + + expect(component.config.initialValues).toBe(initialValues); + })); + }); }); diff --git a/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts index 60e44cefbdf..22aad854dd0 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/add-edit/add-edit-v2.component.ts @@ -1,7 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { CommonModule } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; +import { Component, OnInit, OnDestroy } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormsModule } from "@angular/forms"; import { ActivatedRoute, Params, Router } from "@angular/router"; @@ -158,7 +158,7 @@ export type AddEditQueryParams = Partial>; IconButtonModule, ], }) -export class AddEditV2Component implements OnInit { +export class AddEditV2Component implements OnInit, OnDestroy { headerText: string; config: CipherFormConfig; canDeleteCipher$: Observable; @@ -200,12 +200,58 @@ export class AddEditV2Component implements OnInit { this.subscribeToParams(); } + private messageListener: (message: any) => void; + async ngOnInit() { this.fido2PopoutSessionData = await firstValueFrom(this.fido2PopoutSessionData$); if (BrowserPopupUtils.inPopout(window)) { this.popupCloseWarningService.enable(); } + + // Listen for messages to reload cipher data when the pop up is already open + this.messageListener = async (message: any) => { + if (message?.command === "reloadAddEditCipherData") { + try { + await this.reloadCipherData(); + } catch (error) { + this.logService.error("Failed to reload cipher data", error); + } + } + }; + BrowserApi.addListener(chrome.runtime.onMessage, this.messageListener); + } + + ngOnDestroy() { + if (this.messageListener) { + BrowserApi.removeListener(chrome.runtime.onMessage, this.messageListener); + } + } + + /** + * Reloads the cipher data when the popup is already open and new form data is submitted. + * This completely replaces the initialValues to clear any stale data from the previous submission. + */ + private async reloadCipherData() { + if (!this.config) { + return; + } + + const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); + + const latestCipherInfo = await firstValueFrom( + this.cipherService.addEditCipherInfo$(activeUserId), + ); + + if (latestCipherInfo != null) { + this.config = { + ...this.config, + initialValues: mapAddEditCipherInfoToInitialValues(latestCipherInfo), + }; + + // Be sure to clear the "cached" cipher info, so it doesn't get used again + await this.cipherService.setAddEditCipherInfo(null, activeUserId); + } } /** diff --git a/apps/browser/src/vault/popup/utils/vault-popout-window.spec.ts b/apps/browser/src/vault/popup/utils/vault-popout-window.spec.ts index 4597c004290..3389228dda4 100644 --- a/apps/browser/src/vault/popup/utils/vault-popout-window.spec.ts +++ b/apps/browser/src/vault/popup/utils/vault-popout-window.spec.ts @@ -2,6 +2,7 @@ import { mock } from "jest-mock-extended"; import { CipherType } from "@bitwarden/common/vault/enums"; +import { BrowserApi } from "../../../platform/browser/browser-api"; import BrowserPopupUtils from "../../../platform/browser/browser-popup-utils"; import { @@ -23,6 +24,19 @@ describe("VaultPopoutWindow", () => { .spyOn(BrowserPopupUtils, "closeSingleActionPopout") .mockImplementation(); + beforeEach(() => { + jest.spyOn(BrowserApi, "tabsQuery").mockResolvedValue([]); + jest.spyOn(BrowserApi, "updateWindowProperties").mockResolvedValue(); + global.chrome = { + ...global.chrome, + runtime: { + ...global.chrome?.runtime, + sendMessage: jest.fn().mockResolvedValue(undefined), + getURL: jest.fn((path) => `chrome-extension://extension-id/${path}`), + }, + }; + }); + afterEach(() => { jest.clearAllMocks(); }); @@ -123,6 +137,32 @@ describe("VaultPopoutWindow", () => { }, ); }); + + it("sends a message to refresh data when the popup is already open", async () => { + const existingPopupTab = { + id: 123, + windowId: 456, + url: `chrome-extension://extension-id/popup/index.html#/edit-cipher?singleActionPopout=${VaultPopoutType.addEditVaultItem}_${CipherType.Login}`, + } as chrome.tabs.Tab; + + jest.spyOn(BrowserApi, "tabsQuery").mockResolvedValue([existingPopupTab]); + const sendMessageSpy = jest.spyOn(chrome.runtime, "sendMessage"); + const updateWindowSpy = jest.spyOn(BrowserApi, "updateWindowProperties"); + + await openAddEditVaultItemPopout( + mock({ windowId: 1, url: "https://jest-testing-website.com" }), + { + cipherType: CipherType.Login, + }, + ); + + expect(openPopoutSpy).not.toHaveBeenCalled(); + expect(sendMessageSpy).toHaveBeenCalledWith({ + command: "reloadAddEditCipherData", + data: { cipherId: undefined, cipherType: CipherType.Login }, + }); + expect(updateWindowSpy).toHaveBeenCalledWith(456, { focused: true }); + }); }); describe("closeAddEditVaultItemPopout", () => { diff --git a/apps/browser/src/vault/popup/utils/vault-popout-window.ts b/apps/browser/src/vault/popup/utils/vault-popout-window.ts index 3dae96b6cc7..cccf005cd2e 100644 --- a/apps/browser/src/vault/popup/utils/vault-popout-window.ts +++ b/apps/browser/src/vault/popup/utils/vault-popout-window.ts @@ -115,10 +115,26 @@ async function openAddEditVaultItemPopout( addEditCipherUrl += formatQueryString("uri", url); } - await BrowserPopupUtils.openPopout(addEditCipherUrl, { - singleActionKey, - senderWindowId: windowId, - }); + const extensionUrl = chrome.runtime.getURL("popup/index.html"); + const existingPopupTabs = await BrowserApi.tabsQuery({ url: `${extensionUrl}*` }); + const existingPopup = existingPopupTabs.find((tab) => + tab.url?.includes(`singleActionPopout=${singleActionKey}`), + ); + // Check if the an existing popup is already open + try { + await chrome.runtime.sendMessage({ + command: "reloadAddEditCipherData", + data: { cipherId, cipherType }, + }); + await BrowserApi.updateWindowProperties(existingPopup.windowId, { + focused: true, + }); + } catch { + await BrowserPopupUtils.openPopout(addEditCipherUrl, { + singleActionKey, + senderWindowId: windowId, + }); + } } /** diff --git a/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts b/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts index 1e60ad91fb1..9f3102239ae 100644 --- a/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts +++ b/libs/vault/src/cipher-form/components/cipher-form.component.spec.ts @@ -42,9 +42,18 @@ describe("CipherFormComponent", () => { { provide: CipherFormService, useValue: mockAddEditFormService }, { provide: CipherFormCacheService, - useValue: { init: jest.fn(), getCachedCipherView: jest.fn() }, + useValue: { init: jest.fn(), getCachedCipherView: jest.fn(), clearCache: jest.fn() }, + }, + { + provide: ViewCacheService, + useValue: { + signal: jest.fn(() => { + const signalFn = (): any => null; + signalFn.set = jest.fn(); + return signalFn; + }), + }, }, - { provide: ViewCacheService, useValue: { signal: jest.fn(() => (): any => null) } }, { provide: ConfigService, useValue: mock() }, { provide: AccountService, useValue: mockAccountService }, { provide: CipherArchiveService, useValue: mockCipherArchiveService }, diff --git a/libs/vault/src/cipher-form/components/cipher-form.component.ts b/libs/vault/src/cipher-form/components/cipher-form.component.ts index f94af25e90a..c9e867f8d3a 100644 --- a/libs/vault/src/cipher-form/components/cipher-form.component.ts +++ b/libs/vault/src/cipher-form/components/cipher-form.component.ts @@ -304,13 +304,30 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci * Updates `updatedCipherView` based on the value from the cache. */ setInitialCipherFromCache() { + // If we are coming from the overlay/popup flow clear the cache to avoid old cached data + const hasOverlayData = + this.config.initialValues && + (this.config.initialValues.username !== undefined || + this.config.initialValues.password !== undefined); + + if (hasOverlayData) { + this.cipherFormCacheService.clearCache(); + return; + } + const cachedCipher = this.cipherFormCacheService.getCachedCipherView(); if (cachedCipher === null) { return; } - // Use the cached cipher when it matches the cipher being edited - if (this.updatedCipherView.id === cachedCipher.id) { + const isEditingExistingCipher = + this.updatedCipherView.id && this.updatedCipherView.id === cachedCipher.id; + const isCreatingNewCipher = + !this.updatedCipherView.id && + !cachedCipher.id && + this.updatedCipherView.type === cachedCipher.type; + + if (isEditingExistingCipher || isCreatingNewCipher) { this.updatedCipherView = cachedCipher; } } @@ -382,6 +399,9 @@ export class CipherFormComponent implements AfterViewInit, OnInit, OnChanges, Ci this.config, ); + // Clear the cache after successful save + this.cipherFormCacheService.clearCache(); + this.toastService.showToast({ variant: "success", title: null, diff --git a/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts index 25581ae5ea1..d525dcd9afa 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form-cache.service.ts @@ -22,7 +22,6 @@ export class CipherFormCacheService { key: CIPHER_FORM_CACHE_KEY, initialValue: null, deserializer: CipherView.fromJSON, - clearOnTabChange: true, }); constructor() { @@ -45,4 +44,11 @@ export class CipherFormCacheService { getCachedCipherView(): CipherView | null { return this.cipherCache(); } + + /** + * Clear the cached CipherView. + */ + clearCache(): void { + this.cipherCache.set(null); + } } From a6100d8a0ebe67fbb453049627879fa54b7c45db Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Wed, 3 Dec 2025 13:11:03 +0100 Subject: [PATCH 04/89] Replace webcrypto RSA with PureCrypto RSA (#17742) --- .../abstractions/crypto-function.service.ts | 6 +- .../encrypt.service.implementation.ts | 8 +-- .../web-crypto-function.service.spec.ts | 3 +- .../services/web-crypto-function.service.ts | 47 ++++--------- .../node-crypto-function.service.spec.ts | 15 +++- .../services/node-crypto-function.service.ts | 70 +++++-------------- 6 files changed, 48 insertions(+), 101 deletions(-) diff --git a/libs/common/src/key-management/crypto/abstractions/crypto-function.service.ts b/libs/common/src/key-management/crypto/abstractions/crypto-function.service.ts index 705a1c1a24e..b16371198b3 100644 --- a/libs/common/src/key-management/crypto/abstractions/crypto-function.service.ts +++ b/libs/common/src/key-management/crypto/abstractions/crypto-function.service.ts @@ -91,7 +91,7 @@ export abstract class CryptoFunctionService { abstract rsaEncrypt( data: Uint8Array, publicKey: Uint8Array, - algorithm: "sha1" | "sha256", + algorithm: "sha1", ): Promise; /** * @deprecated HAZMAT WARNING: DO NOT USE THIS FOR NEW CODE. Implement low-level crypto operations @@ -100,10 +100,10 @@ export abstract class CryptoFunctionService { abstract rsaDecrypt( data: Uint8Array, privateKey: Uint8Array, - algorithm: "sha1" | "sha256", + algorithm: "sha1", ): Promise; abstract rsaExtractPublicKey(privateKey: Uint8Array): Promise; - abstract rsaGenerateKeyPair(length: 1024 | 2048 | 4096): Promise<[Uint8Array, Uint8Array]>; + abstract rsaGenerateKeyPair(length: 2048): Promise<[Uint8Array, Uint8Array]>; /** * Generates a key of the given length suitable for use in AES encryption */ diff --git a/libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts b/libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts index 132bbc306cb..a5da0c82382 100644 --- a/libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts +++ b/libs/common/src/key-management/crypto/services/encrypt.service.implementation.ts @@ -252,15 +252,9 @@ export class EncryptServiceImplementation implements EncryptService { throw new Error("[Encrypt service] rsaDecrypt: No data provided for decryption."); } - let algorithm: "sha1" | "sha256"; switch (data.encryptionType) { case EncryptionType.Rsa2048_OaepSha1_B64: case EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64: - algorithm = "sha1"; - break; - case EncryptionType.Rsa2048_OaepSha256_B64: - case EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64: - algorithm = "sha256"; break; default: throw new Error("Invalid encryption type."); @@ -270,6 +264,6 @@ export class EncryptServiceImplementation implements EncryptService { throw new Error("[Encrypt service] rsaDecrypt: No private key provided for decryption."); } - return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, algorithm); + return this.cryptoFunctionService.rsaDecrypt(data.dataBytes, privateKey, "sha1"); } } diff --git a/libs/common/src/key-management/crypto/services/web-crypto-function.service.spec.ts b/libs/common/src/key-management/crypto/services/web-crypto-function.service.spec.ts index af23a515de2..c64926e0e5b 100644 --- a/libs/common/src/key-management/crypto/services/web-crypto-function.service.spec.ts +++ b/libs/common/src/key-management/crypto/services/web-crypto-function.service.spec.ts @@ -299,7 +299,6 @@ describe("WebCrypto Function Service", () => { }); describe("rsaGenerateKeyPair", () => { - testRsaGenerateKeyPair(1024); testRsaGenerateKeyPair(2048); // Generating 4096 bit keys can be slow. Commenting it out to save CI. @@ -495,7 +494,7 @@ function testHmac(algorithm: "sha1" | "sha256" | "sha512", mac: string) { }); } -function testRsaGenerateKeyPair(length: 1024 | 2048 | 4096) { +function testRsaGenerateKeyPair(length: 2048) { it( "should successfully generate a " + length + " bit key pair", async () => { diff --git a/libs/common/src/key-management/crypto/services/web-crypto-function.service.ts b/libs/common/src/key-management/crypto/services/web-crypto-function.service.ts index 829227cada9..ee0b5cab902 100644 --- a/libs/common/src/key-management/crypto/services/web-crypto-function.service.ts +++ b/libs/common/src/key-management/crypto/services/web-crypto-function.service.ts @@ -263,33 +263,19 @@ export class WebCryptoFunctionService implements CryptoFunctionService { async rsaEncrypt( data: Uint8Array, publicKey: Uint8Array, - algorithm: "sha1" | "sha256", + _algorithm: "sha1", ): Promise { - // Note: Edge browser requires that we specify name and hash for both key import and decrypt. - // We cannot use the proper types here. - const rsaParams = { - name: "RSA-OAEP", - hash: { name: this.toWebCryptoAlgorithm(algorithm) }, - }; - const impKey = await this.subtle.importKey("spki", publicKey, rsaParams, false, ["encrypt"]); - const buffer = await this.subtle.encrypt(rsaParams, impKey, data); - return new Uint8Array(buffer); + await SdkLoadService.Ready; + return PureCrypto.rsa_encrypt_data(data, publicKey); } async rsaDecrypt( data: Uint8Array, privateKey: Uint8Array, - algorithm: "sha1" | "sha256", + _algorithm: "sha1", ): Promise { - // Note: Edge browser requires that we specify name and hash for both key import and decrypt. - // We cannot use the proper types here. - const rsaParams = { - name: "RSA-OAEP", - hash: { name: this.toWebCryptoAlgorithm(algorithm) }, - }; - const impKey = await this.subtle.importKey("pkcs8", privateKey, rsaParams, false, ["decrypt"]); - const buffer = await this.subtle.decrypt(rsaParams, impKey, data); - return new Uint8Array(buffer); + await SdkLoadService.Ready; + return PureCrypto.rsa_decrypt_data(data, privateKey); } async rsaExtractPublicKey(privateKey: Uint8Array): Promise { @@ -297,6 +283,13 @@ export class WebCryptoFunctionService implements CryptoFunctionService { return PureCrypto.rsa_extract_public_key(privateKey) as UnsignedPublicKey; } + async rsaGenerateKeyPair(_length: 2048): Promise<[UnsignedPublicKey, Uint8Array]> { + await SdkLoadService.Ready; + const privateKey = PureCrypto.rsa_generate_keypair(); + const publicKey = await this.rsaExtractPublicKey(privateKey); + return [publicKey, privateKey]; + } + async aesGenerateKey(bitLength = 128 | 192 | 256 | 512): Promise { if (bitLength === 512) { // 512 bit keys are not supported in WebCrypto, so we concat two 256 bit keys @@ -314,20 +307,6 @@ export class WebCryptoFunctionService implements CryptoFunctionService { return new Uint8Array(rawKey) as CsprngArray; } - async rsaGenerateKeyPair(length: 1024 | 2048 | 4096): Promise<[Uint8Array, Uint8Array]> { - const rsaParams = { - name: "RSA-OAEP", - modulusLength: length, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 65537 - // Have to specify some algorithm - hash: { name: this.toWebCryptoAlgorithm("sha1") }, - }; - const keyPair = await this.subtle.generateKey(rsaParams, true, ["encrypt", "decrypt"]); - const publicKey = await this.subtle.exportKey("spki", keyPair.publicKey); - const privateKey = await this.subtle.exportKey("pkcs8", keyPair.privateKey); - return [new Uint8Array(publicKey), new Uint8Array(privateKey)]; - } - randomBytes(length: number): Promise { const arr = new Uint8Array(length); this.crypto.getRandomValues(arr); diff --git a/libs/node/src/services/node-crypto-function.service.spec.ts b/libs/node/src/services/node-crypto-function.service.spec.ts index 3256d85110f..28a6c127d44 100644 --- a/libs/node/src/services/node-crypto-function.service.spec.ts +++ b/libs/node/src/services/node-crypto-function.service.spec.ts @@ -1,9 +1,17 @@ +import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EcbDecryptParameters } from "@bitwarden/common/platform/models/domain/decrypt-parameters"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { NodeCryptoFunctionService } from "./node-crypto-function.service"; +class TestSdkLoadService extends SdkLoadService { + protected override load(): Promise { + // Simulate successful WASM load + return Promise.resolve(); + } +} + const RsaPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0Vawl/toXzkEvB82FEtqHP" + "4xlU2ab/v0crqIfXfIoWF/XXdHGIdrZeilnRXPPJT1B9dTsasttEZNnua/0Rek/cjNDHtzT52irfoZYS7X6HNIfOi54Q+egP" + @@ -37,6 +45,10 @@ const Sha512Mac = "5ea7817a0b7c5d4d9b00364ccd214669131fc17fe4aca"; describe("NodeCrypto Function Service", () => { + beforeAll(async () => { + await new TestSdkLoadService().loadAndInit(); + }); + describe("pbkdf2", () => { const regular256Key = "pj9prw/OHPleXI6bRdmlaD+saJS4awrMiQsQiDjeu2I="; const utf8256Key = "yqvoFXgMRmHR3QPYr5pyR4uVuoHkltv9aHUP63p8n7I="; @@ -279,7 +291,6 @@ describe("NodeCrypto Function Service", () => { }); describe("rsaGenerateKeyPair", () => { - testRsaGenerateKeyPair(1024); testRsaGenerateKeyPair(2048); // Generating 4096 bit keys is really slow with Forge lib. @@ -514,7 +525,7 @@ function testCompare(fast = false) { }); } -function testRsaGenerateKeyPair(length: 1024 | 2048 | 4096) { +function testRsaGenerateKeyPair(length: 2048) { it( "should successfully generate a " + length + " bit key pair", async () => { diff --git a/libs/node/src/services/node-crypto-function.service.ts b/libs/node/src/services/node-crypto-function.service.ts index 22cc5756f30..49dbc65ca84 100644 --- a/libs/node/src/services/node-crypto-function.service.ts +++ b/libs/node/src/services/node-crypto-function.service.ts @@ -4,6 +4,7 @@ import * as forge from "node-forge"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { UnsignedPublicKey } from "@bitwarden/common/key-management/types"; +import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { EncryptionType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { @@ -12,6 +13,7 @@ import { } from "@bitwarden/common/platform/models/domain/decrypt-parameters"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { PureCrypto } from "@bitwarden/sdk-internal"; export class NodeCryptoFunctionService implements CryptoFunctionService { pbkdf2( @@ -205,72 +207,34 @@ export class NodeCryptoFunctionService implements CryptoFunctionService { return Promise.resolve(this.toUint8Buffer(decBuf)); } - rsaEncrypt( + async rsaEncrypt( data: Uint8Array, publicKey: Uint8Array, - algorithm: "sha1" | "sha256", + _algorithm: "sha1", ): Promise { - if (algorithm === "sha256") { - throw new Error("Node crypto does not support RSA-OAEP SHA-256"); - } - - const pem = this.toPemPublicKey(publicKey); - const decipher = crypto.publicEncrypt(pem, this.toNodeBuffer(data)); - return Promise.resolve(this.toUint8Buffer(decipher)); + await SdkLoadService.Ready; + return PureCrypto.rsa_encrypt_data(data, publicKey); } - rsaDecrypt( + async rsaDecrypt( data: Uint8Array, privateKey: Uint8Array, - algorithm: "sha1" | "sha256", + _algorithm: "sha1", ): Promise { - if (algorithm === "sha256") { - throw new Error("Node crypto does not support RSA-OAEP SHA-256"); - } - - const pem = this.toPemPrivateKey(privateKey); - const decipher = crypto.privateDecrypt(pem, this.toNodeBuffer(data)); - return Promise.resolve(this.toUint8Buffer(decipher)); + await SdkLoadService.Ready; + return PureCrypto.rsa_decrypt_data(data, privateKey); } async rsaExtractPublicKey(privateKey: Uint8Array): Promise { - const privateKeyByteString = Utils.fromBufferToByteString(privateKey); - const privateKeyAsn1 = forge.asn1.fromDer(privateKeyByteString); - const forgePrivateKey: any = forge.pki.privateKeyFromAsn1(privateKeyAsn1); - const forgePublicKey = (forge.pki as any).setRsaPublicKey(forgePrivateKey.n, forgePrivateKey.e); - const publicKeyAsn1 = forge.pki.publicKeyToAsn1(forgePublicKey); - const publicKeyByteString = forge.asn1.toDer(publicKeyAsn1).data; - const publicKeyArray = Utils.fromByteStringToArray(publicKeyByteString); - return publicKeyArray as UnsignedPublicKey; + await SdkLoadService.Ready; + return PureCrypto.rsa_extract_public_key(privateKey) as UnsignedPublicKey; } - async rsaGenerateKeyPair(length: 1024 | 2048 | 4096): Promise<[UnsignedPublicKey, Uint8Array]> { - return new Promise<[UnsignedPublicKey, Uint8Array]>((resolve, reject) => { - forge.pki.rsa.generateKeyPair( - { - bits: length, - workers: -1, - e: 0x10001, // 65537 - }, - (error, keyPair) => { - if (error != null) { - reject(error); - return; - } - - const publicKeyAsn1 = forge.pki.publicKeyToAsn1(keyPair.publicKey); - const publicKeyByteString = forge.asn1.toDer(publicKeyAsn1).getBytes(); - const publicKey = Utils.fromByteStringToArray(publicKeyByteString); - - const privateKeyAsn1 = forge.pki.privateKeyToAsn1(keyPair.privateKey); - const privateKeyPkcs8 = forge.pki.wrapRsaPrivateKey(privateKeyAsn1); - const privateKeyByteString = forge.asn1.toDer(privateKeyPkcs8).getBytes(); - const privateKey = Utils.fromByteStringToArray(privateKeyByteString); - - resolve([publicKey as UnsignedPublicKey, privateKey]); - }, - ); - }); + async rsaGenerateKeyPair(_length: 2048): Promise<[UnsignedPublicKey, Uint8Array]> { + await SdkLoadService.Ready; + const privateKey = PureCrypto.rsa_generate_keypair(); + const publicKey = await this.rsaExtractPublicKey(privateKey); + return [publicKey, privateKey]; } aesGenerateKey(bitLength: 128 | 192 | 256 | 512): Promise { From 17ebae11d7a28d67b513a68e1477ac9a7a063e9d Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:08:48 +0100 Subject: [PATCH 05/89] Fix the bug by hiding the add button (#17744) --- .../clients/manage-clients.component.html | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/manage-clients.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/manage-clients.component.html index 2ab82bd837b..ce89b3c068d 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/manage-clients.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/manage-clients.component.html @@ -2,18 +2,20 @@ @let provider = provider$ | async; - + @if (provider?.type === ProviderUserType.ProviderAdmin) { + + } `; - const shadowRoot = document.getElementById("shadow-root").attachShadow({ mode: "open" }); + const shadowRoot = document.getElementById("shadow-root")!.attachShadow({ mode: "open" }); shadowRoot.innerHTML = ` `; @@ -1668,7 +1668,7 @@ describe("AutofillOverlayContentService", () => { pageDetailsMock, ); await flushPromises(); - buttonElement.dispatchEvent(new KeyboardEvent("keyup", { code: "Enter" })); + buttonElement?.dispatchEvent(new KeyboardEvent("keyup", { code: "Enter" })); expect(sendExtensionMessageSpy).toHaveBeenCalledWith( "formFieldSubmitted", @@ -1716,6 +1716,85 @@ describe("AutofillOverlayContentService", () => { }); }); + describe("refreshMenuLayerPosition", () => { + it("calls refreshTopLayerPosition on the inline menu content service", () => { + autofillOverlayContentService.refreshMenuLayerPosition(); + + expect(inlineMenuContentService.refreshTopLayerPosition).toHaveBeenCalled(); + }); + + it("does not throw if inline menu content service is not available", () => { + const serviceWithoutInlineMenu = new AutofillOverlayContentService( + domQueryService, + domElementVisibilityService, + inlineMenuFieldQualificationService, + ); + + expect(() => serviceWithoutInlineMenu.refreshMenuLayerPosition()).not.toThrow(); + }); + }); + + describe("getOwnedInlineMenuTagNames", () => { + it("returns tag names from the inline menu content service", () => { + inlineMenuContentService.getOwnedTagNames.mockReturnValue(["div", "span"]); + + const result = autofillOverlayContentService.getOwnedInlineMenuTagNames(); + + expect(result).toEqual(["div", "span"]); + }); + + it("returns an empty array if inline menu content service is not available", () => { + const serviceWithoutInlineMenu = new AutofillOverlayContentService( + domQueryService, + domElementVisibilityService, + inlineMenuFieldQualificationService, + ); + + const result = serviceWithoutInlineMenu.getOwnedInlineMenuTagNames(); + + expect(result).toEqual([]); + }); + }); + + describe("getUnownedTopLayerItems", () => { + it("returns unowned top layer items from the inline menu content service", () => { + const mockElements = document.querySelectorAll("div"); + inlineMenuContentService.getUnownedTopLayerItems.mockReturnValue(mockElements); + + const result = autofillOverlayContentService.getUnownedTopLayerItems(true); + + expect(result).toEqual(mockElements); + expect(inlineMenuContentService.getUnownedTopLayerItems).toHaveBeenCalledWith(true); + }); + + it("returns undefined if inline menu content service is not available", () => { + const serviceWithoutInlineMenu = new AutofillOverlayContentService( + domQueryService, + domElementVisibilityService, + inlineMenuFieldQualificationService, + ); + + const result = serviceWithoutInlineMenu.getUnownedTopLayerItems(); + + expect(result).toBeUndefined(); + }); + }); + + describe("clearUserFilledFields", () => { + it("deletes all user filled fields", () => { + const mockElement1 = document.createElement("input") as FillableFormFieldElement; + const mockElement2 = document.createElement("input") as FillableFormFieldElement; + autofillOverlayContentService["userFilledFields"] = { + username: mockElement1, + password: mockElement2, + }; + + autofillOverlayContentService.clearUserFilledFields(); + + expect(autofillOverlayContentService["userFilledFields"]).toEqual({}); + }); + }); + describe("handleOverlayRepositionEvent", () => { const repositionEvents = [EVENTS.SCROLL, EVENTS.RESIZE]; repositionEvents.forEach((repositionEvent) => { @@ -2049,7 +2128,7 @@ describe("AutofillOverlayContentService", () => { }); it("skips focusing an element if no recently focused field exists", async () => { - autofillOverlayContentService["mostRecentlyFocusedField"] = undefined; + (autofillOverlayContentService as any)["mostRecentlyFocusedField"] = null; sendMockExtensionMessage({ command: "redirectAutofillInlineMenuFocusOut", @@ -2149,7 +2228,6 @@ describe("AutofillOverlayContentService", () => { }); it("returns null if the sub frame URL cannot be parsed correctly", async () => { - delete globalThis.location; globalThis.location = { href: "invalid-base" } as Location; sendMockExtensionMessage( { diff --git a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts index f7c46a9fa77..f6afaae202f 100644 --- a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts +++ b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts @@ -945,7 +945,8 @@ export class InlineMenuFieldQualificationService !fieldType || !this.usernameFieldTypes.has(fieldType) || this.isExcludedFieldType(field, this.excludedAutofillFieldTypesSet) || - this.fieldHasDisqualifyingAttributeValue(field) + this.fieldHasDisqualifyingAttributeValue(field) || + this.isTotpField(field) ) { return false; } From 5f9759fde13c86cf4cd580da61919f7e7bd50de7 Mon Sep 17 00:00:00 2001 From: Vince Grassia <593223+vgrassia@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:10:42 -0500 Subject: [PATCH 07/89] Update Linux build job in Build Desktop workflow to free up space on disk (#17784) --- .github/workflows/build-desktop.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index 949263b34b7..c973796207c 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -175,9 +175,23 @@ jobs: - name: Check out repo uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: + fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false + - name: Free disk space for build + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/share/swift + sudo rm -rf /usr/local/.ghcup + sudo rm -rf /usr/share/miniconda + sudo rm -rf /usr/share/az_* + sudo rm -rf /usr/local/julia* + sudo rm -rf /usr/lib/mono + sudo rm -rf /usr/lib/heroku + sudo rm -rf /usr/local/aws-cli + sudo rm -rf /usr/local/aws-sam-cli + - name: Set up Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: From 6ae096485af03192fb30f8a26af0428ffc0601f1 Mon Sep 17 00:00:00 2001 From: "Michael L." Date: Wed, 3 Dec 2025 18:14:07 +0100 Subject: [PATCH 08/89] Add support for Helium browser integration on mac (#17293) Co-authored-by: Addison Beck --- apps/desktop/resources/entitlements.mas.plist | 3 ++- apps/desktop/src/main/native-messaging.main.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/desktop/resources/entitlements.mas.plist b/apps/desktop/resources/entitlements.mas.plist index 3ebd56f0fd7..2977e5fd786 100644 --- a/apps/desktop/resources/entitlements.mas.plist +++ b/apps/desktop/resources/entitlements.mas.plist @@ -32,8 +32,9 @@ /Library/Application Support/Microsoft Edge Beta/NativeMessagingHosts/ /Library/Application Support/Microsoft Edge Dev/NativeMessagingHosts/ /Library/Application Support/Microsoft Edge Canary/NativeMessagingHosts/ - /Library/Application Support/Vivaldi/NativeMessagingHosts/ + /Library/Application Support/Vivaldi/NativeMessagingHosts/ /Library/Application Support/Zen/NativeMessagingHosts/ + /Library/Application Support/net.imput.helium com.apple.security.cs.allow-jit diff --git a/apps/desktop/src/main/native-messaging.main.ts b/apps/desktop/src/main/native-messaging.main.ts index ba5d8616752..23d2e038635 100644 --- a/apps/desktop/src/main/native-messaging.main.ts +++ b/apps/desktop/src/main/native-messaging.main.ts @@ -314,6 +314,7 @@ export class NativeMessagingMain { "Microsoft Edge Canary": `${this.homedir()}/Library/Application\ Support/Microsoft\ Edge\ Canary/`, Vivaldi: `${this.homedir()}/Library/Application\ Support/Vivaldi/`, Zen: `${this.homedir()}/Library/Application\ Support/Zen/`, + Helium: `${this.homedir()}/Library/Application\ Support/net.imput.helium/`, }; /* eslint-enable no-useless-escape */ } From 6e2203d6d4b56ec33a39e26c68a97d5e869fe081 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Wed, 3 Dec 2025 19:04:18 +0100 Subject: [PATCH 09/89] [PM-18026] Implement forced, automatic KDF upgrades (#15937) * Implement automatic kdf upgrades * Fix kdf config not being updated * Update legacy kdf state on master password unlock sync * Fix cli build * Fix * Deduplicate prompts * Fix dismiss time * Fix default kdf setting * Fix build * Undo changes * Fix test * Fix prettier * Fix test * Update libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Only sync when there is at least one migration * Relative imports * Add tech debt comment * Resolve inconsistent prefix * Clean up * Update docs * Use default PBKDF2 iteratinos instead of custom threshold * Undo type check * Fix build * Add comment * Cleanup * Cleanup * Address component feedback * Use isnullorwhitespace * Fix tests * Allow migration only on vault * Fix tests * Run prettier * Fix tests * Prevent await race condition * Fix min and default values in kdf migration * Run sync only when a migration was run * Update libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix link not being blue * Fix later button on browser --------- Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> --- apps/browser/src/_locales/en/messages.json | 21 ++ apps/cli/src/auth/commands/login.command.ts | 4 + apps/cli/src/base-program.ts | 1 + .../commands/unlock.command.spec.ts | 3 + .../key-management/commands/unlock.command.ts | 4 + apps/cli/src/oss-serve-configurator.ts | 1 + apps/cli/src/program.ts | 2 + .../service-container/service-container.ts | 15 + apps/desktop/src/locales/en/messages.json | 18 ++ .../app/auth/recover-two-factor.component.ts | 2 +- .../change-kdf-confirmation.component.spec.ts | 2 +- .../change-kdf-confirmation.component.ts | 2 +- apps/web/src/locales/en/messages.json | 18 ++ .../login-via-webauthn.component.ts | 2 +- ...igrations-scheduler.service.abstraction.ts | 9 + ...ypted-migrations-scheduler.service.spec.ts | 270 ++++++++++++++++++ .../encrypted-migrations-scheduler.service.ts | 188 ++++++++++++ .../prompt-migration-password.component.html | 55 ++++ .../prompt-migration-password.component.ts | 85 ++++++ .../src/services/jslib-services.module.ts | 52 +++- .../login-via-auth-request.component.ts | 2 +- .../auth/src/angular/login/login.component.ts | 2 +- .../new-device-verification.component.ts | 4 +- .../registration-finish.component.ts | 5 +- libs/auth/src/angular/sso/sso.component.ts | 2 +- .../two-factor-auth.component.ts | 2 +- .../login-success-handler.service.ts | 3 +- .../login-strategies/login.strategy.spec.ts | 2 + .../common/login-strategies/login.strategy.ts | 5 + .../password-login.strategy.ts | 4 + ...ault-login-success-handler.service.spec.ts | 14 +- .../default-login-success-handler.service.ts | 10 +- .../src/auth/models/domain/auth-result.ts | 2 + .../default-encrypted-migrator.spec.ts | 194 +++++++++++++ .../default-encrypted-migrator.ts | 113 ++++++++ .../encrypted-migrator.abstraction.ts | 32 +++ .../migrations/encrypted-migration.ts | 36 +++ .../migrations/minimum-kdf-migration.spec.ts | 184 ++++++++++++ .../migrations/minimum-kdf-migration.ts | 68 +++++ ...n.ts => change-kdf.service.abstraction.ts} | 0 ...ice.spec.ts => change-kdf.service.spec.ts} | 2 +- ...e-kdf-service.ts => change-kdf.service.ts} | 2 +- .../master-password.service.abstraction.ts | 7 + .../services/fake-master-password.service.ts | 4 + .../services/master-password.service.ts | 15 + .../lock/components/lock.component.spec.ts | 3 + .../src/lock/components/lock.component.ts | 13 + libs/state/src/core/state-definitions.ts | 18 +- 48 files changed, 1471 insertions(+), 31 deletions(-) create mode 100644 libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.abstraction.ts create mode 100644 libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts create mode 100644 libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.ts create mode 100644 libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.html create mode 100644 libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.ts create mode 100644 libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.spec.ts create mode 100644 libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.ts create mode 100644 libs/common/src/key-management/encrypted-migrator/encrypted-migrator.abstraction.ts create mode 100644 libs/common/src/key-management/encrypted-migrator/migrations/encrypted-migration.ts create mode 100644 libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.spec.ts create mode 100644 libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.ts rename libs/common/src/key-management/kdf/{change-kdf-service.abstraction.ts => change-kdf.service.abstraction.ts} (100%) rename libs/common/src/key-management/kdf/{change-kdf-service.spec.ts => change-kdf.service.spec.ts} (99%) rename libs/common/src/key-management/kdf/{change-kdf-service.ts => change-kdf.service.ts} (97%) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 6a7df1678bf..bbdea838e62 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index d0ab062d0b3..661e052fb72 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -31,6 +31,7 @@ import { TwoFactorService, TwoFactorApiService } from "@bitwarden/common/auth/tw import { ClientType } from "@bitwarden/common/enums"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; @@ -81,6 +82,7 @@ export class LoginCommand { protected ssoUrlService: SsoUrlService, protected i18nService: I18nService, protected masterPasswordService: MasterPasswordServiceAbstraction, + protected encryptedMigrator: EncryptedMigrator, ) {} async run(email: string, password: string, options: OptionValues) { @@ -367,6 +369,8 @@ export class LoginCommand { } } + await this.encryptedMigrator.runMigrations(response.userId, password); + return await this.handleSuccessResponse(response); } catch (e) { if ( diff --git a/apps/cli/src/base-program.ts b/apps/cli/src/base-program.ts index 69a5e4e1bde..71c3830b4cc 100644 --- a/apps/cli/src/base-program.ts +++ b/apps/cli/src/base-program.ts @@ -182,6 +182,7 @@ export abstract class BaseProgram { this.serviceContainer.organizationApiService, this.serviceContainer.logout, this.serviceContainer.i18nService, + this.serviceContainer.encryptedMigrator, this.serviceContainer.masterPasswordUnlockService, this.serviceContainer.configService, ); diff --git a/apps/cli/src/key-management/commands/unlock.command.spec.ts b/apps/cli/src/key-management/commands/unlock.command.spec.ts index 928a750dca6..70e9a8fd232 100644 --- a/apps/cli/src/key-management/commands/unlock.command.spec.ts +++ b/apps/cli/src/key-management/commands/unlock.command.spec.ts @@ -7,6 +7,7 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; import { MasterPasswordVerificationResponse } from "@bitwarden/common/auth/types/verification"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { MasterPasswordUnlockService } from "@bitwarden/common/key-management/master-password/abstractions/master-password-unlock.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; @@ -40,6 +41,7 @@ describe("UnlockCommand", () => { const organizationApiService = mock(); const logout = jest.fn(); const i18nService = mock(); + const encryptedMigrator = mock(); const masterPasswordUnlockService = mock(); const configService = mock(); @@ -92,6 +94,7 @@ describe("UnlockCommand", () => { organizationApiService, logout, i18nService, + encryptedMigrator, masterPasswordUnlockService, configService, ); diff --git a/apps/cli/src/key-management/commands/unlock.command.ts b/apps/cli/src/key-management/commands/unlock.command.ts index 4ae8ce823a4..c88d9ae1cc4 100644 --- a/apps/cli/src/key-management/commands/unlock.command.ts +++ b/apps/cli/src/key-management/commands/unlock.command.ts @@ -9,6 +9,7 @@ import { VerificationType } from "@bitwarden/common/auth/enums/verification-type import { MasterPasswordVerification } from "@bitwarden/common/auth/types/verification"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { MasterPasswordUnlockService } from "@bitwarden/common/key-management/master-password/abstractions/master-password-unlock.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; @@ -38,6 +39,7 @@ export class UnlockCommand { private organizationApiService: OrganizationApiServiceAbstraction, private logout: () => Promise, private i18nService: I18nService, + private encryptedMigrator: EncryptedMigrator, private masterPasswordUnlockService: MasterPasswordUnlockService, private configService: ConfigService, ) {} @@ -116,6 +118,8 @@ export class UnlockCommand { } } + await this.encryptedMigrator.runMigrations(userId, password); + return this.successResponse(); } diff --git a/apps/cli/src/oss-serve-configurator.ts b/apps/cli/src/oss-serve-configurator.ts index bd51cf4dd91..dbe17224d07 100644 --- a/apps/cli/src/oss-serve-configurator.ts +++ b/apps/cli/src/oss-serve-configurator.ts @@ -176,6 +176,7 @@ export class OssServeConfigurator { this.serviceContainer.organizationApiService, async () => await this.serviceContainer.logout(), this.serviceContainer.i18nService, + this.serviceContainer.encryptedMigrator, this.serviceContainer.masterPasswordUnlockService, this.serviceContainer.configService, ); diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index a47278db089..3e5b5678629 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -195,6 +195,7 @@ export class Program extends BaseProgram { this.serviceContainer.ssoUrlService, this.serviceContainer.i18nService, this.serviceContainer.masterPasswordService, + this.serviceContainer.encryptedMigrator, ); const response = await command.run(email, password, options); this.processResponse(response, true); @@ -311,6 +312,7 @@ export class Program extends BaseProgram { this.serviceContainer.organizationApiService, async () => await this.serviceContainer.logout(), this.serviceContainer.i18nService, + this.serviceContainer.encryptedMigrator, this.serviceContainer.masterPasswordUnlockService, this.serviceContainer.configService, ); diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index c163b7581b4..e29bc517f24 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -76,6 +76,10 @@ import { import { EncryptServiceImplementation } from "@bitwarden/common/key-management/crypto/services/encrypt.service.implementation"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { DeviceTrustService } from "@bitwarden/common/key-management/device-trust/services/device-trust.service.implementation"; +import { DefaultEncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/default-encrypted-migrator"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; +import { DefaultChangeKdfApiService } from "@bitwarden/common/key-management/kdf/change-kdf-api.service"; +import { DefaultChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf.service"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/services/key-connector.service"; import { MasterPasswordUnlockService } from "@bitwarden/common/key-management/master-password/abstractions/master-password-unlock.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; @@ -324,6 +328,7 @@ export class ServiceContainer { cipherEncryptionService: CipherEncryptionService; restrictedItemTypesService: RestrictedItemTypesService; cliRestrictedItemTypesService: CliRestrictedItemTypesService; + encryptedMigrator: EncryptedMigrator; securityStateService: SecurityStateService; masterPasswordUnlockService: MasterPasswordUnlockService; cipherArchiveService: CipherArchiveService; @@ -975,6 +980,16 @@ export class ServiceContainer { ); this.masterPasswordApiService = new MasterPasswordApiService(this.apiService, this.logService); + const changeKdfApiService = new DefaultChangeKdfApiService(this.apiService); + const changeKdfService = new DefaultChangeKdfService(changeKdfApiService, this.sdkService); + this.encryptedMigrator = new DefaultEncryptedMigrator( + this.kdfConfigService, + changeKdfService, + this.logService, + this.configService, + this.masterPasswordService, + this.syncService, + ); } async logout() { diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 757059c4e41..8da3ba54844 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, diff --git a/apps/web/src/app/auth/recover-two-factor.component.ts b/apps/web/src/app/auth/recover-two-factor.component.ts index 9c033b88a75..20f40b5319a 100644 --- a/apps/web/src/app/auth/recover-two-factor.component.ts +++ b/apps/web/src/app/auth/recover-two-factor.component.ts @@ -108,7 +108,7 @@ export class RecoverTwoFactorComponent implements OnInit { message: this.i18nService.t("twoStepRecoverDisabled"), }); - await this.loginSuccessHandlerService.run(authResult.userId); + await this.loginSuccessHandlerService.run(authResult.userId, this.masterPassword); await this.router.navigate(["/settings/security/two-factor"]); } catch (error: unknown) { diff --git a/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.spec.ts b/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.spec.ts index 525ddd89675..2c2caba7b3a 100644 --- a/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.spec.ts +++ b/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.spec.ts @@ -4,7 +4,7 @@ import { mock, MockProxy } from "jest-mock-extended"; import { of } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { ChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf-service.abstraction"; +import { ChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf.service.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; diff --git a/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.ts b/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.ts index b730a3597ba..ffeabffa019 100644 --- a/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.ts +++ b/apps/web/src/app/key-management/change-kdf/change-kdf-confirmation.component.ts @@ -5,7 +5,7 @@ import { firstValueFrom, Observable } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf-service.abstraction"; +import { ChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf.service.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 582efade7f4..19eec245885 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -4621,6 +4621,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, diff --git a/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts b/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts index fa2a01fe8e1..764d9fe7733 100644 --- a/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts +++ b/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts @@ -120,7 +120,7 @@ export class LoginViaWebAuthnComponent implements OnInit { // Only run loginSuccessHandlerService if webAuthn is used for vault decryption. const userKey = await firstValueFrom(this.keyService.userKey$(authResult.userId)); if (userKey) { - await this.loginSuccessHandlerService.run(authResult.userId); + await this.loginSuccessHandlerService.run(authResult.userId, null); } await this.router.navigate([this.successRoute]); diff --git a/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.abstraction.ts b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.abstraction.ts new file mode 100644 index 00000000000..565cbb02cf0 --- /dev/null +++ b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.abstraction.ts @@ -0,0 +1,9 @@ +import { UserId } from "@bitwarden/common/types/guid"; + +export abstract class EncryptedMigrationsSchedulerService { + /** + * Runs migrations for a user if needed, handling both interactive and non-interactive cases + * @param userId The user ID to run migrations for + */ + abstract runMigrationsIfNeeded(userId: UserId): Promise; +} diff --git a/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts new file mode 100644 index 00000000000..76cfbc0bfdd --- /dev/null +++ b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts @@ -0,0 +1,270 @@ +import { Router } from "@angular/router"; +import { mock } from "jest-mock-extended"; +import { of } from "rxjs"; + +import { AccountInfo } from "@bitwarden/common/auth/abstractions/account.service"; +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { SingleUserState, StateProvider } from "@bitwarden/common/platform/state"; +import { SyncService } from "@bitwarden/common/platform/sync"; +import { FakeAccountService } from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; +import { DialogService, ToastService } from "@bitwarden/components"; +import { LogService } from "@bitwarden/logging"; + +import { + DefaultEncryptedMigrationsSchedulerService, + ENCRYPTED_MIGRATION_DISMISSED, +} from "./encrypted-migrations-scheduler.service"; +import { PromptMigrationPasswordComponent } from "./prompt-migration-password.component"; + +const SomeUser = "SomeUser" as UserId; +const AnotherUser = "SomeOtherUser" as UserId; +const accounts: Record = { + [SomeUser]: { + name: "some user", + email: "some.user@example.com", + emailVerified: true, + }, + [AnotherUser]: { + name: "some other user", + email: "some.other.user@example.com", + emailVerified: true, + }, +}; + +describe("DefaultEncryptedMigrationsSchedulerService", () => { + let service: DefaultEncryptedMigrationsSchedulerService; + const mockAccountService = new FakeAccountService(accounts); + const mockAuthService = mock(); + const mockEncryptedMigrator = mock(); + const mockStateProvider = mock(); + const mockSyncService = mock(); + const mockDialogService = mock(); + const mockToastService = mock(); + const mockI18nService = mock(); + const mockLogService = mock(); + const mockRouter = mock(); + + const mockUserId = "test-user-id" as UserId; + const mockMasterPassword = "test-master-password"; + + const createMockUserState = (value: T): jest.Mocked> => + ({ + state$: of(value), + userId: mockUserId, + update: jest.fn(), + combinedState$: of([mockUserId, value]), + }) as any; + + beforeEach(() => { + const mockDialogRef = { + closed: of(mockMasterPassword), + }; + + jest.spyOn(PromptMigrationPasswordComponent, "open").mockReturnValue(mockDialogRef as any); + mockI18nService.t.mockReturnValue("translated_migrationsFailed"); + (mockRouter as any)["events"] = of({ url: "/vault" }) as any; + + service = new DefaultEncryptedMigrationsSchedulerService( + mockSyncService, + mockAccountService, + mockStateProvider, + mockEncryptedMigrator, + mockAuthService, + mockLogService, + mockDialogService, + mockToastService, + mockI18nService, + mockRouter, + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("runMigrationsIfNeeded", () => { + it("should return early if user is not unlocked", async () => { + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Locked)); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockEncryptedMigrator.needsMigrations).not.toHaveBeenCalled(); + expect(mockLogService.info).not.toHaveBeenCalled(); + }); + + it("should log and return when no migration is needed", async () => { + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Unlocked)); + mockEncryptedMigrator.needsMigrations.mockResolvedValue("noMigrationNeeded"); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockEncryptedMigrator.needsMigrations).toHaveBeenCalledWith(mockUserId); + expect(mockLogService.info).toHaveBeenCalledWith( + `[EncryptedMigrationsScheduler] No migrations needed for user ${mockUserId}`, + ); + expect(mockEncryptedMigrator.runMigrations).not.toHaveBeenCalled(); + }); + + it("should run migrations without interaction when master password is not required", async () => { + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Unlocked)); + mockEncryptedMigrator.needsMigrations.mockResolvedValue("needsMigration"); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockEncryptedMigrator.needsMigrations).toHaveBeenCalledWith(mockUserId); + expect(mockLogService.info).toHaveBeenCalledWith( + `[EncryptedMigrationsScheduler] User ${mockUserId} needs migrations with master password`, + ); + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith(mockUserId, null); + }); + + it("should run migrations with interaction when migration is needed", async () => { + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Unlocked)); + mockEncryptedMigrator.needsMigrations.mockResolvedValue("needsMigrationWithMasterPassword"); + const mockUserState = createMockUserState(null); + mockStateProvider.getUser.mockReturnValue(mockUserState); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockEncryptedMigrator.needsMigrations).toHaveBeenCalledWith(mockUserId); + expect(mockLogService.info).toHaveBeenCalledWith( + `[EncryptedMigrationsScheduler] User ${mockUserId} needs migrations with master password`, + ); + expect(PromptMigrationPasswordComponent.open).toHaveBeenCalledWith(mockDialogService); + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith( + mockUserId, + mockMasterPassword, + ); + }); + }); + + describe("runMigrationsWithoutInteraction", () => { + it("should run migrations without master password", async () => { + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Unlocked)); + mockEncryptedMigrator.needsMigrations.mockResolvedValue("needsMigration"); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith(mockUserId, null); + expect(mockLogService.error).not.toHaveBeenCalled(); + }); + + it("should handle errors during migration without interaction", async () => { + const mockError = new Error("Migration failed"); + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Unlocked)); + mockEncryptedMigrator.needsMigrations.mockResolvedValue("needsMigration"); + mockEncryptedMigrator.runMigrations.mockRejectedValue(mockError); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith(mockUserId, null); + expect(mockLogService.error).toHaveBeenCalledWith( + "[EncryptedMigrationsScheduler] Error during migration without interaction", + mockError, + ); + }); + }); + + describe("runMigrationsWithInteraction", () => { + beforeEach(() => { + mockAuthService.authStatusFor$.mockReturnValue(of(AuthenticationStatus.Unlocked)); + mockEncryptedMigrator.needsMigrations.mockResolvedValue("needsMigrationWithMasterPassword"); + }); + + it("should skip if migration was dismissed recently", async () => { + const recentDismissDate = new Date(Date.now() - 12 * 60 * 60 * 1000); // 12 hours ago + const mockUserState = createMockUserState(recentDismissDate); + mockStateProvider.getUser.mockReturnValue(mockUserState); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockStateProvider.getUser).toHaveBeenCalledWith( + mockUserId, + ENCRYPTED_MIGRATION_DISMISSED, + ); + expect(mockLogService.info).toHaveBeenCalledWith( + "[EncryptedMigrationsScheduler] Migration prompt dismissed recently, skipping for now.", + ); + expect(PromptMigrationPasswordComponent.open).not.toHaveBeenCalled(); + }); + + it("should prompt for migration if dismissed date is older than 24 hours", async () => { + const oldDismissDate = new Date(Date.now() - 25 * 60 * 60 * 1000); // 25 hours ago + const mockUserState = createMockUserState(oldDismissDate); + mockStateProvider.getUser.mockReturnValue(mockUserState); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(mockStateProvider.getUser).toHaveBeenCalledWith( + mockUserId, + ENCRYPTED_MIGRATION_DISMISSED, + ); + expect(PromptMigrationPasswordComponent.open).toHaveBeenCalledWith(mockDialogService); + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith( + mockUserId, + mockMasterPassword, + ); + }); + + it("should prompt for migration if no dismiss date exists", async () => { + const mockUserState = createMockUserState(null); + mockStateProvider.getUser.mockReturnValue(mockUserState); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(PromptMigrationPasswordComponent.open).toHaveBeenCalledWith(mockDialogService); + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith( + mockUserId, + mockMasterPassword, + ); + }); + + it("should set dismiss date when empty password is provided", async () => { + const mockUserState = createMockUserState(null); + mockStateProvider.getUser.mockReturnValue(mockUserState); + + const mockDialogRef = { + closed: of(""), // Empty password + }; + jest.spyOn(PromptMigrationPasswordComponent, "open").mockReturnValue(mockDialogRef as any); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(PromptMigrationPasswordComponent.open).toHaveBeenCalledWith(mockDialogService); + expect(mockEncryptedMigrator.runMigrations).not.toHaveBeenCalled(); + expect(mockStateProvider.setUserState).toHaveBeenCalledWith( + ENCRYPTED_MIGRATION_DISMISSED, + expect.any(Date), + mockUserId, + ); + }); + + it("should handle errors during migration prompt and show toast", async () => { + const mockUserState = createMockUserState(null); + mockStateProvider.getUser.mockReturnValue(mockUserState); + + const mockError = new Error("Migration failed"); + mockEncryptedMigrator.runMigrations.mockRejectedValue(mockError); + + await service.runMigrationsIfNeeded(mockUserId); + + expect(PromptMigrationPasswordComponent.open).toHaveBeenCalledWith(mockDialogService); + expect(mockEncryptedMigrator.runMigrations).toHaveBeenCalledWith( + mockUserId, + mockMasterPassword, + ); + expect(mockLogService.error).toHaveBeenCalledWith( + "[EncryptedMigrationsScheduler] Error during migration prompt", + mockError, + ); + expect(mockToastService.showToast).toHaveBeenCalledWith({ + variant: "error", + message: "translated_migrationsFailed", + }); + }); + }); +}); diff --git a/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.ts b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.ts new file mode 100644 index 00000000000..1c50919d1cb --- /dev/null +++ b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.ts @@ -0,0 +1,188 @@ +import { NavigationEnd, Router } from "@angular/router"; +import { + combineLatest, + switchMap, + of, + firstValueFrom, + filter, + concatMap, + Observable, + map, +} from "rxjs"; + +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { + UserKeyDefinition, + ENCRYPTED_MIGRATION_DISK, + StateProvider, +} from "@bitwarden/common/platform/state"; +import { SyncService } from "@bitwarden/common/platform/sync"; +import { UserId } from "@bitwarden/common/types/guid"; +import { DialogService, ToastService } from "@bitwarden/components"; +import { LogService } from "@bitwarden/logging"; + +import { EncryptedMigrationsSchedulerService } from "./encrypted-migrations-scheduler.service.abstraction"; +import { PromptMigrationPasswordComponent } from "./prompt-migration-password.component"; + +export const ENCRYPTED_MIGRATION_DISMISSED = new UserKeyDefinition( + ENCRYPTED_MIGRATION_DISK, + "encryptedMigrationDismissed", + { + deserializer: (obj: string) => (obj != null ? new Date(obj) : null), + clearOn: [], + }, +); +const DISMISS_TIME_HOURS = 24; +const VAULT_ROUTE = "/vault"; + +/** + * This services schedules encrypted migrations for users on clients that are interactive (non-cli), and handles manual interaction, + * if it is required by showing a UI prompt. It is only one means of triggering migrations, in case the user stays unlocked for a while, + * or regularly logs in without a master-password, when the migrations do require a master-password to run. + */ +export class DefaultEncryptedMigrationsSchedulerService + implements EncryptedMigrationsSchedulerService +{ + isMigrating = false; + url$: Observable; + + constructor( + private syncService: SyncService, + private accountService: AccountService, + private stateProvider: StateProvider, + private encryptedMigrator: EncryptedMigrator, + private authService: AuthService, + private logService: LogService, + private dialogService: DialogService, + private toastService: ToastService, + private i18nService: I18nService, + private router: Router, + ) { + this.url$ = this.router.events.pipe( + filter((event: any) => event instanceof NavigationEnd), + map((event: NavigationEnd) => event.url), + ); + + // For all accounts, if the auth status changes to unlocked or a sync happens, prompt for migration + this.accountService.accounts$ + .pipe( + switchMap((accounts) => { + const userIds = Object.keys(accounts) as UserId[]; + + if (userIds.length === 0) { + return of([]); + } + + return combineLatest( + userIds.map((userId) => + combineLatest([ + this.authService.authStatusFor$(userId), + this.syncService.lastSync$(userId).pipe(filter((lastSync) => lastSync != null)), + this.url$, + ]).pipe( + filter( + ([authStatus, _date, url]) => + authStatus === AuthenticationStatus.Unlocked && url === VAULT_ROUTE, + ), + concatMap(() => this.runMigrationsIfNeeded(userId)), + ), + ), + ); + }), + ) + .subscribe(); + } + + async runMigrationsIfNeeded(userId: UserId): Promise { + const authStatus = await firstValueFrom(this.authService.authStatusFor$(userId)); + if (authStatus !== AuthenticationStatus.Unlocked) { + return; + } + + if (this.isMigrating || this.encryptedMigrator.isRunningMigrations()) { + this.logService.info( + `[EncryptedMigrationsScheduler] Skipping migration check for user ${userId} because migrations are already in progress`, + ); + return; + } + + this.isMigrating = true; + switch (await this.encryptedMigrator.needsMigrations(userId)) { + case "noMigrationNeeded": + this.logService.info( + `[EncryptedMigrationsScheduler] No migrations needed for user ${userId}`, + ); + break; + case "needsMigrationWithMasterPassword": + this.logService.info( + `[EncryptedMigrationsScheduler] User ${userId} needs migrations with master password`, + ); + // If the user is unlocked, we can run migrations with the master password + await this.runMigrationsWithInteraction(userId); + break; + case "needsMigration": + this.logService.info( + `[EncryptedMigrationsScheduler] User ${userId} needs migrations with master password`, + ); + // If the user is unlocked, we can prompt for the master password + await this.runMigrationsWithoutInteraction(userId); + break; + } + this.isMigrating = false; + } + + private async runMigrationsWithoutInteraction(userId: UserId): Promise { + try { + await this.encryptedMigrator.runMigrations(userId, null); + } catch (error) { + this.logService.error( + "[EncryptedMigrationsScheduler] Error during migration without interaction", + error, + ); + } + } + + private async runMigrationsWithInteraction(userId: UserId): Promise { + // A dialog can be dismissed for a certain amount of time + const dismissedDate = await firstValueFrom( + this.stateProvider.getUser(userId, ENCRYPTED_MIGRATION_DISMISSED).state$, + ); + if (dismissedDate != null) { + const now = new Date(); + const timeDiff = now.getTime() - (dismissedDate as Date).getTime(); + const hoursDiff = timeDiff / (1000 * 60 * 60); + + if (hoursDiff < DISMISS_TIME_HOURS) { + this.logService.info( + "[EncryptedMigrationsScheduler] Migration prompt dismissed recently, skipping for now.", + ); + return; + } + } + + try { + const dialog = PromptMigrationPasswordComponent.open(this.dialogService); + const masterPassword = await firstValueFrom(dialog.closed); + if (Utils.isNullOrWhitespace(masterPassword)) { + await this.stateProvider.setUserState(ENCRYPTED_MIGRATION_DISMISSED, new Date(), userId); + } else { + await this.encryptedMigrator.runMigrations( + userId, + masterPassword === undefined ? null : masterPassword, + ); + } + } catch (error) { + this.logService.error("[EncryptedMigrationsScheduler] Error during migration prompt", error); + // If migrations failed when the user actively was prompted, show a toast + this.toastService.showToast({ + variant: "error", + message: this.i18nService.t("migrationsFailed"), + }); + } + } +} diff --git a/libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.html b/libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.html new file mode 100644 index 00000000000..6df08342885 --- /dev/null +++ b/libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.html @@ -0,0 +1,55 @@ +
+ +
+ {{ "updateEncryptionSettingsTitle" | i18n }} +
+
+

+ {{ "updateEncryptionSettingsDesc" | i18n }} + + {{ "learnMore" | i18n }} + + +

+ + {{ "masterPass" | i18n }} + {{ "confirmIdentityToContinue" | i18n }} + + + +
+ + + + +
+
diff --git a/libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.ts b/libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.ts new file mode 100644 index 00000000000..060901d68fb --- /dev/null +++ b/libs/angular/src/key-management/encrypted-migration/prompt-migration-password.component.ts @@ -0,0 +1,85 @@ +import { CommonModule } from "@angular/common"; +import { Component, inject, ChangeDetectionStrategy } from "@angular/core"; +import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms"; +import { filter, firstValueFrom, map } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; +import { + LinkModule, + AsyncActionsModule, + ButtonModule, + DialogModule, + DialogRef, + DialogService, + FormFieldModule, + IconButtonModule, +} from "@bitwarden/components"; + +/** + * This is a generic prompt to run encryption migrations that require the master password. + */ +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: "prompt-migration-password.component.html", + imports: [ + DialogModule, + LinkModule, + CommonModule, + JslibModule, + ButtonModule, + IconButtonModule, + ReactiveFormsModule, + AsyncActionsModule, + FormFieldModule, + ], +}) +export class PromptMigrationPasswordComponent { + private dialogRef = inject(DialogRef); + private formBuilder = inject(FormBuilder); + private uvService = inject(UserVerificationService); + private accountService = inject(AccountService); + + migrationPasswordForm = this.formBuilder.group({ + masterPassword: ["", [Validators.required]], + }); + + static open(dialogService: DialogService) { + return dialogService.open(PromptMigrationPasswordComponent); + } + + submit = async () => { + const masterPasswordControl = this.migrationPasswordForm.controls.masterPassword; + + if (!masterPasswordControl.value || masterPasswordControl.invalid) { + return; + } + + const { userId, email } = await firstValueFrom( + this.accountService.activeAccount$.pipe( + filter((account) => account != null), + map((account) => { + return { + userId: account!.id, + email: account!.email, + }; + }), + ), + ); + + if ( + !(await this.uvService.verifyUserByMasterPassword( + { type: VerificationType.MasterPassword, secret: masterPasswordControl.value }, + userId, + email, + )) + ) { + return; + } + + // Return the master password to the caller + this.dialogRef.close(masterPasswordControl.value); + }; +} diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 1589f5c5f30..13935beab19 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1,6 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { ErrorHandler, LOCALE_ID, NgModule } from "@angular/core"; +import { APP_INITIALIZER, ErrorHandler, LOCALE_ID, NgModule } from "@angular/core"; +import { Router } from "@angular/router"; import { Subject } from "rxjs"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. @@ -177,10 +178,12 @@ import { EncryptServiceImplementation } from "@bitwarden/common/key-management/c import { WebCryptoFunctionService } from "@bitwarden/common/key-management/crypto/services/web-crypto-function.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { DeviceTrustService } from "@bitwarden/common/key-management/device-trust/services/device-trust.service.implementation"; +import { DefaultEncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/default-encrypted-migrator"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { DefaultChangeKdfApiService } from "@bitwarden/common/key-management/kdf/change-kdf-api.service"; import { ChangeKdfApiService } from "@bitwarden/common/key-management/kdf/change-kdf-api.service.abstraction"; -import { DefaultChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf-service"; -import { ChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf-service.abstraction"; +import { DefaultChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf.service"; +import { ChangeKdfService } from "@bitwarden/common/key-management/kdf/change-kdf.service.abstraction"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/services/key-connector.service"; import { KeyApiService } from "@bitwarden/common/key-management/keys/services/abstractions/key-api-service.abstraction"; @@ -328,6 +331,7 @@ import { DefaultTaskService, TaskService } from "@bitwarden/common/vault/tasks"; import { AnonLayoutWrapperDataService, DefaultAnonLayoutWrapperDataService, + DialogService, ToastService, } from "@bitwarden/components"; import { @@ -396,6 +400,8 @@ import { DeviceTrustToastService as DeviceTrustToastServiceAbstraction } from ". import { DeviceTrustToastService } from "../auth/services/device-trust-toast.service.implementation"; import { NoopPremiumInterestStateService } from "../billing/services/premium-interest/noop-premium-interest-state.service"; import { PremiumInterestStateService } from "../billing/services/premium-interest/premium-interest-state.service.abstraction"; +import { DefaultEncryptedMigrationsSchedulerService } from "../key-management/encrypted-migration/encrypted-migrations-scheduler.service"; +import { EncryptedMigrationsSchedulerService } from "../key-management/encrypted-migration/encrypted-migrations-scheduler.service.abstraction"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "../platform/abstractions/form-validation-errors.service"; import { DocumentLangSetter } from "../platform/i18n"; import { FormValidationErrorsService } from "../platform/services/form-validation-errors.service"; @@ -516,6 +522,23 @@ const safeProviders: SafeProvider[] = [ TokenServiceAbstraction, ], }), + safeProvider({ + provide: ChangeKdfService, + useClass: DefaultChangeKdfService, + deps: [ChangeKdfApiService, SdkService], + }), + safeProvider({ + provide: EncryptedMigrator, + useClass: DefaultEncryptedMigrator, + deps: [ + KdfConfigService, + ChangeKdfService, + LogService, + ConfigService, + MasterPasswordServiceAbstraction, + SyncService, + ], + }), safeProvider({ provide: LoginStrategyServiceAbstraction, useClass: LoginStrategyService, @@ -1665,6 +1688,7 @@ const safeProviders: SafeProvider[] = [ SsoLoginServiceAbstraction, SyncService, UserAsymmetricKeysRegenerationService, + EncryptedMigrator, LogService, ], }), @@ -1735,6 +1759,28 @@ const safeProviders: SafeProvider[] = [ InternalMasterPasswordServiceAbstraction, ], }), + safeProvider({ + provide: EncryptedMigrationsSchedulerService, + useClass: DefaultEncryptedMigrationsSchedulerService, + deps: [ + SyncService, + AccountService, + StateProvider, + EncryptedMigrator, + AuthServiceAbstraction, + LogService, + DialogService, + ToastService, + I18nServiceAbstraction, + Router, + ], + }), + safeProvider({ + provide: APP_INITIALIZER as SafeInjectionToken<() => Promise>, + useFactory: (encryptedMigrationsScheduler: EncryptedMigrationsSchedulerService) => () => {}, + deps: [EncryptedMigrationsSchedulerService], + multi: true, + }), safeProvider({ provide: LockService, useClass: DefaultLockService, diff --git a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts index 2436593dfda..040d4d3c121 100644 --- a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts +++ b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts @@ -822,7 +822,7 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy { } private async handleSuccessfulLoginNavigation(userId: UserId) { - await this.loginSuccessHandlerService.run(userId); + await this.loginSuccessHandlerService.run(userId, null); await this.router.navigate(["vault"]); } } diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index 0b011b5641f..91ca2b614d1 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -382,7 +382,7 @@ export class LoginComponent implements OnInit, OnDestroy { } // User logged in successfully so execute side effects - await this.loginSuccessHandlerService.run(authResult.userId); + await this.loginSuccessHandlerService.run(authResult.userId, authResult.masterPassword); // Determine where to send the user next // The AuthGuard will handle routing to change-password based on state diff --git a/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts b/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts index c3d6ff5d1fe..726cfd7b3b5 100644 --- a/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts +++ b/libs/auth/src/angular/new-device-verification/new-device-verification.component.ts @@ -152,9 +152,7 @@ export class NewDeviceVerificationComponent implements OnInit, OnDestroy { return; } - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.loginSuccessHandlerService.run(authResult.userId); + await this.loginSuccessHandlerService.run(authResult.userId, authResult.masterPassword); // TODO: PM-22663 use the new service to handle routing. const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); diff --git a/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts b/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts index 19e7c1feabd..99eaa2404d9 100644 --- a/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts +++ b/libs/auth/src/angular/registration/registration-finish/registration-finish.component.ts @@ -206,7 +206,10 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy { return; } - await this.loginSuccessHandlerService.run(authenticationResult.userId); + await this.loginSuccessHandlerService.run( + authenticationResult.userId, + authenticationResult.masterPassword ?? null, + ); if (this.premiumInterest) { await this.premiumInterestStateService.setPremiumInterest( diff --git a/libs/auth/src/angular/sso/sso.component.ts b/libs/auth/src/angular/sso/sso.component.ts index bf618ba39f4..d0cc2bd83e5 100644 --- a/libs/auth/src/angular/sso/sso.component.ts +++ b/libs/auth/src/angular/sso/sso.component.ts @@ -437,7 +437,7 @@ export class SsoComponent implements OnInit { // Everything after the 2FA check is considered a successful login // Just have to figure out where to send the user - await this.loginSuccessHandlerService.run(authResult.userId); + await this.loginSuccessHandlerService.run(authResult.userId, null); // Save off the OrgSsoIdentifier for use in the TDE flows (or elsewhere) // - TDE login decryption options component diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts index ca19d3652bb..4c143cc59f9 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts @@ -450,7 +450,7 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy { } // User is fully logged in so handle any post login logic before executing navigation - await this.loginSuccessHandlerService.run(authResult.userId); + await this.loginSuccessHandlerService.run(authResult.userId, authResult.masterPassword); // Save off the OrgSsoIdentifier for use in the TDE flows // - TDE login decryption options component diff --git a/libs/auth/src/common/abstractions/login-success-handler.service.ts b/libs/auth/src/common/abstractions/login-success-handler.service.ts index 8dee1dd32b9..e6d75d661f5 100644 --- a/libs/auth/src/common/abstractions/login-success-handler.service.ts +++ b/libs/auth/src/common/abstractions/login-success-handler.service.ts @@ -5,6 +5,7 @@ export abstract class LoginSuccessHandlerService { * Runs any service calls required after a successful login. * Service calls that should be included in this method are only those required to be awaited after successful login. * @param userId The user id. + * @param masterPassword The master password, if available. Null when logging in with SSO or other non-master-password methods. */ - abstract run(userId: UserId): Promise; + abstract run(userId: UserId, masterPassword: string | null): Promise; } diff --git a/libs/auth/src/common/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts index 38d62cfdd83..ceb36a44633 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -308,6 +308,7 @@ describe("LoginStrategy", () => { const result = await passwordLoginStrategy.logIn(credentials); const expected = new AuthResult(); + expected.masterPassword = "password"; expected.userId = userId; expected.resetMasterPassword = true; expected.twoFactorProviders = null; @@ -323,6 +324,7 @@ describe("LoginStrategy", () => { const result = await passwordLoginStrategy.logIn(credentials); const expected = new AuthResult(); + expected.masterPassword = "password"; expected.userId = userId; expected.resetMasterPassword = false; expected.twoFactorProviders = null; diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index b8e4ee9e822..2e3c41da900 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -108,6 +108,8 @@ export abstract class LoginStrategy { data.tokenRequest.setTwoFactor(twoFactor); this.cache.next(data); const [authResult] = await this.startLogIn(); + // There is an import cycle between PasswordLoginStrategyData and LoginStrategy, which means this cast is necessary, which is solved by extracting the data classes. + authResult.masterPassword = (this.cache.value as any)["masterPassword"] ?? null; return authResult; } @@ -264,6 +266,9 @@ export abstract class LoginStrategy { await this.processForceSetPasswordReason(response.forcePasswordReset, userId); this.messagingService.send("loggedIn"); + // There is an import cycle between PasswordLoginStrategyData and LoginStrategy, which means this cast is necessary, which is solved by extracting the data classes. + // TODO: https://bitwarden.atlassian.net/browse/PM-27573 + result.masterPassword = (this.cache.value as any)["masterPassword"] ?? null; return result; } diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.ts b/libs/auth/src/common/login-strategies/password-login.strategy.ts index 829351cc88f..ad49567b2ff 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.ts @@ -33,6 +33,8 @@ export class PasswordLoginStrategyData implements LoginStrategyData { localMasterKeyHash: string; /** The user's master key */ masterKey: MasterKey; + /** The user's master password */ + masterPassword: string; /** * Tracks if the user needs to update their password due to * a password that does not meet an organization's master password policy. @@ -83,6 +85,7 @@ export class PasswordLoginStrategy extends LoginStrategy { masterPassword, email, ); + data.masterPassword = masterPassword; data.userEnteredEmail = email; // Hash the password early (before authentication) so we don't persist it in memory in plaintext @@ -251,6 +254,7 @@ export class PasswordLoginStrategy extends LoginStrategy { this.cache.next(data); const [authResult] = await this.startLogIn(); + authResult.masterPassword = this.cache.value["masterPassword"] ?? null; return authResult; } diff --git a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts index 6fb355a8a1b..caa5d8b3290 100644 --- a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts +++ b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts @@ -1,6 +1,7 @@ import { MockProxy, mock } from "jest-mock-extended"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; @@ -19,6 +20,7 @@ describe("DefaultLoginSuccessHandlerService", () => { let ssoLoginService: MockProxy; let syncService: MockProxy; let userAsymmetricKeysRegenerationService: MockProxy; + let encryptedMigrator: MockProxy; let logService: MockProxy; const userId = "USER_ID" as UserId; @@ -30,6 +32,7 @@ describe("DefaultLoginSuccessHandlerService", () => { ssoLoginService = mock(); syncService = mock(); userAsymmetricKeysRegenerationService = mock(); + encryptedMigrator = mock(); logService = mock(); service = new DefaultLoginSuccessHandlerService( @@ -38,6 +41,7 @@ describe("DefaultLoginSuccessHandlerService", () => { ssoLoginService, syncService, userAsymmetricKeysRegenerationService, + encryptedMigrator, logService, ); @@ -50,7 +54,7 @@ describe("DefaultLoginSuccessHandlerService", () => { describe("run", () => { it("should call required services on successful login", async () => { - await service.run(userId); + await service.run(userId, null); expect(syncService.fullSync).toHaveBeenCalledWith(true, { skipTokenRefresh: true }); expect(userAsymmetricKeysRegenerationService.regenerateIfNeeded).toHaveBeenCalledWith(userId); @@ -58,7 +62,7 @@ describe("DefaultLoginSuccessHandlerService", () => { }); it("should get SSO email", async () => { - await service.run(userId); + await service.run(userId, null); expect(ssoLoginService.getSsoEmail).toHaveBeenCalled(); }); @@ -68,8 +72,8 @@ describe("DefaultLoginSuccessHandlerService", () => { ssoLoginService.getSsoEmail.mockResolvedValue(null); }); - it("should log error and return early", async () => { - await service.run(userId); + it("should not check SSO requirements", async () => { + await service.run(userId, null); expect(logService.debug).toHaveBeenCalledWith("SSO login email not found."); expect(ssoLoginService.updateSsoRequiredCache).not.toHaveBeenCalled(); @@ -82,7 +86,7 @@ describe("DefaultLoginSuccessHandlerService", () => { }); it("should call updateSsoRequiredCache() and clearSsoEmail()", async () => { - await service.run(userId); + await service.run(userId, null); expect(ssoLoginService.updateSsoRequiredCache).toHaveBeenCalledWith(testEmail, userId); expect(ssoLoginService.clearSsoEmail).toHaveBeenCalled(); diff --git a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts index 2b9672f1c0b..9d4311868d7 100644 --- a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts +++ b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts @@ -1,4 +1,5 @@ import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; @@ -15,12 +16,19 @@ export class DefaultLoginSuccessHandlerService implements LoginSuccessHandlerSer private ssoLoginService: SsoLoginServiceAbstraction, private syncService: SyncService, private userAsymmetricKeysRegenerationService: UserAsymmetricKeysRegenerationService, + private encryptedMigrator: EncryptedMigrator, private logService: LogService, ) {} - async run(userId: UserId): Promise { + + async run(userId: UserId, masterPassword: string | null): Promise { await this.syncService.fullSync(true, { skipTokenRefresh: true }); await this.userAsymmetricKeysRegenerationService.regenerateIfNeeded(userId); await this.loginEmailService.clearLoginEmail(); + try { + await this.encryptedMigrator.runMigrations(userId, masterPassword); + } catch { + // Don't block login success on migration failure + } const ssoLoginEmail = await this.ssoLoginService.getSsoEmail(); diff --git a/libs/common/src/auth/models/domain/auth-result.ts b/libs/common/src/auth/models/domain/auth-result.ts index a61a35eeb1d..ae3e9bdeda6 100644 --- a/libs/common/src/auth/models/domain/auth-result.ts +++ b/libs/common/src/auth/models/domain/auth-result.ts @@ -18,6 +18,8 @@ export class AuthResult { email: string; requiresEncryptionKeyMigration: boolean; requiresDeviceVerification: boolean; + // The master-password used in the authentication process + masterPassword: string | null; get requiresTwoFactor() { return this.twoFactorProviders != null; diff --git a/libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.spec.ts b/libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.spec.ts new file mode 100644 index 00000000000..5a681ec2913 --- /dev/null +++ b/libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.spec.ts @@ -0,0 +1,194 @@ +import { mock } from "jest-mock-extended"; + +// eslint-disable-next-line no-restricted-imports +import { KdfConfigService } from "@bitwarden/key-management"; +import { LogService } from "@bitwarden/logging"; + +import { ConfigService } from "../../platform/abstractions/config/config.service"; +import { SyncService } from "../../platform/sync"; +import { UserId } from "../../types/guid"; +import { ChangeKdfService } from "../kdf/change-kdf.service.abstraction"; +import { MasterPasswordServiceAbstraction } from "../master-password/abstractions/master-password.service.abstraction"; + +import { DefaultEncryptedMigrator } from "./default-encrypted-migrator"; +import { EncryptedMigration } from "./migrations/encrypted-migration"; +import { MinimumKdfMigration } from "./migrations/minimum-kdf-migration"; + +jest.mock("./migrations/minimum-kdf-migration"); + +describe("EncryptedMigrator", () => { + const mockKdfConfigService = mock(); + const mockChangeKdfService = mock(); + const mockLogService = mock(); + const configService = mock(); + const masterPasswordService = mock(); + const syncService = mock(); + + let sut: DefaultEncryptedMigrator; + const mockMigration = mock(); + + const mockUserId = "00000000-0000-0000-0000-000000000000" as UserId; + const mockMasterPassword = "masterPassword123"; + + beforeEach(() => { + jest.clearAllMocks(); + + // Mock the MinimumKdfMigration constructor to return our mock + (MinimumKdfMigration as jest.MockedClass).mockImplementation( + () => mockMigration, + ); + + sut = new DefaultEncryptedMigrator( + mockKdfConfigService, + mockChangeKdfService, + mockLogService, + configService, + masterPasswordService, + syncService, + ); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe("runMigrations", () => { + it("should throw error when userId is null", async () => { + await expect(sut.runMigrations(null as any, null)).rejects.toThrow("userId"); + }); + + it("should throw error when userId is undefined", async () => { + await expect(sut.runMigrations(undefined as any, null)).rejects.toThrow("userId"); + }); + + it("should not run migration when needsMigration returns 'noMigrationNeeded'", async () => { + mockMigration.needsMigration.mockResolvedValue("noMigrationNeeded"); + + await sut.runMigrations(mockUserId, null); + + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockMigration.runMigrations).not.toHaveBeenCalled(); + }); + + it("should run migration when needsMigration returns 'needsMigration'", async () => { + mockMigration.needsMigration.mockResolvedValue("needsMigration"); + + await sut.runMigrations(mockUserId, mockMasterPassword); + + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockMigration.runMigrations).toHaveBeenCalledWith(mockUserId, mockMasterPassword); + }); + + it("should run migration when needsMigration returns 'needsMigrationWithMasterPassword'", async () => { + mockMigration.needsMigration.mockResolvedValue("needsMigrationWithMasterPassword"); + + await sut.runMigrations(mockUserId, mockMasterPassword); + + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockMigration.runMigrations).toHaveBeenCalledWith(mockUserId, mockMasterPassword); + }); + + it("should throw error when migration needs master password but null is provided", async () => { + mockMigration.needsMigration.mockResolvedValue("needsMigrationWithMasterPassword"); + + await sut.runMigrations(mockUserId, null); + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockMigration.runMigrations).not.toHaveBeenCalled(); + }); + + it("should run multiple migrations", async () => { + const mockSecondMigration = mock(); + mockSecondMigration.needsMigration.mockResolvedValue("needsMigration"); + + (sut as any).migrations.push({ + name: "Test Second Migration", + migration: mockSecondMigration, + }); + + mockMigration.needsMigration.mockResolvedValue("needsMigration"); + + await sut.runMigrations(mockUserId, mockMasterPassword); + + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockSecondMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockMigration.runMigrations).toHaveBeenCalledWith(mockUserId, mockMasterPassword); + expect(mockSecondMigration.runMigrations).toHaveBeenCalledWith( + mockUserId, + mockMasterPassword, + ); + }); + }); + + describe("needsMigrations", () => { + it("should return 'noMigrationNeeded' when no migrations are needed", async () => { + mockMigration.needsMigration.mockResolvedValue("noMigrationNeeded"); + + const result = await sut.needsMigrations(mockUserId); + + expect(result).toBe("noMigrationNeeded"); + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + }); + + it("should return 'needsMigration' when at least one migration needs to run", async () => { + mockMigration.needsMigration.mockResolvedValue("needsMigration"); + + const result = await sut.needsMigrations(mockUserId); + + expect(result).toBe("needsMigration"); + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + }); + + it("should return 'needsMigrationWithMasterPassword' when at least one migration needs master password", async () => { + mockMigration.needsMigration.mockResolvedValue("needsMigrationWithMasterPassword"); + + const result = await sut.needsMigrations(mockUserId); + + expect(result).toBe("needsMigrationWithMasterPassword"); + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + }); + + it("should prioritize 'needsMigrationWithMasterPassword' over 'needsMigration'", async () => { + const mockSecondMigration = mock(); + mockSecondMigration.needsMigration.mockResolvedValue("needsMigration"); + + (sut as any).migrations.push({ + name: "Test Second Migration", + migration: mockSecondMigration, + }); + + mockMigration.needsMigration.mockResolvedValue("needsMigrationWithMasterPassword"); + + const result = await sut.needsMigrations(mockUserId); + + expect(result).toBe("needsMigrationWithMasterPassword"); + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockSecondMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + }); + + it("should return 'needsMigration' when some migrations need running but none need master password", async () => { + const mockSecondMigration = mock(); + mockSecondMigration.needsMigration.mockResolvedValue("noMigrationNeeded"); + + (sut as any).migrations.push({ + name: "Test Second Migration", + migration: mockSecondMigration, + }); + + mockMigration.needsMigration.mockResolvedValue("needsMigration"); + + const result = await sut.needsMigrations(mockUserId); + + expect(result).toBe("needsMigration"); + expect(mockMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + expect(mockSecondMigration.needsMigration).toHaveBeenCalledWith(mockUserId); + }); + + it("should throw error when userId is null", async () => { + await expect(sut.needsMigrations(null as any)).rejects.toThrow("userId"); + }); + + it("should throw error when userId is undefined", async () => { + await expect(sut.needsMigrations(undefined as any)).rejects.toThrow("userId"); + }); + }); +}); diff --git a/libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.ts b/libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.ts new file mode 100644 index 00000000000..bc91e24070a --- /dev/null +++ b/libs/common/src/key-management/encrypted-migrator/default-encrypted-migrator.ts @@ -0,0 +1,113 @@ +// eslint-disable-next-line no-restricted-imports +import { KdfConfigService } from "@bitwarden/key-management"; +import { LogService } from "@bitwarden/logging"; + +import { assertNonNullish } from "../../auth/utils"; +import { ConfigService } from "../../platform/abstractions/config/config.service"; +import { SyncService } from "../../platform/sync"; +import { UserId } from "../../types/guid"; +import { ChangeKdfService } from "../kdf/change-kdf.service.abstraction"; +import { MasterPasswordServiceAbstraction } from "../master-password/abstractions/master-password.service.abstraction"; + +import { EncryptedMigrator } from "./encrypted-migrator.abstraction"; +import { EncryptedMigration, MigrationRequirement } from "./migrations/encrypted-migration"; +import { MinimumKdfMigration } from "./migrations/minimum-kdf-migration"; + +export class DefaultEncryptedMigrator implements EncryptedMigrator { + private migrations: { name: string; migration: EncryptedMigration }[] = []; + private isRunningMigration = false; + + constructor( + readonly kdfConfigService: KdfConfigService, + readonly changeKdfService: ChangeKdfService, + private readonly logService: LogService, + readonly configService: ConfigService, + readonly masterPasswordService: MasterPasswordServiceAbstraction, + readonly syncService: SyncService, + ) { + // Register migrations here + this.migrations.push({ + name: "Minimum PBKDF2 Iteration Count Migration", + migration: new MinimumKdfMigration( + kdfConfigService, + changeKdfService, + logService, + configService, + masterPasswordService, + ), + }); + } + + async runMigrations(userId: UserId, masterPassword: string | null): Promise { + assertNonNullish(userId, "userId"); + + // Ensure that the requirements for running all migrations are met + const needsMigration = await this.needsMigrations(userId); + if (needsMigration === "noMigrationNeeded") { + return; + } else if (needsMigration === "needsMigrationWithMasterPassword" && masterPassword == null) { + // If a migration needs a password, but none is provided, the migrations are skipped. If a manual caller + // during a login / unlock flow calls without a master password in a login / unlock strategy that has no + // password, such as biometric unlock, the migrations are skipped. + // + // The fallback to this, the encrypted migrations scheduler, will first check if a migration needs a password + // and then prompt the user. If the user enters their password, runMigrations is called again with the password. + return; + } + + try { + // No concurrent migrations allowed, so acquire a service-wide lock + if (this.isRunningMigration) { + return; + } + this.isRunningMigration = true; + + // Run all migrations sequentially in the order they were registered + this.logService.mark("[Encrypted Migrator] Start"); + this.logService.info(`[Encrypted Migrator] Starting migrations for user: ${userId}`); + let ranMigration = false; + for (const { name, migration } of this.migrations) { + if ((await migration.needsMigration(userId)) !== "noMigrationNeeded") { + this.logService.info(`[Encrypted Migrator] Running migration: ${name}`); + const start = performance.now(); + await migration.runMigrations(userId, masterPassword); + this.logService.measure(start, "[Encrypted Migrator]", name, "ExecutionTime"); + ranMigration = true; + } + } + this.logService.mark("[Encrypted Migrator] Finish"); + this.logService.info(`[Encrypted Migrator] Completed migrations for user: ${userId}`); + if (ranMigration) { + await this.syncService.fullSync(true); + } + } catch (error) { + this.logService.error( + `[Encrypted Migrator] Error running migrations for user: ${userId}`, + error, + ); + throw error; // Re-throw the error to be handled by the caller + } finally { + this.isRunningMigration = false; + } + } + + async needsMigrations(userId: UserId): Promise { + assertNonNullish(userId, "userId"); + + const migrationRequirements = await Promise.all( + this.migrations.map(async ({ migration }) => migration.needsMigration(userId)), + ); + + if (migrationRequirements.includes("needsMigrationWithMasterPassword")) { + return "needsMigrationWithMasterPassword"; + } else if (migrationRequirements.includes("needsMigration")) { + return "needsMigration"; + } else { + return "noMigrationNeeded"; + } + } + + isRunningMigrations(): boolean { + return this.isRunningMigration; + } +} diff --git a/libs/common/src/key-management/encrypted-migrator/encrypted-migrator.abstraction.ts b/libs/common/src/key-management/encrypted-migrator/encrypted-migrator.abstraction.ts new file mode 100644 index 00000000000..7e408374f7e --- /dev/null +++ b/libs/common/src/key-management/encrypted-migrator/encrypted-migrator.abstraction.ts @@ -0,0 +1,32 @@ +import { UserId } from "../../types/guid"; + +import { MigrationRequirement } from "./migrations/encrypted-migration"; + +export abstract class EncryptedMigrator { + /** + * Runs migrations on a decrypted user, with the cryptographic state initialized. + * This only runs the migrations that are needed for the user. + * This needs to be run after the decrypted user key has been set to state. + * + * If the master password is required but not provided, the migrations will not run, and the function will return early. + * If migrations are already running, the migrations will not run again, and the function will return early. + * + * @param userId The ID of the user to run migrations for. + * @param masterPassword The user's current master password. + * @throws If the user does not exist + * @throws If the user is locked or logged out + * @throws If a migration fails + */ + abstract runMigrations(userId: UserId, masterPassword: string | null): Promise; + /** + * Checks if the user needs to run any migrations. + * This is used to determine if the user should be prompted to run migrations. + * @param userId The ID of the user to check migrations for. + */ + abstract needsMigrations(userId: UserId): Promise; + + /** + * Indicates whether migrations are currently running. + */ + abstract isRunningMigrations(): boolean; +} diff --git a/libs/common/src/key-management/encrypted-migrator/migrations/encrypted-migration.ts b/libs/common/src/key-management/encrypted-migrator/migrations/encrypted-migration.ts new file mode 100644 index 00000000000..e6b1dcc45f6 --- /dev/null +++ b/libs/common/src/key-management/encrypted-migrator/migrations/encrypted-migration.ts @@ -0,0 +1,36 @@ +import { UserId } from "../../../types/guid"; + +/** + * @internal + * IMPORTANT: Please read this when implementing new migrations. + * + * An encrypted migration defines an online migration that mutates the persistent state of the user on the server, or locally. + * It should only be run once per user (or for local migrations, once per device). Migrations get scheduled automatically, + * during actions such as login and unlock, or during sync. + * + * Migrations can require the master-password, which is provided by the user if required. + * Migrations are run as soon as possible non-lazily, and MAY block unlock / login, if they have to run. + * + * Most importantly, implementing a migration should be done such that concurrent migrations may fail, but must never + * leave the user in a broken state. Locally, these are scheduled with an application-global lock. However, no such guarantees + * are made for the server, and other devices may run the migration concurrently. + * + * When adding a migration, it *MUST* be feature-flagged for the initial roll-out. + */ +export interface EncryptedMigration { + /** + * Runs the migration. + * @throws If the migration fails, such as when no network is available. + * @throws If the requirements for migration are not met (e.g. the user is locked) + */ + runMigrations(userId: UserId, masterPassword: string | null): Promise; + /** + * Returns whether the migration needs to be run for the user, and if it does, whether the master password is required. + */ + needsMigration(userId: UserId): Promise; +} + +export type MigrationRequirement = + | "needsMigration" + | "needsMigrationWithMasterPassword" + | "noMigrationNeeded"; diff --git a/libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.spec.ts b/libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.spec.ts new file mode 100644 index 00000000000..cf2bd307b6c --- /dev/null +++ b/libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.spec.ts @@ -0,0 +1,184 @@ +import { mock } from "jest-mock-extended"; + +// eslint-disable-next-line no-restricted-imports +import { + Argon2KdfConfig, + KdfConfigService, + KdfType, + PBKDF2KdfConfig, +} from "@bitwarden/key-management"; +import { LogService } from "@bitwarden/logging"; + +import { FeatureFlag } from "../../../enums/feature-flag.enum"; +import { ConfigService } from "../../../platform/abstractions/config/config.service"; +import { UserId } from "../../../types/guid"; +import { ChangeKdfService } from "../../kdf/change-kdf.service.abstraction"; +import { MasterPasswordServiceAbstraction } from "../../master-password/abstractions/master-password.service.abstraction"; + +import { MinimumKdfMigration } from "./minimum-kdf-migration"; + +describe("MinimumKdfMigration", () => { + const mockKdfConfigService = mock(); + const mockChangeKdfService = mock(); + const mockLogService = mock(); + const mockConfigService = mock(); + const mockMasterPasswordService = mock(); + + let sut: MinimumKdfMigration; + + const mockUserId = "00000000-0000-0000-0000-000000000000" as UserId; + const mockMasterPassword = "masterPassword"; + + beforeEach(() => { + jest.clearAllMocks(); + + sut = new MinimumKdfMigration( + mockKdfConfigService, + mockChangeKdfService, + mockLogService, + mockConfigService, + mockMasterPasswordService, + ); + }); + + describe("needsMigration", () => { + it("should return 'noMigrationNeeded' when user does not have a master password`", async () => { + mockMasterPasswordService.userHasMasterPassword.mockResolvedValue(false); + const result = await sut.needsMigration(mockUserId); + expect(result).toBe("noMigrationNeeded"); + }); + + it("should return 'noMigrationNeeded' when user uses argon2id`", async () => { + mockMasterPasswordService.userHasMasterPassword.mockResolvedValue(true); + mockKdfConfigService.getKdfConfig.mockResolvedValue(new Argon2KdfConfig(3, 64, 4)); + const result = await sut.needsMigration(mockUserId); + expect(result).toBe("noMigrationNeeded"); + }); + + it("should return 'noMigrationNeeded' when PBKDF2 iterations are already above minimum", async () => { + const mockKdfConfig = { + kdfType: KdfType.PBKDF2_SHA256, + iterations: PBKDF2KdfConfig.ITERATIONS.min + 1000, + }; + mockKdfConfigService.getKdfConfig.mockResolvedValue(mockKdfConfig as any); + + const result = await sut.needsMigration(mockUserId); + + expect(result).toBe("noMigrationNeeded"); + expect(mockKdfConfigService.getKdfConfig).toHaveBeenCalledWith(mockUserId); + }); + + it("should return 'noMigrationNeeded' when PBKDF2 iterations equal minimum", async () => { + const mockKdfConfig = { + kdfType: KdfType.PBKDF2_SHA256, + iterations: PBKDF2KdfConfig.ITERATIONS.min, + }; + mockKdfConfigService.getKdfConfig.mockResolvedValue(mockKdfConfig as any); + mockConfigService.getFeatureFlag.mockResolvedValue(true); + + const result = await sut.needsMigration(mockUserId); + + expect(result).toBe("noMigrationNeeded"); + expect(mockKdfConfigService.getKdfConfig).toHaveBeenCalledWith(mockUserId); + }); + + it("should return 'noMigrationNeeded' when feature flag is disabled", async () => { + const mockKdfConfig = { + kdfType: KdfType.PBKDF2_SHA256, + iterations: PBKDF2KdfConfig.ITERATIONS.min - 1000, + }; + mockKdfConfigService.getKdfConfig.mockResolvedValue(mockKdfConfig as any); + mockConfigService.getFeatureFlag.mockResolvedValue(false); + + const result = await sut.needsMigration(mockUserId); + + expect(result).toBe("noMigrationNeeded"); + expect(mockKdfConfigService.getKdfConfig).toHaveBeenCalledWith(mockUserId); + expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( + FeatureFlag.ForceUpdateKDFSettings, + ); + }); + + it("should return 'needsMigrationWithMasterPassword' when PBKDF2 iterations are below minimum and feature flag is enabled", async () => { + const mockKdfConfig = { + kdfType: KdfType.PBKDF2_SHA256, + iterations: PBKDF2KdfConfig.ITERATIONS.min - 1000, + }; + mockKdfConfigService.getKdfConfig.mockResolvedValue(mockKdfConfig as any); + mockConfigService.getFeatureFlag.mockResolvedValue(true); + + const result = await sut.needsMigration(mockUserId); + + expect(result).toBe("needsMigrationWithMasterPassword"); + expect(mockKdfConfigService.getKdfConfig).toHaveBeenCalledWith(mockUserId); + expect(mockConfigService.getFeatureFlag).toHaveBeenCalledWith( + FeatureFlag.ForceUpdateKDFSettings, + ); + }); + + it("should throw error when userId is null", async () => { + await expect(sut.needsMigration(null as any)).rejects.toThrow("userId"); + }); + + it("should throw error when userId is undefined", async () => { + await expect(sut.needsMigration(undefined as any)).rejects.toThrow("userId"); + }); + }); + + describe("runMigrations", () => { + it("should update KDF parameters with minimum PBKDF2 iterations", async () => { + await sut.runMigrations(mockUserId, mockMasterPassword); + + expect(mockLogService.info).toHaveBeenCalledWith( + `[MinimumKdfMigration] Updating user ${mockUserId} to minimum PBKDF2 iteration count ${PBKDF2KdfConfig.ITERATIONS.min}`, + ); + expect(mockChangeKdfService.updateUserKdfParams).toHaveBeenCalledWith( + mockMasterPassword, + expect.any(PBKDF2KdfConfig), + mockUserId, + ); + + // Verify the PBKDF2KdfConfig has the correct iteration count + const kdfConfigArg = (mockChangeKdfService.updateUserKdfParams as jest.Mock).mock.calls[0][1]; + expect(kdfConfigArg.iterations).toBe(PBKDF2KdfConfig.ITERATIONS.defaultValue); + }); + + it("should throw error when userId is null", async () => { + await expect(sut.runMigrations(null as any, mockMasterPassword)).rejects.toThrow("userId"); + }); + + it("should throw error when userId is undefined", async () => { + await expect(sut.runMigrations(undefined as any, mockMasterPassword)).rejects.toThrow( + "userId", + ); + }); + + it("should throw error when masterPassword is null", async () => { + await expect(sut.runMigrations(mockUserId, null as any)).rejects.toThrow("masterPassword"); + }); + + it("should throw error when masterPassword is undefined", async () => { + await expect(sut.runMigrations(mockUserId, undefined as any)).rejects.toThrow( + "masterPassword", + ); + }); + + it("should handle errors from changeKdfService", async () => { + const mockError = new Error("KDF update failed"); + mockChangeKdfService.updateUserKdfParams.mockRejectedValue(mockError); + + await expect(sut.runMigrations(mockUserId, mockMasterPassword)).rejects.toThrow( + "KDF update failed", + ); + + expect(mockLogService.info).toHaveBeenCalledWith( + `[MinimumKdfMigration] Updating user ${mockUserId} to minimum PBKDF2 iteration count ${PBKDF2KdfConfig.ITERATIONS.min}`, + ); + expect(mockChangeKdfService.updateUserKdfParams).toHaveBeenCalledWith( + mockMasterPassword, + expect.any(PBKDF2KdfConfig), + mockUserId, + ); + }); + }); +}); diff --git a/libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.ts b/libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.ts new file mode 100644 index 00000000000..0666064b36e --- /dev/null +++ b/libs/common/src/key-management/encrypted-migrator/migrations/minimum-kdf-migration.ts @@ -0,0 +1,68 @@ +import { UserId } from "@bitwarden/common/types/guid"; +// eslint-disable-next-line no-restricted-imports +import { KdfConfigService, KdfType, PBKDF2KdfConfig } from "@bitwarden/key-management"; +import { LogService } from "@bitwarden/logging"; + +import { assertNonNullish } from "../../../auth/utils"; +import { FeatureFlag } from "../../../enums/feature-flag.enum"; +import { ConfigService } from "../../../platform/abstractions/config/config.service"; +import { ChangeKdfService } from "../../kdf/change-kdf.service.abstraction"; +import { MasterPasswordServiceAbstraction } from "../../master-password/abstractions/master-password.service.abstraction"; + +import { EncryptedMigration, MigrationRequirement } from "./encrypted-migration"; + +/** + * @internal + * This migrator ensures the user's account has a minimum PBKDF2 iteration count. + * It will update the entire account, logging out old clients if necessary. + */ +export class MinimumKdfMigration implements EncryptedMigration { + constructor( + private readonly kdfConfigService: KdfConfigService, + private readonly changeKdfService: ChangeKdfService, + private readonly logService: LogService, + private readonly configService: ConfigService, + private readonly masterPasswordService: MasterPasswordServiceAbstraction, + ) {} + + async runMigrations(userId: UserId, masterPassword: string | null): Promise { + assertNonNullish(userId, "userId"); + assertNonNullish(masterPassword, "masterPassword"); + + this.logService.info( + `[MinimumKdfMigration] Updating user ${userId} to minimum PBKDF2 iteration count ${PBKDF2KdfConfig.ITERATIONS.defaultValue}`, + ); + await this.changeKdfService.updateUserKdfParams( + masterPassword!, + new PBKDF2KdfConfig(PBKDF2KdfConfig.ITERATIONS.defaultValue), + userId, + ); + await this.kdfConfigService.setKdfConfig( + userId, + new PBKDF2KdfConfig(PBKDF2KdfConfig.ITERATIONS.defaultValue), + ); + } + + async needsMigration(userId: UserId): Promise { + assertNonNullish(userId, "userId"); + + if (!(await this.masterPasswordService.userHasMasterPassword(userId))) { + return "noMigrationNeeded"; + } + + // Only PBKDF2 users below the minimum iteration count need migration + const kdfConfig = await this.kdfConfigService.getKdfConfig(userId); + if ( + kdfConfig.kdfType !== KdfType.PBKDF2_SHA256 || + kdfConfig.iterations >= PBKDF2KdfConfig.ITERATIONS.min + ) { + return "noMigrationNeeded"; + } + + if (!(await this.configService.getFeatureFlag(FeatureFlag.ForceUpdateKDFSettings))) { + return "noMigrationNeeded"; + } + + return "needsMigrationWithMasterPassword"; + } +} diff --git a/libs/common/src/key-management/kdf/change-kdf-service.abstraction.ts b/libs/common/src/key-management/kdf/change-kdf.service.abstraction.ts similarity index 100% rename from libs/common/src/key-management/kdf/change-kdf-service.abstraction.ts rename to libs/common/src/key-management/kdf/change-kdf.service.abstraction.ts diff --git a/libs/common/src/key-management/kdf/change-kdf-service.spec.ts b/libs/common/src/key-management/kdf/change-kdf.service.spec.ts similarity index 99% rename from libs/common/src/key-management/kdf/change-kdf-service.spec.ts rename to libs/common/src/key-management/kdf/change-kdf.service.spec.ts index c7df90f4790..12096155641 100644 --- a/libs/common/src/key-management/kdf/change-kdf-service.spec.ts +++ b/libs/common/src/key-management/kdf/change-kdf.service.spec.ts @@ -17,7 +17,7 @@ import { } from "../master-password/types/master-password.types"; import { ChangeKdfApiService } from "./change-kdf-api.service.abstraction"; -import { DefaultChangeKdfService } from "./change-kdf-service"; +import { DefaultChangeKdfService } from "./change-kdf.service"; describe("ChangeKdfService", () => { const changeKdfApiService = mock(); diff --git a/libs/common/src/key-management/kdf/change-kdf-service.ts b/libs/common/src/key-management/kdf/change-kdf.service.ts similarity index 97% rename from libs/common/src/key-management/kdf/change-kdf-service.ts rename to libs/common/src/key-management/kdf/change-kdf.service.ts index 64fbd1fce05..89d97e6704f 100644 --- a/libs/common/src/key-management/kdf/change-kdf-service.ts +++ b/libs/common/src/key-management/kdf/change-kdf.service.ts @@ -14,7 +14,7 @@ import { } from "../master-password/types/master-password.types"; import { ChangeKdfApiService } from "./change-kdf-api.service.abstraction"; -import { ChangeKdfService } from "./change-kdf-service.abstraction"; +import { ChangeKdfService } from "./change-kdf.service.abstraction"; export class DefaultChangeKdfService implements ChangeKdfService { constructor( diff --git a/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts b/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts index f982c2c5ce8..0e86761685f 100644 --- a/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts +++ b/libs/common/src/key-management/master-password/abstractions/master-password.service.abstraction.ts @@ -106,6 +106,13 @@ export abstract class MasterPasswordServiceAbstraction { password: string, masterPasswordUnlockData: MasterPasswordUnlockData, ) => Promise; + + /** + * Returns whether the user has a master password set. + * @param userId The user ID. + * @throws If the user ID is missing. + */ + abstract userHasMasterPassword(userId: UserId): Promise; } export abstract class InternalMasterPasswordServiceAbstraction extends MasterPasswordServiceAbstraction { diff --git a/libs/common/src/key-management/master-password/services/fake-master-password.service.ts b/libs/common/src/key-management/master-password/services/fake-master-password.service.ts index 5db7f178b18..90fcaddb1a5 100644 --- a/libs/common/src/key-management/master-password/services/fake-master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/fake-master-password.service.ts @@ -33,6 +33,10 @@ export class FakeMasterPasswordService implements InternalMasterPasswordServiceA this.masterKeyHashSubject.next(initialMasterKeyHash); } + userHasMasterPassword(userId: UserId): Promise { + return this.mock.userHasMasterPassword(userId); + } + emailToSalt(email: string): MasterPasswordSalt { return this.mock.emailToSalt(email); } diff --git a/libs/common/src/key-management/master-password/services/master-password.service.ts b/libs/common/src/key-management/master-password/services/master-password.service.ts index 8012a9230e7..c2947b2263d 100644 --- a/libs/common/src/key-management/master-password/services/master-password.service.ts +++ b/libs/common/src/key-management/master-password/services/master-password.service.ts @@ -25,6 +25,7 @@ import { MasterKey, UserKey } from "../../../types/key"; import { KeyGenerationService } from "../../crypto"; import { CryptoFunctionService } from "../../crypto/abstractions/crypto-function.service"; import { EncryptedString, EncString } from "../../crypto/models/enc-string"; +import { USES_KEY_CONNECTOR } from "../../key-connector/services/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "../abstractions/master-password.service.abstraction"; import { MasterKeyWrappedUserKey, @@ -85,6 +86,19 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr private accountService: AccountService, ) {} + async userHasMasterPassword(userId: UserId): Promise { + assertNonNullish(userId, "userId"); + // A user has a master-password if they have a master-key encrypted user key *but* are not a key connector user + // Note: We can't use the key connector service as an abstraction here because it causes a run-time dependency injection cycle between KC service and MP service. + const usesKeyConnector = await firstValueFrom( + this.stateProvider.getUser(userId, USES_KEY_CONNECTOR).state$, + ); + const usesMasterKey = await firstValueFrom( + this.stateProvider.getUser(userId, MASTER_KEY_ENCRYPTED_USER_KEY).state$, + ); + return usesMasterKey && !usesKeyConnector; + } + saltForUser$(userId: UserId): Observable { assertNonNullish(userId, "userId"); return this.accountService.accounts$.pipe( @@ -307,6 +321,7 @@ export class MasterPasswordService implements InternalMasterPasswordServiceAbstr masterPasswordUnlockData.kdf.toSdkConfig(), ), ); + return userKey as UserKey; } diff --git a/libs/key-management-ui/src/lock/components/lock.component.spec.ts b/libs/key-management-ui/src/lock/components/lock.component.spec.ts index b51d4c13490..b708d101f82 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.spec.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.spec.ts @@ -22,6 +22,7 @@ import { } from "@bitwarden/common/auth/types/verification"; import { ClientType, DeviceType } from "@bitwarden/common/enums"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -91,6 +92,7 @@ describe("LockComponent", () => { const mockLockComponentService = mock(); const mockAnonLayoutWrapperDataService = mock(); const mockBroadcasterService = mock(); + const mockEncryptedMigrator = mock(); const mockConfigService = mock(); beforeEach(async () => { @@ -149,6 +151,7 @@ describe("LockComponent", () => { { provide: LockComponentService, useValue: mockLockComponentService }, { provide: AnonLayoutWrapperDataService, useValue: mockAnonLayoutWrapperDataService }, { provide: BroadcasterService, useValue: mockBroadcasterService }, + { provide: EncryptedMigrator, useValue: mockEncryptedMigrator }, { provide: ConfigService, useValue: mockConfigService }, ], }) diff --git a/libs/key-management-ui/src/lock/components/lock.component.ts b/libs/key-management-ui/src/lock/components/lock.component.ts index 801a9d191f5..7f715d2215d 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.ts @@ -31,6 +31,7 @@ import { import { ClientType, DeviceType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; +import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -177,6 +178,8 @@ export class LockComponent implements OnInit, OnDestroy { private logoutService: LogoutService, private lockComponentService: LockComponentService, private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, + private encryptedMigrator: EncryptedMigrator, + private configService: ConfigService, // desktop deps private broadcasterService: BroadcasterService, @@ -639,6 +642,16 @@ export class LockComponent implements OnInit, OnDestroy { } await this.biometricStateService.resetUserPromptCancelled(); + + try { + await this.encryptedMigrator.runMigrations( + this.activeAccount.id, + afterUnlockActions.passwordEvaluation?.masterPassword ?? null, + ); + } catch { + // Don't block login success on migration failure + } + this.messagingService.send("unlocked"); if (afterUnlockActions.passwordEvaluation) { diff --git a/libs/state/src/core/state-definitions.ts b/libs/state/src/core/state-definitions.ts index 9d404f14dd7..156c03620b7 100644 --- a/libs/state/src/core/state-definitions.ts +++ b/libs/state/src/core/state-definitions.ts @@ -54,8 +54,6 @@ export const DEVICE_TRUST_DISK_LOCAL = new StateDefinition("deviceTrust", "disk" web: "disk-local", browser: "disk-backup-local-storage", }); -export const KDF_CONFIG_DISK = new StateDefinition("kdfConfig", "disk"); -export const KEY_CONNECTOR_DISK = new StateDefinition("keyConnector", "disk"); export const LOGIN_EMAIL_DISK = new StateDefinition("loginEmail", "disk", { web: "disk-local", }); @@ -64,8 +62,6 @@ export const LOGIN_STRATEGY_MEMORY = new StateDefinition("loginStrategy", "memor export const MASTER_PASSWORD_DISK = new StateDefinition("masterPassword", "disk"); export const MASTER_PASSWORD_MEMORY = new StateDefinition("masterPassword", "memory"); export const MASTER_PASSWORD_UNLOCK_DISK = new StateDefinition("masterPasswordUnlock", "disk"); -export const PIN_DISK = new StateDefinition("pinUnlock", "disk"); -export const PIN_MEMORY = new StateDefinition("pinUnlock", "memory"); export const ROUTER_DISK = new StateDefinition("router", "disk"); export const SSO_DISK = new StateDefinition("ssoLogin", "disk"); export const SSO_DISK_LOCAL = new StateDefinition("ssoLoginLocal", "disk", { web: "disk-local" }); @@ -117,13 +113,10 @@ export const PHISHING_DETECTION_DISK = new StateDefinition("phishingDetection", export const APPLICATION_ID_DISK = new StateDefinition("applicationId", "disk", { web: "disk-local", }); -export const BIOMETRIC_SETTINGS_DISK = new StateDefinition("biometricSettings", "disk"); export const CLEAR_EVENT_DISK = new StateDefinition("clearEvent", "disk"); export const CONFIG_DISK = new StateDefinition("config", "disk", { web: "disk-local", }); -export const CRYPTO_DISK = new StateDefinition("crypto", "disk"); -export const CRYPTO_MEMORY = new StateDefinition("crypto", "memory"); export const DESKTOP_SETTINGS_DISK = new StateDefinition("desktopSettings", "disk"); export const ENVIRONMENT_DISK = new StateDefinition("environment", "disk"); export const ENVIRONMENT_MEMORY = new StateDefinition("environment", "memory"); @@ -225,3 +218,14 @@ export const VAULT_BROWSER_INTRO_CAROUSEL = new StateDefinition( "disk", ); export const VAULT_AT_RISK_PASSWORDS_MEMORY = new StateDefinition("vaultAtRiskPasswords", "memory"); + +// KM + +export const BIOMETRIC_SETTINGS_DISK = new StateDefinition("biometricSettings", "disk"); +export const ENCRYPTED_MIGRATION_DISK = new StateDefinition("encryptedMigration", "disk"); +export const PIN_DISK = new StateDefinition("pinUnlock", "disk"); +export const PIN_MEMORY = new StateDefinition("pinUnlock", "memory"); +export const CRYPTO_DISK = new StateDefinition("crypto", "disk"); +export const CRYPTO_MEMORY = new StateDefinition("crypto", "memory"); +export const KDF_CONFIG_DISK = new StateDefinition("kdfConfig", "disk"); +export const KEY_CONNECTOR_DISK = new StateDefinition("keyConnector", "disk"); From 1bfff49ef5d6fc9489d0d6422fd4887388f8bd30 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Wed, 3 Dec 2025 20:10:10 +0100 Subject: [PATCH 10/89] [PM-29122] Fix debug build causing slow unlock (#17798) * Fix debug build causing slow unlock * Cleanup * Fix release mode build actually building debug --- .github/workflows/build-desktop.yml | 8 ++++++-- apps/desktop/desktop_native/napi/scripts/build.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index c973796207c..ab5a1a50c17 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -263,9 +263,11 @@ jobs: PKG_CONFIG_ALLOW_CROSS: true PKG_CONFIG_ALL_STATIC: true TARGET: musl + # Note: It is important that we use the release build because some compute heavy + # operations such as key derivation for oo7 on linux are too slow in debug mode run: | rustup target add x86_64-unknown-linux-musl - node build.js --target=x86_64-unknown-linux-musl + node build.js --target=x86_64-unknown-linux-musl --release - name: Build application run: npm run dist:lin @@ -426,9 +428,11 @@ jobs: PKG_CONFIG_ALLOW_CROSS: true PKG_CONFIG_ALL_STATIC: true TARGET: musl + # Note: It is important that we use the release build because some compute heavy + # operations such as key derivation for oo7 on linux are too slow in debug mode run: | rustup target add aarch64-unknown-linux-musl - node build.js --target=aarch64-unknown-linux-musl + node build.js --target=aarch64-unknown-linux-musl --release - name: Check index.d.ts generated if: github.event_name == 'pull_request' && steps.cache.outputs.cache-hit != 'true' diff --git a/apps/desktop/desktop_native/napi/scripts/build.js b/apps/desktop/desktop_native/napi/scripts/build.js index a6680f5d311..7b3dccf81e4 100644 --- a/apps/desktop/desktop_native/napi/scripts/build.js +++ b/apps/desktop/desktop_native/napi/scripts/build.js @@ -11,4 +11,4 @@ if (isRelease) { process.env.RUST_LOG = 'debug'; } -execSync(`napi build --platform --js false`, { stdio: 'inherit', env: process.env }); +execSync(`napi build --platform --js false ${isRelease ? '--release' : ''}`, { stdio: 'inherit', env: process.env }); From d64da69fa7488421c3063e3784a5ec5fd35768bf Mon Sep 17 00:00:00 2001 From: Alex <55413326+AlexRubik@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:21:58 -0500 Subject: [PATCH 11/89] [PM-6979] Remove HIBP 404 handling (#17769) --- .../dirt/services/hibp-api.service.spec.ts | 21 +++++++++++++++++++ .../common/src/services/audit.service.spec.ts | 13 ++++++------ libs/common/src/services/audit.service.ts | 11 +--------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/libs/common/src/dirt/services/hibp-api.service.spec.ts b/libs/common/src/dirt/services/hibp-api.service.spec.ts index fd2a54bdd10..9e08b4d0623 100644 --- a/libs/common/src/dirt/services/hibp-api.service.spec.ts +++ b/libs/common/src/dirt/services/hibp-api.service.spec.ts @@ -35,5 +35,26 @@ describe("HibpApiService", () => { expect(result).toHaveLength(1); expect(result[0]).toBeInstanceOf(BreachAccountResponse); }); + + it("should return empty array when no breaches found (REST semantics)", async () => { + // Server now returns 200 OK with empty array [] instead of 404 + const mockResponse: any[] = []; + const username = "safe@example.com"; + + apiService.send.mockResolvedValue(mockResponse); + + const result = await sut.getHibpBreach(username); + + expect(apiService.send).toHaveBeenCalledWith( + "GET", + "/hibp/breach?username=" + encodeURIComponent(username), + null, + true, + true, + ); + expect(result).toEqual([]); + expect(result).toBeInstanceOf(Array); + expect(result).toHaveLength(0); + }); }); }); diff --git a/libs/common/src/services/audit.service.spec.ts b/libs/common/src/services/audit.service.spec.ts index b0e96eb5c5c..e653b026735 100644 --- a/libs/common/src/services/audit.service.spec.ts +++ b/libs/common/src/services/audit.service.spec.ts @@ -1,7 +1,6 @@ import { ApiService } from "../abstractions/api.service"; import { HibpApiService } from "../dirt/services/hibp-api.service"; import { CryptoFunctionService } from "../key-management/crypto/abstractions/crypto-function.service"; -import { ErrorResponse } from "../models/response/error.response"; import { AuditService } from "./audit.service"; @@ -73,14 +72,16 @@ describe("AuditService", () => { expect(mockApi.nativeFetch).toHaveBeenCalledTimes(4); }); - it("should return empty array for breachedAccounts on 404", async () => { - mockHibpApi.getHibpBreach.mockRejectedValueOnce({ statusCode: 404 } as ErrorResponse); + it("should return empty array for breachedAccounts when no breaches found", async () => { + // Server returns 200 with empty array (correct REST semantics) + mockHibpApi.getHibpBreach.mockResolvedValueOnce([]); const result = await auditService.breachedAccounts("user@example.com"); expect(result).toEqual([]); }); - it("should throw error for breachedAccounts on non-404 error", async () => { - mockHibpApi.getHibpBreach.mockRejectedValueOnce({ statusCode: 500 } as ErrorResponse); - await expect(auditService.breachedAccounts("user@example.com")).rejects.toThrow(); + it("should propagate errors from breachedAccounts", async () => { + const error = new Error("API error"); + mockHibpApi.getHibpBreach.mockRejectedValueOnce(error); + await expect(auditService.breachedAccounts("user@example.com")).rejects.toBe(error); }); }); diff --git a/libs/common/src/services/audit.service.ts b/libs/common/src/services/audit.service.ts index 0bdf45917de..7762c2cbd93 100644 --- a/libs/common/src/services/audit.service.ts +++ b/libs/common/src/services/audit.service.ts @@ -6,7 +6,6 @@ import { AuditService as AuditServiceAbstraction } from "../abstractions/audit.s import { BreachAccountResponse } from "../dirt/models/response/breach-account.response"; import { HibpApiService } from "../dirt/services/hibp-api.service"; import { CryptoFunctionService } from "../key-management/crypto/abstractions/crypto-function.service"; -import { ErrorResponse } from "../models/response/error.response"; import { Utils } from "../platform/misc/utils"; const PwnedPasswordsApi = "https://api.pwnedpasswords.com/range/"; @@ -70,14 +69,6 @@ export class AuditService implements AuditServiceAbstraction { } async breachedAccounts(username: string): Promise { - try { - return await this.hibpApiService.getHibpBreach(username); - } catch (e) { - const error = e as ErrorResponse; - if (error.statusCode === 404) { - return []; - } - throw new Error(); - } + return this.hibpApiService.getHibpBreach(username); } } From 28fbddb63f80653ea7f6bc3efed8545b3d2ae5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Wed, 3 Dec 2025 20:40:55 +0100 Subject: [PATCH 12/89] fix(passkeys): [PM-28324] Add a guard that conditionally forces a popout depending on platform * Add a guard that conditionally forces a popout depending on platform * Test the routeguard * Use mockImplementation instead. * autoclose popout --- .../guards/platform-popout.guard.spec.ts | 193 ++++++++++++++++++ .../popup/guards/platform-popout.guard.ts | 46 +++++ apps/browser/src/popup/app-routing.module.ts | 3 +- .../login-via-webauthn.component.ts | 21 +- 4 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 apps/browser/src/auth/popup/guards/platform-popout.guard.spec.ts create mode 100644 apps/browser/src/auth/popup/guards/platform-popout.guard.ts diff --git a/apps/browser/src/auth/popup/guards/platform-popout.guard.spec.ts b/apps/browser/src/auth/popup/guards/platform-popout.guard.spec.ts new file mode 100644 index 00000000000..d39012fd88a --- /dev/null +++ b/apps/browser/src/auth/popup/guards/platform-popout.guard.spec.ts @@ -0,0 +1,193 @@ +import { TestBed } from "@angular/core/testing"; +import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router"; + +import { BrowserApi } from "../../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../../platform/browser/browser-popup-utils"; + +import { platformPopoutGuard } from "./platform-popout.guard"; + +describe("platformPopoutGuard", () => { + let getPlatformInfoSpy: jest.SpyInstance; + let inPopoutSpy: jest.SpyInstance; + let inSidebarSpy: jest.SpyInstance; + let openPopoutSpy: jest.SpyInstance; + let closePopupSpy: jest.SpyInstance; + + const mockRoute = {} as ActivatedRouteSnapshot; + const mockState: RouterStateSnapshot = { + url: "/login-with-passkey?param=value", + } as RouterStateSnapshot; + + beforeEach(() => { + getPlatformInfoSpy = jest.spyOn(BrowserApi, "getPlatformInfo"); + inPopoutSpy = jest.spyOn(BrowserPopupUtils, "inPopout"); + inSidebarSpy = jest.spyOn(BrowserPopupUtils, "inSidebar"); + openPopoutSpy = jest.spyOn(BrowserPopupUtils, "openPopout").mockImplementation(); + closePopupSpy = jest.spyOn(BrowserApi, "closePopup").mockImplementation(); + + TestBed.configureTestingModule({}); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("when platform matches", () => { + beforeEach(() => { + getPlatformInfoSpy.mockResolvedValue({ os: "linux" }); + inPopoutSpy.mockReturnValue(false); + inSidebarSpy.mockReturnValue(false); + }); + + it("should open popout and block navigation when not already in popout or sidebar", async () => { + const guard = platformPopoutGuard(["linux"]); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(getPlatformInfoSpy).toHaveBeenCalled(); + expect(inPopoutSpy).toHaveBeenCalledWith(window); + expect(inSidebarSpy).toHaveBeenCalledWith(window); + expect(openPopoutSpy).toHaveBeenCalledWith( + "popup/index.html#/login-with-passkey?param=value&autoClosePopout=true", + ); + expect(closePopupSpy).toHaveBeenCalledWith(window); + expect(result).toBe(false); + }); + + it("should allow navigation when already in popout", async () => { + inPopoutSpy.mockReturnValue(true); + + const guard = platformPopoutGuard(["linux"]); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(openPopoutSpy).not.toHaveBeenCalled(); + expect(closePopupSpy).not.toHaveBeenCalled(); + expect(result).toBe(true); + }); + + it("should allow navigation when already in sidebar", async () => { + inSidebarSpy.mockReturnValue(true); + + const guard = platformPopoutGuard(["linux"]); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(openPopoutSpy).not.toHaveBeenCalled(); + expect(closePopupSpy).not.toHaveBeenCalled(); + expect(result).toBe(true); + }); + }); + + describe("when platform does not match", () => { + beforeEach(() => { + getPlatformInfoSpy.mockResolvedValue({ os: "win" }); + inPopoutSpy.mockReturnValue(false); + inSidebarSpy.mockReturnValue(false); + }); + + it("should allow navigation without opening popout", async () => { + const guard = platformPopoutGuard(["linux"]); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(getPlatformInfoSpy).toHaveBeenCalled(); + expect(openPopoutSpy).not.toHaveBeenCalled(); + expect(result).toBe(true); + }); + }); + + describe("when forcePopout is true", () => { + beforeEach(() => { + getPlatformInfoSpy.mockResolvedValue({ os: "win" }); + inPopoutSpy.mockReturnValue(false); + inSidebarSpy.mockReturnValue(false); + }); + + it("should open popout regardless of platform", async () => { + const guard = platformPopoutGuard(["linux"], true); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(openPopoutSpy).toHaveBeenCalledWith( + "popup/index.html#/login-with-passkey?param=value&autoClosePopout=true", + ); + expect(closePopupSpy).toHaveBeenCalledWith(window); + expect(result).toBe(false); + }); + + it("should not open popout when already in popout", async () => { + inPopoutSpy.mockReturnValue(true); + + const guard = platformPopoutGuard(["linux"], true); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(openPopoutSpy).not.toHaveBeenCalled(); + expect(result).toBe(true); + }); + }); + + describe("with multiple platforms", () => { + beforeEach(() => { + inPopoutSpy.mockReturnValue(false); + inSidebarSpy.mockReturnValue(false); + }); + + it.each(["linux", "mac", "win"])( + "should open popout when platform is %s and included in platforms array", + async (platform) => { + getPlatformInfoSpy.mockResolvedValue({ os: platform }); + + const guard = platformPopoutGuard(["linux", "mac", "win"]); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(openPopoutSpy).toHaveBeenCalledWith( + "popup/index.html#/login-with-passkey?param=value&autoClosePopout=true", + ); + expect(closePopupSpy).toHaveBeenCalledWith(window); + expect(result).toBe(false); + }, + ); + + it("should not open popout when platform is not in the array", async () => { + getPlatformInfoSpy.mockResolvedValue({ os: "android" }); + + const guard = platformPopoutGuard(["linux", "mac"]); + const result = await TestBed.runInInjectionContext(() => guard(mockRoute, mockState)); + + expect(openPopoutSpy).not.toHaveBeenCalled(); + expect(result).toBe(true); + }); + }); + + describe("url handling", () => { + beforeEach(() => { + getPlatformInfoSpy.mockResolvedValue({ os: "linux" }); + inPopoutSpy.mockReturnValue(false); + inSidebarSpy.mockReturnValue(false); + }); + + it("should preserve query parameters in the popout url", async () => { + const stateWithQuery: RouterStateSnapshot = { + url: "/path?foo=bar&baz=qux", + } as RouterStateSnapshot; + + const guard = platformPopoutGuard(["linux"]); + await TestBed.runInInjectionContext(() => guard(mockRoute, stateWithQuery)); + + expect(openPopoutSpy).toHaveBeenCalledWith( + "popup/index.html#/path?foo=bar&baz=qux&autoClosePopout=true", + ); + expect(closePopupSpy).toHaveBeenCalledWith(window); + }); + + it("should handle urls without query parameters", async () => { + const stateWithoutQuery: RouterStateSnapshot = { + url: "/simple-path", + } as RouterStateSnapshot; + + const guard = platformPopoutGuard(["linux"]); + await TestBed.runInInjectionContext(() => guard(mockRoute, stateWithoutQuery)); + + expect(openPopoutSpy).toHaveBeenCalledWith( + "popup/index.html#/simple-path?autoClosePopout=true", + ); + expect(closePopupSpy).toHaveBeenCalledWith(window); + }); + }); +}); diff --git a/apps/browser/src/auth/popup/guards/platform-popout.guard.ts b/apps/browser/src/auth/popup/guards/platform-popout.guard.ts new file mode 100644 index 00000000000..aad005e141b --- /dev/null +++ b/apps/browser/src/auth/popup/guards/platform-popout.guard.ts @@ -0,0 +1,46 @@ +import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot } from "@angular/router"; + +import { BrowserApi } from "../../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../../platform/browser/browser-popup-utils"; + +/** + * Guard that forces a popout window for specific platforms. + * Useful when popup context would close during operations (e.g., WebAuthn on Linux). + * + * @param platforms - Array of platform OS strings (e.g., ["linux", "mac", "win"]) + * @param forcePopout - If true, always force popout regardless of platform (useful for testing) + * @returns CanActivateFn that opens popout and blocks navigation if conditions met + */ +export function platformPopoutGuard( + platforms: string[], + forcePopout: boolean = false, +): CanActivateFn { + return async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + // Check if current platform matches + const platformInfo = await BrowserApi.getPlatformInfo(); + const isPlatformMatch = platforms.includes(platformInfo.os); + + // Check if already in popout/sidebar + const inPopout = BrowserPopupUtils.inPopout(window); + const inSidebar = BrowserPopupUtils.inSidebar(window); + + // Open popout if conditions met + if ((isPlatformMatch || forcePopout) && !inPopout && !inSidebar) { + // Add autoClosePopout query param to signal the popout should close after completion + const [path, existingQuery] = state.url.split("?"); + const params = new URLSearchParams(existingQuery || ""); + params.set("autoClosePopout", "true"); + const urlWithAutoClose = `${path}?${params.toString()}`; + + // Open the popout window + await BrowserPopupUtils.openPopout(`popup/index.html#${urlWithAutoClose}`); + + // Close the original popup window + BrowserApi.closePopup(window); + + return false; // Block navigation - popout will reload + } + + return true; // Allow navigation + }; +} diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index a36396afa1a..48f06147cdf 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -48,6 +48,7 @@ import { LockComponent, ConfirmKeyConnectorDomainComponent } from "@bitwarden/ke import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component"; import { AuthExtensionRoute } from "../auth/popup/constants/auth-extension-route.constant"; import { fido2AuthGuard } from "../auth/popup/guards/fido2-auth.guard"; +import { platformPopoutGuard } from "../auth/popup/guards/platform-popout.guard"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; import { ExtensionDeviceManagementComponent } from "../auth/popup/settings/extension-device-management.component"; import { Fido2Component } from "../autofill/popup/fido2/fido2.component"; @@ -414,7 +415,7 @@ const routes: Routes = [ }, { path: AuthRoute.LoginWithPasskey, - canActivate: [unauthGuardFn(unauthRouteOverrides)], + canActivate: [unauthGuardFn(unauthRouteOverrides), platformPopoutGuard(["linux"])], data: { pageIcon: TwoFactorAuthSecurityKeyIcon, pageTitle: { diff --git a/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts b/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts index 764d9fe7733..b4d856309ed 100644 --- a/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts +++ b/libs/angular/src/auth/login-via-webauthn/login-via-webauthn.component.ts @@ -2,7 +2,7 @@ // @ts-strict-ignore import { CommonModule } from "@angular/common"; import { Component, OnInit } from "@angular/core"; -import { Router, RouterModule } from "@angular/router"; +import { ActivatedRoute, Router, RouterModule } from "@angular/router"; import { firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; @@ -19,6 +19,7 @@ import { ClientType } from "@bitwarden/common/enums"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; 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 { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { @@ -49,6 +50,7 @@ export type State = "assert" | "assertFailed"; }) export class LoginViaWebAuthnComponent implements OnInit { protected currentState: State = "assert"; + private shouldAutoClosePopout = false; protected readonly Icons = { TwoFactorAuthSecurityKeyIcon, @@ -70,6 +72,7 @@ export class LoginViaWebAuthnComponent implements OnInit { constructor( private webAuthnLoginService: WebAuthnLoginServiceAbstraction, private router: Router, + private route: ActivatedRoute, private logService: LogService, private validationService: ValidationService, private i18nService: I18nService, @@ -77,9 +80,14 @@ export class LoginViaWebAuthnComponent implements OnInit { private keyService: KeyService, private platformUtilsService: PlatformUtilsService, private anonLayoutWrapperDataService: AnonLayoutWrapperDataService, + private messagingService: MessagingService, ) {} ngOnInit(): void { + // Check if we should auto-close the popout after successful authentication + this.shouldAutoClosePopout = + this.route.snapshot.queryParamMap.get("autoClosePopout") === "true"; + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // eslint-disable-next-line @typescript-eslint/no-floating-promises this.authenticate(); @@ -123,6 +131,17 @@ export class LoginViaWebAuthnComponent implements OnInit { await this.loginSuccessHandlerService.run(authResult.userId, null); } + // If autoClosePopout is enabled and we're in a browser extension, + // re-open the regular popup and close this popout window + if ( + this.shouldAutoClosePopout && + this.platformUtilsService.getClientType() === ClientType.Browser + ) { + this.messagingService.send("openPopup"); + window.close(); + return; + } + await this.router.navigate([this.successRoute]); } catch (error) { if (error instanceof ErrorResponse) { From 04d7744747e64e06feff308c2483152abe709238 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Wed, 3 Dec 2025 15:12:12 -0500 Subject: [PATCH 13/89] normalize lowercasing for cipher compared against lowercased input value (#17803) --- apps/browser/src/autofill/background/notification.background.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 547c5ba1575..17e3ec159c3 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -658,7 +658,7 @@ export default class NotificationBackground { if ( username !== null && newPassword === null && - cipher.login.username === normalizedUsername && + cipher.login.username.toLowerCase() === normalizedUsername && cipher.login.password === currentPassword ) { // Assumed to be a login From dab1a37bfe4b3a51aa7426533fa52795b2371474 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:19:26 -0600 Subject: [PATCH 14/89] PM-24535 Web premium upgrade path for archive (#16854) * add premium badge to web filter when the user does not have access to premium * remove feature flag pass through in favor of showing/hiding archive vault observable * refactor archive observable to be more generic * add archive premium badge for the web * show premium badge inline for archive filter * show premium subscription ended message when user has archived ciphers * fix missing refactor * remove unneeded can archive check * reference observable directly * reduce the number of firstValueFroms by combining observables into a single stream * fix failing tests * add import to storybook * update variable naming for premium filters * pass event to `promptForPremium` * remove check for organization * fix footer variable reference * refactor back to `hasArchiveFlagEnabled$` - more straight forward to the underlying logic * update archive service test with new feature flag format --- .../item-more-options.component.spec.ts | 2 +- .../item-more-options.component.ts | 2 +- .../settings/vault-settings-v2.component.ts | 2 +- .../vault/app/vault/item-footer.component.ts | 2 +- .../vault-filter/vault-filter.component.ts | 3 + .../vault-cipher-row.component.html | 20 +++- .../vault-cipher-row.component.spec.ts | 1 + .../vault-items/vault-cipher-row.component.ts | 18 +++- .../vault-items/vault-items.component.html | 1 + .../vault-items/vault-items.component.spec.ts | 7 ++ .../vault-items/vault-items.component.ts | 4 + .../vault-items/vault-items.module.ts | 2 + .../vault-items/vault-items.stories.ts | 7 ++ .../components/vault-filter.component.ts | 34 ++++++- .../vault-filter-section.component.html | 3 + .../vault-filter-section.component.ts | 9 ++ .../models/vault-filter-section.type.ts | 10 ++ .../shared/vault-filter-shared.module.ts | 3 +- .../individual-vault/vault.component.html | 10 ++ .../vault/individual-vault/vault.component.ts | 36 ++++--- apps/web/src/locales/en/messages.json | 9 ++ .../components/vault-filter.component.ts | 2 +- .../abstractions/cipher-archive.service.ts | 5 +- .../default-cipher-archive.service.spec.ts | 95 ++++++++++++++++++- .../default-cipher-archive.service.ts | 37 ++++---- 25 files changed, 265 insertions(+), 59 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts index 577b7d96771..b9f48b7407b 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.spec.ts @@ -108,7 +108,7 @@ describe("ItemMoreOptionsComponent", () => { { provide: RestrictedItemTypesService, useValue: { restricted$: of([]) } }, { provide: CipherArchiveService, - useValue: { userCanArchive$: () => of(true), hasArchiveFlagEnabled$: () => of(true) }, + useValue: { userCanArchive$: () => of(true), hasArchiveFlagEnabled$: of(true) }, }, { provide: ToastService, useValue: { showToast: () => {} } }, { provide: Router, useValue: { navigate: () => Promise.resolve(true) } }, diff --git a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts index 4dfaf7bc66f..b65acc6ca8e 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/item-more-options/item-more-options.component.ts @@ -141,7 +141,7 @@ export class ItemMoreOptionsComponent { }), ); - protected showArchive$: Observable = this.cipherArchiveService.hasArchiveFlagEnabled$(); + protected showArchive$: Observable = this.cipherArchiveService.hasArchiveFlagEnabled$; protected canArchive$: Observable = this.accountService.activeAccount$.pipe( getUserId, diff --git a/apps/browser/src/vault/popup/settings/vault-settings-v2.component.ts b/apps/browser/src/vault/popup/settings/vault-settings-v2.component.ts index c6db820c232..e085cb21c2d 100644 --- a/apps/browser/src/vault/popup/settings/vault-settings-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/vault-settings-v2.component.ts @@ -49,7 +49,7 @@ export class VaultSettingsV2Component implements OnInit, OnDestroy { this.userId$.pipe(switchMap((userId) => this.cipherArchiveService.userCanArchive$(userId))), ); - protected readonly showArchiveItem = toSignal(this.cipherArchiveService.hasArchiveFlagEnabled$()); + protected readonly showArchiveItem = toSignal(this.cipherArchiveService.hasArchiveFlagEnabled$); protected readonly userHasArchivedItems = toSignal( this.userId$.pipe( diff --git a/apps/desktop/src/vault/app/vault/item-footer.component.ts b/apps/desktop/src/vault/app/vault/item-footer.component.ts index 0034bd9a43c..0ac12c928f2 100644 --- a/apps/desktop/src/vault/app/vault/item-footer.component.ts +++ b/apps/desktop/src/vault/app/vault/item-footer.component.ts @@ -225,7 +225,7 @@ export class ItemFooterComponent implements OnInit, OnChanges { switchMap((id) => combineLatest([ this.cipherArchiveService.userCanArchive$(id), - this.cipherArchiveService.hasArchiveFlagEnabled$(), + this.cipherArchiveService.hasArchiveFlagEnabled$, ]), ), ), diff --git a/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.component.ts index 01e61f0ab28..a253bb87c50 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault-filter/vault-filter.component.ts @@ -11,6 +11,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { DialogService, ToastService } from "@bitwarden/components"; @@ -59,6 +60,7 @@ export class VaultFilterComponent protected restrictedItemTypesService: RestrictedItemTypesService, protected cipherService: CipherService, protected cipherArchiveService: CipherArchiveService, + premiumUpgradePromptService: PremiumUpgradePromptService, ) { super( vaultFilterService, @@ -72,6 +74,7 @@ export class VaultFilterComponent restrictedItemTypesService, cipherService, cipherArchiveService, + premiumUpgradePromptService, ); } diff --git a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html index c8732154ef4..d56c9d15cff 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html +++ b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html @@ -203,10 +203,22 @@ {{ "eventLogs" | i18n }} @if (showArchiveButton) { - + @if (userCanArchive) { + + } + @if (!userCanArchive) { + + } } @if (showUnArchiveButton) { diff --git a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.spec.ts b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.spec.ts index d5f7b54f37a..9378ee54e51 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.spec.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.spec.ts @@ -72,6 +72,7 @@ describe("VaultCipherRowComponent", () => { fixture = TestBed.createComponent(VaultCipherRowComponent); component = fixture.componentInstance; + fixture.componentRef.setInput("archiveEnabled", false); overlayContainer = TestBed.inject(OverlayContainer); }); diff --git a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.ts b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.ts index 4ea062db8d1..92c49ac218a 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.ts @@ -8,6 +8,7 @@ import { OnInit, Output, ViewChild, + input, } from "@angular/core"; import { CollectionView } from "@bitwarden/admin-console/common"; @@ -101,8 +102,10 @@ export class VaultCipherRowComponent implements OnInit // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals // eslint-disable-next-line @angular-eslint/prefer-signals @Input() userCanArchive: boolean; + /** Archive feature is enabled */ + readonly archiveEnabled = input.required(); /** - * Enforge Org Data Ownership Policy Status + * Enforce Org Data Ownership Policy Status */ // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals // eslint-disable-next-line @angular-eslint/prefer-signals @@ -142,16 +145,21 @@ export class VaultCipherRowComponent implements OnInit } protected get showArchiveButton() { + if (!this.archiveEnabled()) { + return false; + } + return ( - this.userCanArchive && - !CipherViewLikeUtils.isArchived(this.cipher) && - !CipherViewLikeUtils.isDeleted(this.cipher) && - !this.cipher.organizationId + !CipherViewLikeUtils.isArchived(this.cipher) && !CipherViewLikeUtils.isDeleted(this.cipher) ); } // If item is archived always show unarchive button, even if user is not premium protected get showUnArchiveButton() { + if (!this.archiveEnabled()) { + return false; + } + return CipherViewLikeUtils.isArchived(this.cipher); } diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.html b/apps/web/src/app/vault/components/vault-items/vault-items.component.html index cb2af9a64e5..70c44e80a39 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.html +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.html @@ -179,6 +179,7 @@ (onEvent)="event($event)" [userCanArchive]="userCanArchive" [enforceOrgDataOwnershipPolicy]="enforceOrgDataOwnershipPolicy" + [archiveEnabled]="archiveFeatureEnabled$ | async" > diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts b/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts index 902fc2eb5a2..1eccb4c49ce 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.spec.ts @@ -4,6 +4,7 @@ import { of } from "rxjs"; import { CollectionView } from "@bitwarden/admin-console/common"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; @@ -54,6 +55,12 @@ describe("VaultItemsComponent", () => { t: (key: string) => key, }, }, + { + provide: CipherArchiveService, + useValue: { + hasArchiveFlagEnabled$: of(true), + }, + }, ], }); diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.ts b/apps/web/src/app/vault/components/vault-items/vault-items.component.ts index 3ab643927f1..a935314eb3a 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.ts @@ -7,6 +7,7 @@ import { Observable, combineLatest, map, of, startWith, switchMap } from "rxjs"; import { CollectionView, Unassigned, CollectionAdminView } from "@bitwarden/admin-console/common"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; import { RestrictedCipherType, @@ -145,9 +146,12 @@ export class VaultItemsComponent { protected disableMenu$: Observable; private restrictedTypes: RestrictedCipherType[] = []; + protected archiveFeatureEnabled$ = this.cipherArchiveService.hasArchiveFlagEnabled$; + constructor( protected cipherAuthorizationService: CipherAuthorizationService, protected restrictedItemTypesService: RestrictedItemTypesService, + protected cipherArchiveService: CipherArchiveService, ) { this.canDeleteSelected$ = this.selection.changed.pipe( startWith(null), diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.module.ts b/apps/web/src/app/vault/components/vault-items/vault-items.module.ts index a3a92559878..a7c264114b9 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.module.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.module.ts @@ -3,6 +3,7 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; +import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge"; import { ScrollLayoutDirective, TableModule } from "@bitwarden/components"; import { CopyCipherFieldDirective } from "@bitwarden/vault"; @@ -29,6 +30,7 @@ import { VaultItemsComponent } from "./vault-items.component"; PipesModule, CopyCipherFieldDirective, ScrollLayoutDirective, + PremiumBadgeComponent, ], declarations: [VaultItemsComponent, VaultCipherRowComponent, VaultCollectionRowComponent], exports: [VaultItemsComponent], diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts index 043ae900b40..d973fbcbbc7 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts @@ -30,6 +30,7 @@ import { import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; +import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; @@ -143,6 +144,12 @@ export default { isCipherRestricted: () => false, // No restrictions for this story }, }, + { + provide: CipherArchiveService, + useValue: { + hasArchiveFlagEnabled$: of(true), + }, + }, ], }), applicationConfig({ diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts index e40a32dc8b9..8839fa5039d 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/vault-filter.component.ts @@ -19,8 +19,10 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { UserId } from "@bitwarden/common/types/guid"; import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; @@ -170,6 +172,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy { protected restrictedItemTypesService: RestrictedItemTypesService, protected cipherService: CipherService, protected cipherArchiveService: CipherArchiveService, + private premiumUpgradePromptService: PremiumUpgradePromptService, ) {} async ngOnInit(): Promise { @@ -252,14 +255,20 @@ export class VaultFilterComponent implements OnInit, OnDestroy { }; async buildAllFilters(): Promise { - const hasArchiveFlag = await firstValueFrom(this.cipherArchiveService.hasArchiveFlagEnabled$()); + const [userId, showArchive] = await firstValueFrom( + combineLatest([ + this.accountService.activeAccount$.pipe(getUserId), + this.cipherArchiveService.hasArchiveFlagEnabled$, + ]), + ); + const builderFilter = {} as VaultFilterList; builderFilter.organizationFilter = await this.addOrganizationFilter(); builderFilter.typeFilter = await this.addTypeFilter(); builderFilter.folderFilter = await this.addFolderFilter(); builderFilter.collectionFilter = await this.addCollectionFilter(); - if (hasArchiveFlag) { - builderFilter.archiveFilter = await this.addArchiveFilter(); + if (showArchive) { + builderFilter.archiveFilter = await this.addArchiveFilter(userId); } builderFilter.trashFilter = await this.addTrashFilter(); return builderFilter; @@ -419,7 +428,18 @@ export class VaultFilterComponent implements OnInit, OnDestroy { return trashFilterSection; } - protected async addArchiveFilter(): Promise { + protected async addArchiveFilter(userId: UserId): Promise { + const [hasArchivedCiphers, userHasPremium] = await firstValueFrom( + combineLatest([ + this.cipherArchiveService + .archivedCiphers$(userId) + .pipe(map((archivedCiphers) => archivedCiphers.length > 0)), + this.cipherArchiveService.userHasPremium$(userId), + ]), + ); + + const promptForPremiumOnFilter = !userHasPremium && !hasArchivedCiphers; + const archiveFilterSection: VaultFilterSection = { data$: this.vaultFilterService.buildTypeTree( { @@ -442,6 +462,12 @@ export class VaultFilterComponent implements OnInit, OnDestroy { isSelectable: true, }, action: this.applyTypeFilter as (filterNode: TreeNode) => Promise, + premiumOptions: { + showBadgeForNonPremium: true, + blockFilterAction: promptForPremiumOnFilter + ? async () => await this.premiumUpgradePromptService.promptForPremium() + : undefined, + }, }; return archiveFilterSection; } diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.html b/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.html index f7078d2a67a..66f14dcf2f6 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.html +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/components/vault-filter-section.component.html @@ -105,6 +105,9 @@ *ngComponentOutlet="optionsInfo.component; injector: createInjector(f.node)" > + + +
    ) { + if (this.section?.premiumOptions?.blockFilterAction) { + await this.section.premiumOptions.blockFilterAction(); + return; + } + await this.section?.action(filterNode); } @@ -123,6 +128,10 @@ export class VaultFilterSectionComponent implements OnInit, OnDestroy { return this.section?.options; } + get premiumFeature() { + return this.section?.premiumOptions?.showBadgeForNonPremium; + } + get divider() { return this.section?.divider; } diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts index f1e6222b57a..d275b1251e9 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter-section.type.ts @@ -47,6 +47,16 @@ export type VaultFilterSection = { component: any; }; divider?: boolean; + premiumOptions?: { + /** When true, the premium badge will show on the filter for non-premium users. */ + showBadgeForNonPremium?: true; + /** + * Action to be called instead of applying the filter. + * Useful when the user does not have access to a filter (e.g., premium feature) + * and custom behavior is needed when invoking the filter. + */ + blockFilterAction?: () => Promise; + }; }; export type VaultFilterList = { diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/vault-filter-shared.module.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/vault-filter-shared.module.ts index c8becac8ef5..190ace6db63 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/vault-filter-shared.module.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/vault-filter-shared.module.ts @@ -1,5 +1,6 @@ import { NgModule } from "@angular/core"; +import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge"; import { SearchModule } from "@bitwarden/components"; import { SharedModule } from "../../../../shared"; @@ -7,7 +8,7 @@ import { SharedModule } from "../../../../shared"; import { VaultFilterSectionComponent } from "./components/vault-filter-section.component"; @NgModule({ - imports: [SharedModule, SearchModule], + imports: [SharedModule, SearchModule, PremiumBadgeComponent], declarations: [VaultFilterSectionComponent], exports: [SharedModule, VaultFilterSectionComponent, SearchModule], }) diff --git a/apps/web/src/app/vault/individual-vault/vault.component.html b/apps/web/src/app/vault/individual-vault/vault.component.html index 711a34413b5..522b63c21fd 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.html +++ b/apps/web/src/app/vault/individual-vault/vault.component.html @@ -34,6 +34,16 @@ {{ trashCleanupWarning }} + +

    {{ "premiumSubscriptionEndedDesc" | i18n }}

    + {{ + "restartPremium" | i18n + }} +
    ; VaultItemsModule, SharedModule, OrganizationWarningsModule, + BannerComponent, ], providers: [ RoutedVaultFilterService, @@ -230,13 +231,6 @@ export class VaultComponent implements OnInit, OnDestr .pipe(map((a) => a?.id)) .pipe(switchMap((id) => this.organizationService.organizations$(id))); - protected userCanArchive$ = this.accountService.activeAccount$.pipe( - getUserId, - switchMap((userId) => { - return this.cipherArchiveService.userCanArchive$(userId); - }), - ); - emptyState$ = combineLatest([ this.currentSearchText$, this.routedVaultFilterService.filter$, @@ -295,14 +289,28 @@ export class VaultComponent implements OnInit, OnDestr }), ); - protected enforceOrgDataOwnershipPolicy$ = this.accountService.activeAccount$.pipe( - getUserId, + private userId$ = this.accountService.activeAccount$.pipe(getUserId); + + protected enforceOrgDataOwnershipPolicy$ = this.userId$.pipe( switchMap((userId) => this.policyService.policyAppliesToUser$(PolicyType.OrganizationDataOwnership, userId), ), ); - private userId$ = this.accountService.activeAccount$.pipe(getUserId); + protected userCanArchive$ = this.userId$.pipe( + switchMap((userId) => { + return this.cipherArchiveService.userCanArchive$(userId); + }), + ); + + protected showSubscriptionEndedMessaging$ = this.userId$.pipe( + switchMap((userId) => + combineLatest([ + this.routedVaultFilterBridgeService.activeFilter$, + this.cipherArchiveService.showSubscriptionEndedMessaging$(userId), + ]).pipe(map(([activeFilter, showMessaging]) => activeFilter.isArchived && showMessaging)), + ), + ); constructor( private syncService: SyncService, @@ -438,13 +446,13 @@ export class VaultComponent implements OnInit, OnDestr allowedCiphers$, filter$, this.currentSearchText$, - this.cipherArchiveService.hasArchiveFlagEnabled$(), + this.cipherArchiveService.hasArchiveFlagEnabled$, ]).pipe( filter(([ciphers, filter]) => ciphers != undefined && filter != undefined), - concatMap(async ([ciphers, filter, searchText, archiveEnabled]) => { + concatMap(async ([ciphers, filter, searchText, showArchiveVault]) => { const failedCiphers = (await firstValueFrom(this.cipherService.failedToDecryptCiphers$(activeUserId))) ?? []; - const filterFunction = createFilterFunction(filter, archiveEnabled); + const filterFunction = createFilterFunction(filter, showArchiveVault); // Append any failed to decrypt ciphers to the top of the cipher list const allCiphers = [...failedCiphers, ...ciphers]; diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 19eec245885..4ed0ac639b0 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3133,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, diff --git a/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts b/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts index 659db1bb925..f664cff2e8d 100644 --- a/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts +++ b/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts @@ -89,7 +89,7 @@ export class VaultFilterComponent implements OnInit { this.collections = await this.initCollections(); this.showArchiveVaultFilter = await firstValueFrom( - this.cipherArchiveService.hasArchiveFlagEnabled$(), + this.cipherArchiveService.hasArchiveFlagEnabled$, ); this.isLoaded = true; diff --git a/libs/common/src/vault/abstractions/cipher-archive.service.ts b/libs/common/src/vault/abstractions/cipher-archive.service.ts index d33fc5e7cc7..0969b7de1ac 100644 --- a/libs/common/src/vault/abstractions/cipher-archive.service.ts +++ b/libs/common/src/vault/abstractions/cipher-archive.service.ts @@ -4,10 +4,11 @@ import { CipherId, UserId } from "@bitwarden/common/types/guid"; import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils"; export abstract class CipherArchiveService { - abstract hasArchiveFlagEnabled$(): Observable; + abstract hasArchiveFlagEnabled$: Observable; abstract archivedCiphers$(userId: UserId): Observable; abstract userCanArchive$(userId: UserId): Observable; - abstract showArchiveVault$(userId: UserId): Observable; + abstract userHasPremium$(userId: UserId): Observable; abstract archiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise; abstract unarchiveWithServer(ids: CipherId | CipherId[], userId: UserId): Promise; + abstract showSubscriptionEndedMessaging$(userId: UserId): Observable; } diff --git a/libs/common/src/vault/services/default-cipher-archive.service.spec.ts b/libs/common/src/vault/services/default-cipher-archive.service.spec.ts index 972b04d2c4e..807311ca851 100644 --- a/libs/common/src/vault/services/default-cipher-archive.service.spec.ts +++ b/libs/common/src/vault/services/default-cipher-archive.service.spec.ts @@ -1,5 +1,5 @@ import { mock } from "jest-mock-extended"; -import { of, firstValueFrom } from "rxjs"; +import { of, firstValueFrom, BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; @@ -24,12 +24,14 @@ describe("DefaultCipherArchiveService", () => { const userId = "user-id" as UserId; const cipherId = "123" as CipherId; + const featureFlag = new BehaviorSubject(true); beforeEach(() => { mockCipherService = mock(); mockApiService = mock(); mockBillingAccountProfileStateService = mock(); mockConfigService = mock(); + mockConfigService.getFeatureFlag$.mockReturnValue(featureFlag.asObservable()); service = new DefaultCipherArchiveService( mockCipherService, @@ -86,7 +88,7 @@ describe("DefaultCipherArchiveService", () => { describe("userCanArchive$", () => { it("should return true when user has premium and feature flag is enabled", async () => { mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(true)); - mockConfigService.getFeatureFlag$.mockReturnValue(of(true)); + featureFlag.next(true); const result = await firstValueFrom(service.userCanArchive$(userId)); @@ -101,7 +103,7 @@ describe("DefaultCipherArchiveService", () => { it("should return false when feature flag is disabled", async () => { mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(false)); - mockConfigService.getFeatureFlag$.mockReturnValue(of(false)); + featureFlag.next(false); const result = await firstValueFrom(service.userCanArchive$(userId)); @@ -109,6 +111,93 @@ describe("DefaultCipherArchiveService", () => { }); }); + describe("hasArchiveFlagEnabled$", () => { + it("returns true when feature flag is enabled", async () => { + featureFlag.next(true); + + const result = await firstValueFrom(service.hasArchiveFlagEnabled$); + + expect(result).toBe(true); + expect(mockConfigService.getFeatureFlag$).toHaveBeenCalledWith( + FeatureFlag.PM19148_InnovationArchive, + ); + }); + + it("returns false when feature flag is disabled", async () => { + featureFlag.next(false); + + const result = await firstValueFrom(service.hasArchiveFlagEnabled$); + + expect(result).toBe(false); + }); + }); + + describe("userHasPremium$", () => { + it("returns true when user has premium", async () => { + mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(true)); + + const result = await firstValueFrom(service.userHasPremium$(userId)); + + expect(result).toBe(true); + expect(mockBillingAccountProfileStateService.hasPremiumFromAnySource$).toHaveBeenCalledWith( + userId, + ); + }); + + it("returns false when user does not have premium", async () => { + mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(false)); + + const result = await firstValueFrom(service.userHasPremium$(userId)); + + expect(result).toBe(false); + }); + }); + + describe("showSubscriptionEndedMessaging$", () => { + it("returns true when user has archived ciphers but no premium", async () => { + const mockCiphers: CipherListView[] = [ + { + id: "1", + archivedDate: "2024-01-15T10:30:00.000Z", + type: "identity", + } as unknown as CipherListView, + ]; + + mockCipherService.cipherListViews$.mockReturnValue(of(mockCiphers)); + mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(false)); + + const result = await firstValueFrom(service.showSubscriptionEndedMessaging$(userId)); + + expect(result).toBe(true); + }); + + it("returns false when user has archived ciphers and has premium", async () => { + const mockCiphers: CipherListView[] = [ + { + id: "1", + archivedDate: "2024-01-15T10:30:00.000Z", + type: "identity", + } as unknown as CipherListView, + ]; + + mockCipherService.cipherListViews$.mockReturnValue(of(mockCiphers)); + mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(true)); + + const result = await firstValueFrom(service.showSubscriptionEndedMessaging$(userId)); + + expect(result).toBe(false); + }); + + it("returns false when user has no archived ciphers and no premium", async () => { + mockCipherService.cipherListViews$.mockReturnValue(of([])); + mockBillingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(false)); + + const result = await firstValueFrom(service.showSubscriptionEndedMessaging$(userId)); + + expect(result).toBe(false); + }); + }); + describe("archiveWithServer", () => { const mockResponse = { data: [ diff --git a/libs/common/src/vault/services/default-cipher-archive.service.ts b/libs/common/src/vault/services/default-cipher-archive.service.ts index a56a22474a3..8076735c9e2 100644 --- a/libs/common/src/vault/services/default-cipher-archive.service.ts +++ b/libs/common/src/vault/services/default-cipher-archive.service.ts @@ -27,10 +27,6 @@ export class DefaultCipherArchiveService implements CipherArchiveService { private configService: ConfigService, ) {} - hasArchiveFlagEnabled$(): Observable { - return this.configService.getFeatureFlag$(FeatureFlag.PM19148_InnovationArchive); - } - /** * Observable that contains the list of ciphers that have been archived. */ @@ -61,23 +57,22 @@ export class DefaultCipherArchiveService implements CipherArchiveService { ); } - /** - * User can access the archive vault if: - * Feature Flag is enabled - * There is at least one archived item - * ///////////// NOTE ///////////// - * This is separated from userCanArchive because a user that loses premium status, but has archived items, - * should still be able to access their archive vault. The items will be read-only, and can be restored. - */ - showArchiveVault$(userId: UserId): Observable { - return combineLatest([ - this.configService.getFeatureFlag$(FeatureFlag.PM19148_InnovationArchive), - this.archivedCiphers$(userId), - ]).pipe( - map( - ([archiveFlagEnabled, hasArchivedItems]) => - archiveFlagEnabled && hasArchivedItems.length > 0, - ), + /** Returns true when the archive features should be shown. */ + hasArchiveFlagEnabled$: Observable = this.configService + .getFeatureFlag$(FeatureFlag.PM19148_InnovationArchive) + .pipe(shareReplay({ refCount: true, bufferSize: 1 })); + + /** Returns true when the user has premium from any means. */ + userHasPremium$(userId: UserId): Observable { + return this.billingAccountProfileStateService + .hasPremiumFromAnySource$(userId) + .pipe(shareReplay({ refCount: true, bufferSize: 1 })); + } + + /** Returns true when the user has previously archived ciphers but lost their premium membership. */ + showSubscriptionEndedMessaging$(userId: UserId): Observable { + return combineLatest([this.archivedCiphers$(userId), this.userHasPremium$(userId)]).pipe( + map(([archivedCiphers, hasPremium]) => archivedCiphers.length > 0 && !hasPremium), shareReplay({ refCount: true, bufferSize: 1 }), ); } From d581f06b321d5217130cfdfca99684b2fdc0f896 Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Wed, 3 Dec 2025 17:23:17 -0500 Subject: [PATCH 15/89] refactor(IdentityTokenResponse): [Auth/PM-3537] Remove deprecated KeyConnectorUrl from of IdentityTokenResponse + misc TDE cleanup (#17593) * PM-3537 - Remove KeyConnectorUrl from IdentityTokenResponse and clean up other flagged behavior * PM-3537 - SSO Login Strategy tests - remove key connector url * PM-3537 - Update LoginStrategyService tests to pass --- .../login-strategies/login.strategy.spec.ts | 2 +- .../common/login-strategies/login.strategy.ts | 2 +- .../sso-login.strategy.spec.ts | 61 ------------------- .../login-strategies/sso-login.strategy.ts | 12 +--- .../models/domain/user-decryption-options.ts | 21 +++---- .../login-strategy.service.spec.ts | 4 ++ .../response/identity-token.response.ts | 3 +- 7 files changed, 15 insertions(+), 90 deletions(-) diff --git a/libs/auth/src/common/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts index ceb36a44633..82e1183a1d6 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -259,7 +259,7 @@ describe("LoginStrategy", () => { expect(userDecryptionOptionsService.setUserDecryptionOptionsById).toHaveBeenCalledWith( userId, - UserDecryptionOptions.fromResponse(idTokenResponse), + UserDecryptionOptions.fromIdentityTokenResponse(idTokenResponse), ); expect(masterPasswordService.mock.setMasterPasswordUnlockData).toHaveBeenCalledWith( new MasterPasswordUnlockData( diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index 2e3c41da900..08d5ae6246f 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -199,7 +199,7 @@ export abstract class LoginStrategy { // as the user decryption options help determine the available timeout actions. await this.userDecryptionOptionsService.setUserDecryptionOptionsById( userId, - UserDecryptionOptions.fromResponse(tokenResponse), + UserDecryptionOptions.fromIdentityTokenResponse(tokenResponse), ); if (tokenResponse.userDecryptionOptions?.masterPasswordUnlock != null) { diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index acbb680ae6d..3dbce6500a8 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -503,67 +503,6 @@ describe("SsoLoginStrategy", () => { HasMasterPassword: false, KeyConnectorOption: { KeyConnectorUrl: keyConnectorUrl }, }); - tokenResponse.keyConnectorUrl = keyConnectorUrl; - }); - - it("gets and sets the master key if Key Connector is enabled and the user doesn't have a master password", async () => { - const masterKey = new SymmetricCryptoKey( - new Uint8Array(64).buffer as CsprngArray, - ) as MasterKey; - - apiService.postIdentityToken.mockResolvedValue(tokenResponse); - masterPasswordService.masterKeySubject.next(masterKey); - - await ssoLoginStrategy.logIn(credentials); - - expect(keyConnectorService.setMasterKeyFromUrl).toHaveBeenCalledWith(keyConnectorUrl, userId); - }); - - it("converts new SSO user with no master password to Key Connector on first login", async () => { - tokenResponse.key = undefined; - tokenResponse.kdfConfig = new Argon2KdfConfig(10, 64, 4); - - apiService.postIdentityToken.mockResolvedValue(tokenResponse); - - await ssoLoginStrategy.logIn(credentials); - - expect(keyConnectorService.setNewSsoUserKeyConnectorConversionData).toHaveBeenCalledWith( - { - kdfConfig: new Argon2KdfConfig(10, 64, 4), - keyConnectorUrl: keyConnectorUrl, - organizationId: ssoOrgId, - }, - userId, - ); - }); - - it("decrypts and sets the user key if Key Connector is enabled and the user doesn't have a master password", async () => { - const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey; - const masterKey = new SymmetricCryptoKey( - new Uint8Array(64).buffer as CsprngArray, - ) as MasterKey; - - apiService.postIdentityToken.mockResolvedValue(tokenResponse); - masterPasswordService.masterKeySubject.next(masterKey); - masterPasswordService.mock.decryptUserKeyWithMasterKey.mockResolvedValue(userKey); - - await ssoLoginStrategy.logIn(credentials); - - expect(masterPasswordService.mock.decryptUserKeyWithMasterKey).toHaveBeenCalledWith( - masterKey, - userId, - undefined, - ); - expect(keyService.setUserKey).toHaveBeenCalledWith(userKey, userId); - }); - }); - - describe("Key Connector Pre-TDE", () => { - let tokenResponse: IdentityTokenResponse; - beforeEach(() => { - tokenResponse = identityTokenResponseFactory(); - tokenResponse.userDecryptionOptions = null; - tokenResponse.keyConnectorUrl = keyConnectorUrl; }); it("gets and sets the master key if Key Connector is enabled and the user doesn't have a master password", async () => { diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index d806f6d733e..33802765aca 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -157,22 +157,12 @@ export class SsoLoginStrategy extends LoginStrategy { // In order for us to set the master key from Key Connector, we need to have a Key Connector URL // and the user must not have a master password. return userHasKeyConnectorUrl && !userHasMasterPassword; - } else { - // In pre-TDE versions of the server, the userDecryptionOptions will not be present. - // In this case, we can determine if the user has a master password and has a Key Connector URL by - // just checking the keyConnectorUrl property. This is because the server short-circuits on the response - // and will not pass back the URL in the response if the user has a master password. - // TODO: remove compatibility check after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3537) - return tokenResponse.keyConnectorUrl != null; } } private getKeyConnectorUrl(tokenResponse: IdentityTokenResponse): string { - // TODO: remove tokenResponse.keyConnectorUrl reference after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3537) const userDecryptionOptions = tokenResponse?.userDecryptionOptions; - return ( - tokenResponse.keyConnectorUrl ?? userDecryptionOptions?.keyConnectorOption?.keyConnectorUrl - ); + return userDecryptionOptions?.keyConnectorOption?.keyConnectorUrl; } // TODO: future passkey login strategy will need to support setting user key (decrypting via TDE or admin approval request) diff --git a/libs/auth/src/common/models/domain/user-decryption-options.ts b/libs/auth/src/common/models/domain/user-decryption-options.ts index 7653a3b77ff..44d8bff4d2c 100644 --- a/libs/auth/src/common/models/domain/user-decryption-options.ts +++ b/libs/auth/src/common/models/domain/user-decryption-options.ts @@ -112,10 +112,11 @@ export class UserDecryptionOptions { * @throws If the response is nullish, this method will throw an error. User decryption options * are required for client initialization. */ - // TODO: Change response type to `UserDecryptionOptionsResponse` after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3537) - static fromResponse(response: IdentityTokenResponse): UserDecryptionOptions { + static fromIdentityTokenResponse(response: IdentityTokenResponse): UserDecryptionOptions { if (response == null) { - throw new Error("User Decryption Options are required for client initialization."); + throw new Error( + "User Decryption Options are required for client initialization. Response is nullish.", + ); } const decryptionOptions = new UserDecryptionOptions(); @@ -134,17 +135,9 @@ export class UserDecryptionOptions { responseOptions.keyConnectorOption, ); } else { - // If the response does not have userDecryptionOptions, this means it's on a pre-TDE server version and so - // we must base our decryption options on the presence of the keyConnectorUrl. - // Note that the presence of keyConnectorUrl implies that the user does not have a master password, as in pre-TDE - // server versions, a master password short-circuited the addition of the keyConnectorUrl to the response. - // TODO: remove this check after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3537) - const usingKeyConnector = response.keyConnectorUrl != null; - decryptionOptions.hasMasterPassword = !usingKeyConnector; - if (usingKeyConnector) { - decryptionOptions.keyConnectorOption = new KeyConnectorUserDecryptionOption(); - decryptionOptions.keyConnectorOption.keyConnectorUrl = response.keyConnectorUrl; - } + throw new Error( + "User Decryption Options are required for client initialization. userDecryptionOptions is missing in response.", + ); } return decryptionOptions; } diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts index 831692c160f..20251e339a5 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts @@ -10,6 +10,7 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; import { PreloginResponse } from "@bitwarden/common/auth/models/response/prelogin.response"; +import { UserDecryptionOptionsResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; @@ -496,6 +497,7 @@ describe("LoginStrategyService", () => { refresh_token: "REFRESH_TOKEN", scope: "api offline_access", token_type: "Bearer", + userDecryptionOptions: new UserDecryptionOptionsResponse({ HasMasterPassword: true }), }), ); apiService.postPrelogin.mockResolvedValue( @@ -563,6 +565,7 @@ describe("LoginStrategyService", () => { refresh_token: "REFRESH_TOKEN", scope: "api offline_access", token_type: "Bearer", + userDecryptionOptions: new UserDecryptionOptionsResponse({ HasMasterPassword: true }), }), ); @@ -692,6 +695,7 @@ describe("LoginStrategyService", () => { refresh_token: "REFRESH_TOKEN", scope: "api offline_access", token_type: "Bearer", + userDecryptionOptions: new UserDecryptionOptionsResponse({ HasMasterPassword: true }), }), ); diff --git a/libs/common/src/auth/models/response/identity-token.response.ts b/libs/common/src/auth/models/response/identity-token.response.ts index dab96f6cf8c..59e7eb98ec2 100644 --- a/libs/common/src/auth/models/response/identity-token.response.ts +++ b/libs/common/src/auth/models/response/identity-token.response.ts @@ -26,7 +26,6 @@ export class IdentityTokenResponse extends BaseResponse { forcePasswordReset: boolean; masterPasswordPolicy: MasterPasswordPolicyResponse; apiUseKeyConnector: boolean; - keyConnectorUrl: string; userDecryptionOptions?: UserDecryptionOptionsResponse; @@ -70,7 +69,7 @@ export class IdentityTokenResponse extends BaseResponse { : new Argon2KdfConfig(kdfIterations, kdfMemory, kdfParallelism); this.forcePasswordReset = this.getResponseProperty("ForcePasswordReset"); this.apiUseKeyConnector = this.getResponseProperty("ApiUseKeyConnector"); - this.keyConnectorUrl = this.getResponseProperty("KeyConnectorUrl"); + this.masterPasswordPolicy = new MasterPasswordPolicyResponse( this.getResponseProperty("MasterPasswordPolicy"), ); From 77fe04f8c7812b857c4e3b24277f1f297c5626b4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:32:13 -0800 Subject: [PATCH 16/89] [deps] Vault: Update open to v11 (#17625) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- apps/cli/package.json | 2 +- package-lock.json | 83 ++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index d041f818c29..7e7ae62658c 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -83,7 +83,7 @@ "multer": "2.0.2", "node-fetch": "2.6.12", "node-forge": "1.3.2", - "open": "10.1.2", + "open": "11.0.0", "papaparse": "5.5.3", "proper-lockfile": "4.1.2", "rxjs": "7.8.1", diff --git a/package-lock.json b/package-lock.json index ea662c62b6e..4dfc6c644fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "node-fetch": "2.6.12", "node-forge": "1.3.2", "oidc-client-ts": "2.4.1", - "open": "10.1.2", + "open": "11.0.0", "papaparse": "5.5.3", "proper-lockfile": "4.1.2", "qrcode-parser": "2.1.3", @@ -219,7 +219,7 @@ "multer": "2.0.2", "node-fetch": "2.6.12", "node-forge": "1.3.2", - "open": "10.1.2", + "open": "11.0.0", "papaparse": "5.5.3", "proper-lockfile": "4.1.2", "rxjs": "7.8.1", @@ -19713,9 +19713,9 @@ } }, "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -24785,6 +24785,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", @@ -32477,18 +32489,36 @@ "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" }, "node_modules/open": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", - "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", "license": "MIT", "dependencies": { - "default-browser": "^5.2.1", + "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", - "is-wsl": "^3.1.0" + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" }, "engines": { - "node": ">=18" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/wsl-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.0.tgz", + "integrity": "sha512-3sFIGLiaDP7rTO4xh3g+b3AzhYDIUGGywE/WsmqzJWDxus5aJXVnPTNC/6L+r2WzrwXqVOdD262OaO+cEyPMSQ==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -34417,6 +34447,18 @@ "node": "^12.20.0 || >=14" } }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", @@ -41311,6 +41353,24 @@ "node": ">= 0.6" } }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/webpack-dev-server/node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", @@ -41895,7 +41955,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", - "dev": true, "license": "MIT", "dependencies": { "is-wsl": "^3.1.0" diff --git a/package.json b/package.json index ab83b981b66..e3e4be193b7 100644 --- a/package.json +++ b/package.json @@ -194,7 +194,7 @@ "node-fetch": "2.6.12", "node-forge": "1.3.2", "oidc-client-ts": "2.4.1", - "open": "10.1.2", + "open": "11.0.0", "papaparse": "5.5.3", "proper-lockfile": "4.1.2", "qrcode-parser": "2.1.3", From 433c0ced3277e8dcae7015d97ed351118b21ce8c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:27:49 -0800 Subject: [PATCH 17/89] [deps] Vault: Update koa to v3 (#17565) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- apps/cli/package.json | 2 +- package-lock.json | 204 ++++++++---------------------------------- package.json | 4 +- 3 files changed, 41 insertions(+), 169 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 7e7ae62658c..0ae4bf9ce30 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -75,7 +75,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.3", + "koa": "3.1.1", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lowdb": "1.0.0", diff --git a/package-lock.json b/package-lock.json index 4dfc6c644fc..381515007a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.3", + "koa": "3.1.1", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lit": "3.3.1", @@ -102,7 +102,7 @@ "@types/inquirer": "8.2.10", "@types/jest": "29.5.14", "@types/jsdom": "21.1.7", - "@types/koa": "3.0.0", + "@types/koa": "3.0.1", "@types/koa__multer": "2.0.7", "@types/koa__router": "12.0.4", "@types/koa-bodyparser": "4.3.7", @@ -211,7 +211,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.3", + "koa": "3.1.1", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lowdb": "1.0.0", @@ -13887,9 +13887,9 @@ } }, "node_modules/@types/koa": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/koa/-/koa-3.0.0.tgz", - "integrity": "sha512-MOcVYdVYmkSutVHZZPh8j3+dAjLyR5Tl59CN0eKgpkE1h/LBSmPAsQQuWs+bKu7WtGNn+hKfJH9Gzml+PulmDg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-3.0.1.tgz", + "integrity": "sha512-VkB6WJUQSe0zBpR+Q7/YIUESGp5wPHcaXr0xueU5W0EOUWtlSbblsl+Kl31lyRQ63nIILh0e/7gXjQ09JXJIHw==", "dev": true, "license": "MIT", "dependencies": { @@ -17675,40 +17675,6 @@ "dev": true, "license": "ISC" }, - "node_modules/cache-content-type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", - "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", - "license": "MIT", - "dependencies": { - "mime-types": "^2.1.18", - "ylru": "^1.2.0" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/cache-content-type/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cache-content-type/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -24759,6 +24725,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -24944,6 +24911,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -27483,37 +27451,32 @@ } }, "node_modules/koa": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.3.tgz", - "integrity": "sha512-zPPuIt+ku1iCpFBRwseMcPYQ1cJL8l60rSmKeOuGfOXyE6YnTBmf2aEFNL2HQGrD0cPcLO/t+v9RTgC+fwEh/g==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/koa/-/koa-3.1.1.tgz", + "integrity": "sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==", "license": "MIT", "dependencies": { - "accepts": "^1.3.5", - "cache-content-type": "^1.0.0", - "content-disposition": "~0.5.2", - "content-type": "^1.0.4", - "cookies": "~0.9.0", - "debug": "^4.3.2", + "accepts": "^1.3.8", + "content-disposition": "~0.5.4", + "content-type": "^1.0.5", + "cookies": "~0.9.1", "delegates": "^1.0.0", - "depd": "^2.0.0", - "destroy": "^1.0.4", - "encodeurl": "^1.0.2", + "destroy": "^1.2.0", + "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "fresh": "~0.5.2", - "http-assert": "^1.3.0", - "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", + "http-assert": "^1.5.0", + "http-errors": "^2.0.0", "koa-compose": "^4.1.0", - "koa-convert": "^2.0.0", - "on-finished": "^2.3.0", - "only": "~0.0.2", - "parseurl": "^1.3.2", - "statuses": "^1.5.0", - "type-is": "^1.6.16", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1", + "type-is": "^2.0.1", "vary": "^1.1.2" }, "engines": { - "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" + "node": ">= 18" } }, "node_modules/koa-bodyparser": { @@ -27579,19 +27542,6 @@ "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", "license": "MIT" }, - "node_modules/koa-convert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz", - "integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==", - "license": "MIT", - "dependencies": { - "co": "^4.6.0", - "koa-compose": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/koa-is-json": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", @@ -27621,6 +27571,18 @@ "node": ">= 0.6" } }, + "node_modules/koa/node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/koa/node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -27633,15 +27595,6 @@ "node": ">= 0.6" } }, - "node_modules/koa/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/koa/node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -27651,40 +27604,6 @@ "node": ">= 0.6" } }, - "node_modules/koa/node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "license": "MIT", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/koa/node_modules/http-errors/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/koa/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/koa/node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -27694,18 +27613,6 @@ "node": ">= 0.6" } }, - "node_modules/koa/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/koa/node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -27715,28 +27622,6 @@ "node": ">= 0.6" } }, - "node_modules/koa/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/koa/node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/launch-editor": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", @@ -32483,11 +32368,6 @@ "node": ">=6" } }, - "node_modules/only": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", - "integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==" - }, "node_modules/open": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", @@ -35987,6 +35867,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -42072,15 +41953,6 @@ "fd-slicer": "~1.1.0" } }, - "node_modules/ylru": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.4.0.tgz", - "integrity": "sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index e3e4be193b7..209bbc3beb1 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@types/inquirer": "8.2.10", "@types/jest": "29.5.14", "@types/jsdom": "21.1.7", - "@types/koa": "3.0.0", + "@types/koa": "3.0.1", "@types/koa__multer": "2.0.7", "@types/koa__router": "12.0.4", "@types/koa-bodyparser": "4.3.7", @@ -183,7 +183,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.3", + "koa": "3.1.1", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lit": "3.3.1", From 2ef84ca460e92db9cdd12f6079a215976d0b5ab1 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 4 Dec 2025 09:14:09 +0100 Subject: [PATCH 18/89] [PM-27230] Resolve sdk breaking changes; update account init and save signed public key (#17488) * Update account init and save signed public key * Update sdk * Fix build * Fix types * Fix test * Fix test --- .../user-key-rotation.service.spec.ts | 4 ++ .../key-rotation/user-key-rotation.service.ts | 27 +++++++--- libs/common/src/key-management/types.ts | 8 ++- .../services/key-state/user-key.state.ts | 11 +++- .../services/sdk/default-sdk.service.spec.ts | 1 + .../services/sdk/default-sdk.service.ts | 52 ++++++++++++++----- .../src/platform/sync/default-sync.service.ts | 4 ++ .../src/abstractions/key.service.ts | 6 ++- libs/key-management/src/key.service.ts | 11 +++- package-lock.json | 16 +++--- package.json | 4 +- 11 files changed, 110 insertions(+), 34 deletions(-) diff --git a/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts b/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts index b790fb8409a..f4b50b4a772 100644 --- a/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts +++ b/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts @@ -1096,6 +1096,9 @@ describe("KeyRotationService", () => { mockKeyService.userSigningKey$.mockReturnValue( new BehaviorSubject(TEST_VECTOR_SIGNING_KEY_V2 as WrappedSigningKey), ); + mockKeyService.userSignedPublicKey$.mockReturnValue( + new BehaviorSubject(TEST_VECTOR_SIGNED_PUBLIC_KEY_V2 as SignedPublicKey), + ); mockSecurityStateService.accountSecurityState$.mockReturnValue( new BehaviorSubject(TEST_VECTOR_SECURITY_STATE_V2 as SignedSecurityState), ); @@ -1140,6 +1143,7 @@ describe("KeyRotationService", () => { publicKeyEncryptionKeyPair: { wrappedPrivateKey: TEST_VECTOR_PRIVATE_KEY_V2, publicKey: Utils.fromB64ToArray(TEST_VECTOR_PUBLIC_KEY_V2) as UnsignedPublicKey, + signedPublicKey: TEST_VECTOR_SIGNED_PUBLIC_KEY_V2 as SignedPublicKey, }, signingKey: TEST_VECTOR_SIGNING_KEY_V2 as WrappedSigningKey, securityState: TEST_VECTOR_SECURITY_STATE_V2 as SignedSecurityState, diff --git a/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.ts b/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.ts index 168dbe7442e..b9bd23b12de 100644 --- a/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.ts +++ b/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.ts @@ -10,6 +10,7 @@ import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-st import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { SecurityStateService } from "@bitwarden/common/key-management/security-state/abstractions/security-state.service"; import { + SignedPublicKey, SignedSecurityState, UnsignedPublicKey, WrappedPrivateKey, @@ -308,9 +309,11 @@ export class UserKeyRotationService { userId: asUuid(userId), kdfParams: kdfConfig.toSdkConfig(), email: email, - privateKey: cryptographicStateParameters.publicKeyEncryptionKeyPair.wrappedPrivateKey, - signingKey: undefined, - securityState: undefined, + accountCryptographicState: { + V1: { + private_key: cryptographicStateParameters.publicKeyEncryptionKeyPair.wrappedPrivateKey, + }, + }, method: { decryptedKey: { decrypted_user_key: cryptographicStateParameters.userKey.toBase64() }, }, @@ -334,9 +337,15 @@ export class UserKeyRotationService { userId: asUuid(userId), kdfParams: kdfConfig.toSdkConfig(), email: email, - privateKey: cryptographicStateParameters.publicKeyEncryptionKeyPair.wrappedPrivateKey, - signingKey: cryptographicStateParameters.signingKey, - securityState: cryptographicStateParameters.securityState, + accountCryptographicState: { + V2: { + private_key: cryptographicStateParameters.publicKeyEncryptionKeyPair.wrappedPrivateKey, + signing_key: cryptographicStateParameters.signingKey, + security_state: cryptographicStateParameters.securityState, + signed_public_key: + cryptographicStateParameters.publicKeyEncryptionKeyPair.signedPublicKey, + }, + }, method: { decryptedKey: { decrypted_user_key: cryptographicStateParameters.userKey.toBase64() }, }, @@ -632,6 +641,10 @@ export class UserKeyRotationService { this.securityStateService.accountSecurityState$(user.id), "User security state", ); + const signedPublicKey = await this.firstValueFromOrThrow( + this.keyService.userSignedPublicKey$(user.id), + "User signed public key", + ); return { masterKeyKdfConfig, @@ -642,6 +655,7 @@ export class UserKeyRotationService { publicKeyEncryptionKeyPair: { wrappedPrivateKey: currentUserKeyWrappedPrivateKey, publicKey: publicKey, + signedPublicKey: signedPublicKey!, }, signingKey: signingKey!, securityState: securityState!, @@ -679,6 +693,7 @@ export type V2CryptographicStateParameters = { publicKeyEncryptionKeyPair: { wrappedPrivateKey: WrappedPrivateKey; publicKey: UnsignedPublicKey; + signedPublicKey: SignedPublicKey; }; signingKey: WrappedSigningKey; securityState: SignedSecurityState; diff --git a/libs/common/src/key-management/types.ts b/libs/common/src/key-management/types.ts index df64a3ed342..1c349e83a03 100644 --- a/libs/common/src/key-management/types.ts +++ b/libs/common/src/key-management/types.ts @@ -1,6 +1,10 @@ import { Opaque } from "type-fest"; -import { EncString, SignedSecurityState as SdkSignedSecurityState } from "@bitwarden/sdk-internal"; +import { + EncString, + SignedSecurityState as SdkSignedSecurityState, + SignedPublicKey as SdkSignedPublicKey, +} from "@bitwarden/sdk-internal"; /** * A private key, encrypted with a symmetric key. @@ -10,7 +14,7 @@ export type WrappedPrivateKey = Opaque; /** * A public key, signed with the accounts signature key. */ -export type SignedPublicKey = Opaque; +export type SignedPublicKey = Opaque; /** * A public key in base64 encoded SPKI-DER */ diff --git a/libs/common/src/platform/services/key-state/user-key.state.ts b/libs/common/src/platform/services/key-state/user-key.state.ts index 2416c211d6b..64577768c8d 100644 --- a/libs/common/src/platform/services/key-state/user-key.state.ts +++ b/libs/common/src/platform/services/key-state/user-key.state.ts @@ -1,5 +1,5 @@ import { EncryptedString } from "../../../key-management/crypto/models/enc-string"; -import { WrappedSigningKey } from "../../../key-management/types"; +import { SignedPublicKey, WrappedSigningKey } from "../../../key-management/types"; import { UserKey } from "../../../types/key"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; import { CRYPTO_DISK, CRYPTO_MEMORY, UserKeyDefinition } from "../../state"; @@ -35,3 +35,12 @@ export const USER_KEY_ENCRYPTED_SIGNING_KEY = new UserKeyDefinition( + CRYPTO_DISK, + "userSignedPublicKey", + { + deserializer: (obj) => obj, + clearOn: ["logout"], + }, +); diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts index dc945594079..1286ea7b7f9 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts @@ -105,6 +105,7 @@ describe("DefaultSdkService", () => { .mockReturnValue(of("private-key" as EncryptedString)); keyService.encryptedOrgKeys$.calledWith(userId).mockReturnValue(of({})); keyService.userSigningKey$.calledWith(userId).mockReturnValue(of(null)); + keyService.userSignedPublicKey$.calledWith(userId).mockReturnValue(of(null)); securityStateService.accountSecurityState$.calledWith(userId).mockReturnValue(of(null)); }); diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.ts b/libs/common/src/platform/services/sdk/default-sdk.service.ts index 6e7bcbb197d..5084f5f5f18 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.ts @@ -16,6 +16,7 @@ import { } from "rxjs"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { UserKey } from "@bitwarden/common/types/key"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { KeyService, KdfConfigService, KdfConfig, KdfType } from "@bitwarden/key-management"; @@ -24,15 +25,14 @@ import { ClientSettings, TokenProvider, UnsignedSharedKey, + WrappedAccountCryptographicState, } from "@bitwarden/sdk-internal"; import { ApiService } from "../../../abstractions/api.service"; import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service"; -import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; +import { EncString } from "../../../key-management/crypto/models/enc-string"; import { SecurityStateService } from "../../../key-management/security-state/abstractions/security-state.service"; -import { SignedSecurityState, WrappedSigningKey } from "../../../key-management/types"; import { OrganizationId, UserId } from "../../../types/guid"; -import { UserKey } from "../../../types/key"; import { Environment, EnvironmentService } from "../../abstractions/environment.service"; import { PlatformUtilsService } from "../../abstractions/platform-utils.service"; import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory"; @@ -174,6 +174,9 @@ export class DefaultSdkService implements SdkService { const securityState$ = this.securityStateService .accountSecurityState$(userId) .pipe(distinctUntilChanged(compareValues)); + const signedPublicKey$ = this.keyService + .userSignedPublicKey$(userId) + .pipe(distinctUntilChanged(compareValues)); const client$ = combineLatest([ this.environmentService.getEnvironment$(userId), @@ -184,11 +187,22 @@ export class DefaultSdkService implements SdkService { signingKey$, orgKeys$, securityState$, + signedPublicKey$, SdkLoadService.Ready, // Makes sure we wait (once) for the SDK to be loaded ]).pipe( // switchMap is required to allow the clean-up logic to be executed when `combineLatest` emits a new value. switchMap( - ([env, account, kdfParams, privateKey, userKey, signingKey, orgKeys, securityState]) => { + ([ + env, + account, + kdfParams, + privateKey, + userKey, + signingKey, + orgKeys, + securityState, + signedPublicKey, + ]) => { // Create our own observable to be able to implement clean-up logic return new Observable>((subscriber) => { const createAndInitializeClient = async () => { @@ -202,15 +216,31 @@ export class DefaultSdkService implements SdkService { settings, ); + let accountCryptographicState: WrappedAccountCryptographicState; + if (signingKey != null && securityState != null && signedPublicKey != null) { + accountCryptographicState = { + V2: { + private_key: privateKey, + signing_key: signingKey, + security_state: securityState, + signed_public_key: signedPublicKey, + }, + }; + } else { + accountCryptographicState = { + V1: { + private_key: privateKey, + }, + }; + } + await this.initializeClient( userId, client, account, kdfParams, - privateKey, userKey, - signingKey, - securityState, + accountCryptographicState, orgKeys, ); @@ -245,10 +275,8 @@ export class DefaultSdkService implements SdkService { client: PasswordManagerClient, account: AccountInfo, kdfParams: KdfConfig, - privateKey: EncryptedString, userKey: UserKey, - signingKey: WrappedSigningKey | null, - securityState: SignedSecurityState | null, + accountCryptographicState: WrappedAccountCryptographicState, orgKeys: Record, ) { await client.crypto().initialize_user_crypto({ @@ -265,9 +293,7 @@ export class DefaultSdkService implements SdkService { parallelism: kdfParams.parallelism, }, }, - privateKey, - signingKey: signingKey || undefined, - securityState: securityState || undefined, + accountCryptographicState: accountCryptographicState, }); // We initialize the org crypto even if the org_keys are diff --git a/libs/common/src/platform/sync/default-sync.service.ts b/libs/common/src/platform/sync/default-sync.service.ts index e599fbc1c48..910702bddd0 100644 --- a/libs/common/src/platform/sync/default-sync.service.ts +++ b/libs/common/src/platform/sync/default-sync.service.ts @@ -253,6 +253,10 @@ export class DefaultSyncService extends CoreSyncService { response.accountKeys.securityState.securityState, response.id, ); + await this.keyService.setSignedPublicKey( + response.accountKeys.publicKeyEncryptionKeyPair.signedPublicKey, + response.id, + ); } } else { await this.keyService.setPrivateKey(response.privateKey, response.id); diff --git a/libs/key-management/src/abstractions/key.service.ts b/libs/key-management/src/abstractions/key.service.ts index f86ca922c9e..feb4a38ac27 100644 --- a/libs/key-management/src/abstractions/key.service.ts +++ b/libs/key-management/src/abstractions/key.service.ts @@ -7,7 +7,7 @@ import { EncryptedString, EncString, } from "@bitwarden/common/key-management/crypto/models/enc-string"; -import { WrappedSigningKey } from "@bitwarden/common/key-management/types"; +import { SignedPublicKey, WrappedSigningKey } from "@bitwarden/common/key-management/types"; import { KeySuffixOptions, HashPurpose } from "@bitwarden/common/platform/enums"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { OrganizationId, ProviderId, UserId } from "@bitwarden/common/types/guid"; @@ -428,4 +428,8 @@ export abstract class KeyService { * @param userId The user id for the key */ abstract validateUserKey(key: UserKey, userId: UserId): Promise; + + abstract setSignedPublicKey(signedPublicKey: SignedPublicKey, userId: UserId): Promise; + + abstract userSignedPublicKey$(userId: UserId): Observable; } diff --git a/libs/key-management/src/key.service.ts b/libs/key-management/src/key.service.ts index f2c3c0eff7a..f0e5f6ee08e 100644 --- a/libs/key-management/src/key.service.ts +++ b/libs/key-management/src/key.service.ts @@ -28,7 +28,7 @@ import { EncryptedString, } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; -import { WrappedSigningKey } from "@bitwarden/common/key-management/types"; +import { SignedPublicKey, WrappedSigningKey } from "@bitwarden/common/key-management/types"; import { VaultTimeoutStringType } from "@bitwarden/common/key-management/vault-timeout"; import { VAULT_TIMEOUT } from "@bitwarden/common/key-management/vault-timeout/services/vault-timeout-settings.state"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -46,6 +46,7 @@ import { USER_EVER_HAD_USER_KEY, USER_KEY, USER_KEY_ENCRYPTED_SIGNING_KEY, + USER_SIGNED_PUBLIC_KEY, } from "@bitwarden/common/platform/services/key-state/user-key.state"; import { StateProvider } from "@bitwarden/common/platform/state"; import { CsprngArray } from "@bitwarden/common/types/csprng"; @@ -1013,4 +1014,12 @@ export class DefaultKeyService implements KeyServiceAbstraction { }), ); } + + async setSignedPublicKey(signedPublicKey: SignedPublicKey, userId: UserId): Promise { + await this.stateProvider.setUserState(USER_SIGNED_PUBLIC_KEY, signedPublicKey, userId); + } + + userSignedPublicKey$(userId: UserId): Observable { + return this.stateProvider.getUserState$(USER_SIGNED_PUBLIC_KEY, userId); + } } diff --git a/package-lock.json b/package-lock.json index 381515007a2..88754d75ad0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,8 @@ "@angular/platform-browser": "20.3.15", "@angular/platform-browser-dynamic": "20.3.15", "@angular/router": "20.3.15", - "@bitwarden/commercial-sdk-internal": "0.2.0-main.403", - "@bitwarden/sdk-internal": "0.2.0-main.403", + "@bitwarden/commercial-sdk-internal": "0.2.0-main.409", + "@bitwarden/sdk-internal": "0.2.0-main.409", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", "@koa/multer": "4.0.0", @@ -4615,9 +4615,9 @@ "link": true }, "node_modules/@bitwarden/commercial-sdk-internal": { - "version": "0.2.0-main.403", - "resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.403.tgz", - "integrity": "sha512-M2ZUu29oua7CaDTNK7mCwY7PhaIUbNYogAAvxLOmkJuyHNxxqvS9usjjlD2CkQVNBeTUFqvAQpaZQo9vgzEEFA==", + "version": "0.2.0-main.409", + "resolved": "https://registry.npmjs.org/@bitwarden/commercial-sdk-internal/-/commercial-sdk-internal-0.2.0-main.409.tgz", + "integrity": "sha512-86AVuOG5S9Te9ZMvozCV1FN8v98ROnUwr24nTeocqD/5OJIKoWWXk1t+g4YoVF+8AItpD6hFfO/uL05mG80jDA==", "license": "BITWARDEN SOFTWARE DEVELOPMENT KIT LICENSE AGREEMENT", "dependencies": { "type-fest": "^4.41.0" @@ -4720,9 +4720,9 @@ "link": true }, "node_modules/@bitwarden/sdk-internal": { - "version": "0.2.0-main.403", - "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.403.tgz", - "integrity": "sha512-ROEZdTbeKU68kDh9WYm9wKsLQD5jdTRclXLKl8x0aTj+Tx0nKyyXmLyUfOP+qh3EHIetij4jwPx2z3uS+7r8mg==", + "version": "0.2.0-main.409", + "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.409.tgz", + "integrity": "sha512-3e3hZenNos1xACJ2Bsq14RrzCnWdIilJuJhFwZYQBI6PQ+R38UGGQhGJDandKvQggfR8bDCY3re8x8n9G7MDiA==", "license": "GPL-3.0", "dependencies": { "type-fest": "^4.41.0" diff --git a/package.json b/package.json index 209bbc3beb1..b07d9f2a9e6 100644 --- a/package.json +++ b/package.json @@ -157,8 +157,8 @@ "@angular/platform-browser": "20.3.15", "@angular/platform-browser-dynamic": "20.3.15", "@angular/router": "20.3.15", - "@bitwarden/sdk-internal": "0.2.0-main.403", - "@bitwarden/commercial-sdk-internal": "0.2.0-main.403", + "@bitwarden/sdk-internal": "0.2.0-main.409", + "@bitwarden/commercial-sdk-internal": "0.2.0-main.409", "@electron/fuses": "1.8.0", "@emotion/css": "11.13.5", "@koa/multer": "4.0.0", From b9cb19a98e1ec0df2f4b57b96368ed7dae28554d Mon Sep 17 00:00:00 2001 From: adudek-bw Date: Thu, 4 Dec 2025 09:45:46 -0500 Subject: [PATCH 19/89] [PM-27081] Fix direct importers for linux (#17480) * Fix direct importers for linux --- .../chromium_importer/src/chromium/mod.rs | 32 ++++++++++--------- .../src/chromium/platform/linux.rs | 11 ++++--- .../src/chromium/platform/macos.rs | 14 ++++---- .../src/chromium/platform/windows/mod.rs | 12 +++---- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/apps/desktop/desktop_native/chromium_importer/src/chromium/mod.rs b/apps/desktop/desktop_native/chromium_importer/src/chromium/mod.rs index e57b40b5778..7011a2cce63 100644 --- a/apps/desktop/desktop_native/chromium_importer/src/chromium/mod.rs +++ b/apps/desktop/desktop_native/chromium_importer/src/chromium/mod.rs @@ -61,8 +61,8 @@ impl InstalledBrowserRetriever for DefaultInstalledBrowserRetriever { let mut browsers = Vec::with_capacity(SUPPORTED_BROWSER_MAP.len()); for (browser, config) in SUPPORTED_BROWSER_MAP.iter() { - let data_dir = get_browser_data_dir(config)?; - if data_dir.exists() { + let data_dir = get_and_validate_data_dir(config); + if data_dir.is_ok() { browsers.push((*browser).to_string()); } } @@ -114,7 +114,7 @@ pub async fn import_logins( #[derive(Debug, Clone, Copy)] pub(crate) struct BrowserConfig { pub name: &'static str, - pub data_dir: &'static str, + pub data_dir: &'static [&'static str], } pub(crate) static SUPPORTED_BROWSER_MAP: LazyLock< @@ -126,11 +126,19 @@ pub(crate) static SUPPORTED_BROWSER_MAP: LazyLock< .collect::>() }); -fn get_browser_data_dir(config: &BrowserConfig) -> Result { - let dir = dirs::home_dir() - .ok_or_else(|| anyhow!("Home directory not found"))? - .join(config.data_dir); - Ok(dir) +fn get_and_validate_data_dir(config: &BrowserConfig) -> Result { + for data_dir in config.data_dir.iter() { + let dir = dirs::home_dir() + .ok_or_else(|| anyhow!("Home directory not found"))? + .join(data_dir); + if dir.exists() { + return Ok(dir); + } + } + Err(anyhow!( + "Browser user data directory '{:?}' not found", + config.data_dir + )) } // @@ -174,13 +182,7 @@ fn load_local_state_for_browser(browser_name: &String) -> Result<(PathBuf, Local .get(browser_name.as_str()) .ok_or_else(|| anyhow!("Unsupported browser: {}", browser_name))?; - let data_dir = get_browser_data_dir(config)?; - if !data_dir.exists() { - return Err(anyhow!( - "Browser user data directory '{}' not found", - data_dir.display() - )); - } + let data_dir = get_and_validate_data_dir(config)?; let local_state = load_local_state(&data_dir)?; diff --git a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs index 14e38797640..f542e23129a 100644 --- a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs +++ b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs @@ -18,19 +18,22 @@ use crate::{ pub(crate) const SUPPORTED_BROWSERS: &[BrowserConfig] = &[ BrowserConfig { name: "Chrome", - data_dir: ".config/google-chrome", + data_dir: &[".config/google-chrome"], }, BrowserConfig { name: "Chromium", - data_dir: "snap/chromium/common/chromium", + data_dir: &["snap/chromium/common/chromium"], }, BrowserConfig { name: "Brave", - data_dir: "snap/brave/current/.config/BraveSoftware/Brave-Browser", + data_dir: &[ + "snap/brave/current/.config/BraveSoftware/Brave-Browser", + ".config/BraveSoftware/Brave-Browser", + ], }, BrowserConfig { name: "Opera", - data_dir: "snap/opera/current/.config/opera", + data_dir: &["snap/opera/current/.config/opera", ".config/opera"], }, ]; diff --git a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/macos.rs b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/macos.rs index 5d0b4f0c75c..6cd746d60b6 100644 --- a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/macos.rs +++ b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/macos.rs @@ -14,31 +14,31 @@ use crate::{ pub(crate) const SUPPORTED_BROWSERS: &[BrowserConfig] = &[ BrowserConfig { name: "Chrome", - data_dir: "Library/Application Support/Google/Chrome", + data_dir: &["Library/Application Support/Google/Chrome"], }, BrowserConfig { name: "Chromium", - data_dir: "Library/Application Support/Chromium", + data_dir: &["Library/Application Support/Chromium"], }, BrowserConfig { name: "Microsoft Edge", - data_dir: "Library/Application Support/Microsoft Edge", + data_dir: &["Library/Application Support/Microsoft Edge"], }, BrowserConfig { name: "Brave", - data_dir: "Library/Application Support/BraveSoftware/Brave-Browser", + data_dir: &["Library/Application Support/BraveSoftware/Brave-Browser"], }, BrowserConfig { name: "Arc", - data_dir: "Library/Application Support/Arc/User Data", + data_dir: &["Library/Application Support/Arc/User Data"], }, BrowserConfig { name: "Opera", - data_dir: "Library/Application Support/com.operasoftware.Opera", + data_dir: &["Library/Application Support/com.operasoftware.Opera"], }, BrowserConfig { name: "Vivaldi", - data_dir: "Library/Application Support/Vivaldi", + data_dir: &["Library/Application Support/Vivaldi"], }, ]; diff --git a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/windows/mod.rs b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/windows/mod.rs index 9cc89ed2161..524b5994873 100644 --- a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/windows/mod.rs +++ b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/windows/mod.rs @@ -25,27 +25,27 @@ pub use signature::*; pub(crate) const SUPPORTED_BROWSERS: &[BrowserConfig] = &[ BrowserConfig { name: "Brave", - data_dir: "AppData/Local/BraveSoftware/Brave-Browser/User Data", + data_dir: &["AppData/Local/BraveSoftware/Brave-Browser/User Data"], }, BrowserConfig { name: "Chrome", - data_dir: "AppData/Local/Google/Chrome/User Data", + data_dir: &["AppData/Local/Google/Chrome/User Data"], }, BrowserConfig { name: "Chromium", - data_dir: "AppData/Local/Chromium/User Data", + data_dir: &["AppData/Local/Chromium/User Data"], }, BrowserConfig { name: "Microsoft Edge", - data_dir: "AppData/Local/Microsoft/Edge/User Data", + data_dir: &["AppData/Local/Microsoft/Edge/User Data"], }, BrowserConfig { name: "Opera", - data_dir: "AppData/Roaming/Opera Software/Opera Stable", + data_dir: &["AppData/Roaming/Opera Software/Opera Stable"], }, BrowserConfig { name: "Vivaldi", - data_dir: "AppData/Local/Vivaldi/User Data", + data_dir: &["AppData/Local/Vivaldi/User Data"], }, ]; From 5386b58f2329eaed2acb9178560eeca9a265bb16 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Thu, 4 Dec 2025 16:06:13 +0100 Subject: [PATCH 20/89] Revert "Desktop Native compile debug builds with debug log level (#17357)" (#17815) This reverts commit a2abbd09bf40c06268ef38803b4e7148684607b3. --- apps/desktop/desktop_native/napi/package.json | 2 +- apps/desktop/desktop_native/napi/scripts/build.js | 14 -------------- apps/desktop/desktop_native/napi/src/lib.rs | 14 +++----------- 3 files changed, 4 insertions(+), 26 deletions(-) delete mode 100644 apps/desktop/desktop_native/napi/scripts/build.js diff --git a/apps/desktop/desktop_native/napi/package.json b/apps/desktop/desktop_native/napi/package.json index ca17377c9f2..d557ccfd259 100644 --- a/apps/desktop/desktop_native/napi/package.json +++ b/apps/desktop/desktop_native/napi/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "description": "", "scripts": { - "build": "node scripts/build.js", + "build": "napi build --platform --js false", "test": "cargo test" }, "author": "", diff --git a/apps/desktop/desktop_native/napi/scripts/build.js b/apps/desktop/desktop_native/napi/scripts/build.js deleted file mode 100644 index 7b3dccf81e4..00000000000 --- a/apps/desktop/desktop_native/napi/scripts/build.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -const { execSync } = require('child_process'); - -const args = process.argv.slice(2); -const isRelease = args.includes('--release'); - -if (isRelease) { - console.log('Building release mode.'); -} else { - console.log('Building debug mode.'); - process.env.RUST_LOG = 'debug'; -} - -execSync(`napi build --platform --js false ${isRelease ? '--release' : ''}`, { stdio: 'inherit', env: process.env }); diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index c34e7574f68..b5dcb277a75 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -961,7 +961,7 @@ pub mod logging { }; use tracing::Level; use tracing_subscriber::{ - filter::EnvFilter, + filter::{EnvFilter, LevelFilter}, fmt::format::{DefaultVisitor, Writer}, layer::SubscriberExt, util::SubscriberInitExt, @@ -1049,17 +1049,9 @@ pub mod logging { pub fn init_napi_log(js_log_fn: ThreadsafeFunction<(LogLevel, String), CalleeHandled>) { let _ = JS_LOGGER.0.set(js_log_fn); - // the log level hierarchy is determined by: - // - if RUST_LOG is detected at runtime - // - if RUST_LOG is provided at compile time - // - default to INFO let filter = EnvFilter::builder() - .with_default_directive( - option_env!("RUST_LOG") - .unwrap_or("info") - .parse() - .expect("should provide valid log level at compile time."), - ) + // set the default log level to INFO. + .with_default_directive(LevelFilter::INFO.into()) // parse directives from the RUST_LOG environment variable, // overriding the default directive for matching targets. .from_env_lossy(); From 4155e26c28299beb112cbcce9313a614c62589f6 Mon Sep 17 00:00:00 2001 From: Vicki League Date: Thu, 4 Dec 2025 10:44:04 -0500 Subject: [PATCH 21/89] [PM-18839] Use mono font for color password component (#17785) --- libs/components/src/color-password/color-password.component.ts | 2 +- libs/components/src/color-password/color-password.stories.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/components/src/color-password/color-password.component.ts b/libs/components/src/color-password/color-password.component.ts index bd7f3beb403..eaaefd29f1d 100644 --- a/libs/components/src/color-password/color-password.component.ts +++ b/libs/components/src/color-password/color-password.component.ts @@ -14,7 +14,7 @@ type CharacterType = "letter" | "emoji" | "special" | "number"; @Component({ selector: "bit-color-password", template: `@for (character of passwordCharArray(); track $index; let i = $index) { - + {{ character }} @if (showCount()) { {{ i + 1 }} diff --git a/libs/components/src/color-password/color-password.stories.ts b/libs/components/src/color-password/color-password.stories.ts index 65b6a3c0f18..2ed5cdc4b8d 100644 --- a/libs/components/src/color-password/color-password.stories.ts +++ b/libs/components/src/color-password/color-password.stories.ts @@ -4,7 +4,7 @@ import { formatArgsForCodeSnippet } from "../../../../.storybook/format-args-for import { ColorPasswordComponent } from "./color-password.component"; -const examplePassword = "Wq$Jk😀7jlI DX#rS5Sdi!z "; +const examplePassword = "Wq$Jk😀7jlI DX#rS5Sdi!z0O "; export default { title: "Component Library/Color Password", From ad12704c218226b5d831939017867cc2d85c80b5 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Thu, 4 Dec 2025 11:50:19 -0500 Subject: [PATCH 22/89] [CL-871] responsive sidebar product switcher (#17780) * only make switcher sticky when height is larger than 850 * use rem based value for media query * add comment about why 53rem was chosen --- libs/components/src/navigation/side-nav.component.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/components/src/navigation/side-nav.component.html b/libs/components/src/navigation/side-nav.component.html index d2e6aeab2bb..0a0d4af3adc 100644 --- a/libs/components/src/navigation/side-nav.component.html +++ b/libs/components/src/navigation/side-nav.component.html @@ -23,7 +23,11 @@ (keydown)="handleKeyDown($event)" > -
    + + +
    @if (data.open) { From 474ffa2ce14134c8fd2494d44fec3863064460d6 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:13:21 -0800 Subject: [PATCH 23/89] [PM-25360] - allow item details name to be selectable (#17693) * allow item details name to be selectable * use tw class --- .../src/cipher-view/item-details/item-details-v2.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/vault/src/cipher-view/item-details/item-details-v2.component.html b/libs/vault/src/cipher-view/item-details/item-details-v2.component.html index 6cc85e161d4..52e850dd09b 100644 --- a/libs/vault/src/cipher-view/item-details/item-details-v2.component.html +++ b/libs/vault/src/cipher-view/item-details/item-details-v2.component.html @@ -10,7 +10,7 @@
    -

    +

    {{ cipher().name }}

    From cf806dcac4127edf8413563eabef35c81a638111 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Thu, 4 Dec 2025 15:16:48 -0500 Subject: [PATCH 24/89] do not trigger an update notification if the entered password matches a stored cipher with the same value and matching username (#17811) --- .../background/notification.background.ts | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 17e3ec159c3..1cbf915b06a 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -627,11 +627,11 @@ export default class NotificationBackground { } const username: string | null = data.username || null; - const currentPassword = data.password || null; - const newPassword = data.newPassword || null; + const currentPasswordFieldValue = data.password || null; + const newPasswordFieldValue = data.newPassword || null; - if (authStatus === AuthenticationStatus.Locked && newPassword !== null) { - await this.pushChangePasswordToQueue(null, loginDomain, newPassword, tab, true); + if (authStatus === AuthenticationStatus.Locked && newPasswordFieldValue !== null) { + await this.pushChangePasswordToQueue(null, loginDomain, newPasswordFieldValue, tab, true); return true; } @@ -657,35 +657,49 @@ export default class NotificationBackground { const [cipher] = ciphers; if ( username !== null && - newPassword === null && + newPasswordFieldValue === null && cipher.login.username.toLowerCase() === normalizedUsername && - cipher.login.password === currentPassword + cipher.login.password === currentPasswordFieldValue ) { // Assumed to be a login return false; } } - if (currentPassword && !newPassword) { + if ( + ciphers.length > 0 && + currentPasswordFieldValue?.length && // Only use current password for change if no new password present. - if (ciphers.length > 0) { - await this.pushChangePasswordToQueue( - ciphers.map((cipher) => cipher.id), - loginDomain, - currentPassword, - tab, - ); - return true; + !newPasswordFieldValue + ) { + const currentPasswordMatchesAnExistingValue = ciphers.some( + (cipher) => + cipher.login?.password?.length && cipher.login.password === currentPasswordFieldValue, + ); + + // The password entered matched a stored cipher value with + // the same username (no change) + if (currentPasswordMatchesAnExistingValue) { + return false; } + + await this.pushChangePasswordToQueue( + ciphers.map((cipher) => cipher.id), + loginDomain, + currentPasswordFieldValue, + tab, + ); + + return true; } - if (newPassword) { + if (newPasswordFieldValue) { // Otherwise include all known ciphers. if (ciphers.length > 0) { await this.pushChangePasswordToQueue( ciphers.map((cipher) => cipher.id), loginDomain, - newPassword, + newPasswordFieldValue, tab, ); From 2bf9e3f6df4be7514198f3ea1bcb5669872a340e Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Thu, 4 Dec 2025 13:39:12 -0800 Subject: [PATCH 25/89] [PM-29106] Add null check for login Uris that may come from SDK login list view (#17791) --- libs/common/src/vault/services/search.service.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/common/src/vault/services/search.service.ts b/libs/common/src/vault/services/search.service.ts index 0b34bd3863f..feb6a7494b5 100644 --- a/libs/common/src/vault/services/search.service.ts +++ b/libs/common/src/vault/services/search.service.ts @@ -335,8 +335,10 @@ export class SearchService implements SearchServiceAbstraction { if ( login && - login.uris.length && - login.uris.some((loginUri) => loginUri?.uri?.toLowerCase().indexOf(query) > -1) + login.uris?.length && + login.uris?.some( + (loginUri) => loginUri?.uri && loginUri.uri.toLowerCase().indexOf(query) > -1, + ) ) { return true; } From d32365fbba1a9bf732846257787b44c3a9c690e8 Mon Sep 17 00:00:00 2001 From: Tom <144813356+ttalty@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:04:26 -0500 Subject: [PATCH 26/89] [PM-29164] Access Intelligence display for only enterprise (#17807) * Access Intelligence display for only enterprise * modifying the access intelligence routing to properly match. Added documentation. * tasks remove useriskinsights flag * fixing tasks test cases * tasks should only check for enterprise * fixing uncommitted changes * reverting unecessary change from all activites * adding back missing test case --- .../organization-layout.component.html | 15 ++++++++----- .../layouts/organization-layout.component.ts | 5 +++++ .../organizations-routing.module.ts | 7 ++++-- .../access-intelligence-routing.module.ts | 3 ++- .../organization.service.abstraction.ts | 12 ++++++++++ .../models/domain/organization.ts | 4 ++++ .../services/default-task.service.spec.ts | 22 +++++++++---------- .../tasks/services/default-task.service.ts | 2 +- 8 files changed, 48 insertions(+), 22 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index e84f78458d6..59bc03babd4 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -2,12 +2,15 @@ - + + @if (canShowAccessIntelligenceTab(organization)) { + + } + org.canAccessReports)], + canActivate: [organizationPermissionsGuard(canAccessAccessIntelligence)], loadChildren: () => import("../../dirt/access-intelligence/access-intelligence.module").then( (m) => m.AccessIntelligenceModule, diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts index 4bdc8e25047..85c6dbdd206 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/access-intelligence-routing.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; +import { canAccessAccessIntelligence } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard"; import { RiskInsightsComponent } from "./risk-insights.component"; @@ -8,7 +9,7 @@ import { RiskInsightsComponent } from "./risk-insights.component"; const routes: Routes = [ { path: "", - canActivate: [organizationPermissionsGuard((org) => org.canAccessReports)], + canActivate: [organizationPermissionsGuard(canAccessAccessIntelligence)], component: RiskInsightsComponent, data: { titleId: "accessIntelligence", diff --git a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts index 363b82c507d..54d2f93ac03 100644 --- a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts +++ b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts @@ -41,6 +41,18 @@ export function canAccessBillingTab(org: Organization): boolean { return org.isOwner; } +/** + * Access Intelligence is only available to: + * - Enterprise organizations + * - Users in those organizations with report access + * + * @param org The organization to verify access + * @returns If true can access the Access Intelligence feature + */ +export function canAccessAccessIntelligence(org: Organization): boolean { + return org.canUseAccessIntelligence && org.canAccessReports; +} + export function canAccessOrgAdmin(org: Organization): boolean { // Admin console can only be accessed by Owners for disabled organizations if (!org.enabled && !org.isOwner) { diff --git a/libs/common/src/admin-console/models/domain/organization.ts b/libs/common/src/admin-console/models/domain/organization.ts index b2153024ef8..dba4a1fedb3 100644 --- a/libs/common/src/admin-console/models/domain/organization.ts +++ b/libs/common/src/admin-console/models/domain/organization.ts @@ -402,4 +402,8 @@ export class Organization { this.permissions.accessEventLogs) ); } + + get canUseAccessIntelligence() { + return this.productTierType === ProductTierType.Enterprise; + } } diff --git a/libs/common/src/vault/tasks/services/default-task.service.spec.ts b/libs/common/src/vault/tasks/services/default-task.service.spec.ts index 8fc2f902ca4..b57915aadbc 100644 --- a/libs/common/src/vault/tasks/services/default-task.service.spec.ts +++ b/libs/common/src/vault/tasks/services/default-task.service.spec.ts @@ -51,10 +51,10 @@ describe("Default task service", () => { mockGetAllOrgs$.mockReturnValue( new BehaviorSubject([ { - useAccessIntelligence: false, + canUseAccessIntelligence: false, }, { - useAccessIntelligence: true, + canUseAccessIntelligence: true, }, ] as Organization[]), ); @@ -70,10 +70,10 @@ describe("Default task service", () => { mockGetAllOrgs$.mockReturnValue( new BehaviorSubject([ { - useAccessIntelligence: false, + canUseAccessIntelligence: false, }, { - useAccessIntelligence: false, + canUseAccessIntelligence: false, }, ] as Organization[]), ); @@ -91,17 +91,17 @@ describe("Default task service", () => { mockGetAllOrgs$.mockReturnValue( new BehaviorSubject([ { - useAccessIntelligence: true, + canUseAccessIntelligence: true, }, ] as Organization[]), ); }); - it("should return an empty array if tasks are not enabled", async () => { + it("should return no tasks if not present and canUserAccessIntelligence is false", async () => { mockGetAllOrgs$.mockReturnValue( new BehaviorSubject([ { - useAccessIntelligence: false, + canUseAccessIntelligence: false, }, ] as Organization[]), ); @@ -111,7 +111,6 @@ describe("Default task service", () => { const result = await firstValueFrom(tasks$("user-id" as UserId)); expect(result.length).toBe(0); - expect(mockApiSend).not.toHaveBeenCalled(); }); it("should fetch tasks from the API when the state is null", async () => { @@ -163,17 +162,17 @@ describe("Default task service", () => { mockGetAllOrgs$.mockReturnValue( new BehaviorSubject([ { - useAccessIntelligence: true, + canUseAccessIntelligence: true, }, ] as Organization[]), ); }); - it("should return an empty array if tasks are not enabled", async () => { + it("should return no tasks if not present and canUserAccessIntelligence is false", async () => { mockGetAllOrgs$.mockReturnValue( new BehaviorSubject([ { - useAccessIntelligence: false, + canUseAccessIntelligence: false, }, ] as Organization[]), ); @@ -183,7 +182,6 @@ describe("Default task service", () => { const result = await firstValueFrom(pendingTasks$("user-id" as UserId)); expect(result.length).toBe(0); - expect(mockApiSend).not.toHaveBeenCalled(); }); it("should filter tasks to only pending tasks", async () => { diff --git a/libs/common/src/vault/tasks/services/default-task.service.ts b/libs/common/src/vault/tasks/services/default-task.service.ts index 5bd23ed8605..60e05e0728f 100644 --- a/libs/common/src/vault/tasks/services/default-task.service.ts +++ b/libs/common/src/vault/tasks/services/default-task.service.ts @@ -48,7 +48,7 @@ export class DefaultTaskService implements TaskService { tasksEnabled$ = perUserCache$((userId) => { return this.organizationService.organizations$(userId).pipe( - map((orgs) => orgs.some((o) => o.useAccessIntelligence)), + map((orgs) => orgs.some((o) => o.canUseAccessIntelligence)), distinctUntilChanged(), ); }); From 2976c9c6541b6f9cbaa19256af7575f5c930e0a5 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:00:29 +0100 Subject: [PATCH 27/89] Autosync the updated translations (#17826) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/af/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ar/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/az/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/be/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/bg/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/bn/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/bs/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ca/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/cs/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/cy/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/da/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/de/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/el/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/en_GB/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/en_IN/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/eo/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/es/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/et/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/eu/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/fa/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/fi/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/fil/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/fr/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/gl/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/he/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/hi/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/hr/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/hu/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/id/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/it/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ja/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ka/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/km/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/kn/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ko/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/lt/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/lv/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/me/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ml/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/mr/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/my/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/nb/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ne/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/nl/messages.json | 36 ++++++++++++++++++-- apps/desktop/src/locales/nn/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/or/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/pl/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/pt_BR/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/pt_PT/messages.json | 36 ++++++++++++++++++-- apps/desktop/src/locales/ro/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ru/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/si/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/sk/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/sl/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/sr/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/sv/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/ta/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/te/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/th/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/tr/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/uk/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/vi/messages.json | 34 +++++++++++++++++- apps/desktop/src/locales/zh_CN/messages.json | 36 ++++++++++++++++++-- apps/desktop/src/locales/zh_TW/messages.json | 34 +++++++++++++++++- 64 files changed, 2115 insertions(+), 67 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 1c6a2bc49c9..a4230a128c5 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Leer meer" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funksie Onbeskikbaar" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GG geënkripteerde berging vir lêeraanhegsels." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alle Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Is u seker u wil die “Nooit”-opsie gebruik? Deur u vergrendelopsies op “Nooit” te stel word u kluis se enkripsie op u toestel bewaar. Indien u hierdie opsie gebruik moet u verseker dat u toestel behoorlik beskerm is." }, "vault": { - "message": "Kluis" + "message": "Kluis", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Meld aan met meesterwagwoord" diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index ca404f4e179..54a9425c901 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "اعرف المزيد" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "الميزة غير متوفرة" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 جيغابايت وحدة تخزين مشفرة لمرفقات الملفات." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "خيارات تسجيل الدخول بخطوتين المملوكة مثل YubiKey و Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "كل الإرسالات", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "هل أنت متأكد من أنك تريد استخدام خيار \"مطلقا\"؟ إعداد خيارات القفل إلى \"مطلقا\" يخزن مفتاح تشفير المستودع الخاص بك على جهازك. إذا كنت تستخدم هذا الخيار، يجب أن تتأكد من الحفاظ على حماية جهازك بشكل صحيح." }, "vault": { - "message": "الخزانة" + "message": "الخزانة", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "تسجيل الدخول باستخدام كلمة المرور الرئيسية" diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 55c2bdcd677..9e8c77aa76a 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Daha ətraflı" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Özəllik əlçatmazdır" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "Fayl qoşmaları üçün 1 GB şifrələnmiş saxlama sahəsi." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey və Duo kimi mülkiyyətçi iki addımlı giriş seçimləri." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Əlaqə məlumatları" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Bütün \"Send\"lər", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "\"Heç vaxt\"i seçmək istədiyinizə əminsiniz? Kilid seçimini \"Heç vaxt\" olaraq ayarlasanız, seyfinizin şifrələmə açarı cihazınızda saxlanılacaq. Bu seçimi istifadə etsəniz, cihazınızı daha yaxşı mühafizə etdiyinizə əmin olmalısınız." }, "vault": { - "message": "Seyf" + "message": "Seyf", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Ana parolla giriş et" diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index b2e4db47b32..e9b3834a9f7 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Даведацца больш" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Функцыя недаступна" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 ГБ зашыфраванага сховішча для далучаных файлаў." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Прапрыетарныя варыянты двухэтапнага ўваходу, такія як YubiKey, FIDO U2F і Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Усе Send'ы", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Вы сапраўды хочаце адключыць блакіроўку сховішча? Прызначыўшы параметр блакіравання \"Ніколі\", ключ шыфравання будзе захоўвацца на вашай прыладзе. Калі вы выкарыстоўваеце гэты параметр, вы павінны быць упэўнены ў тым, што ваша прылада надзейна абаронена." }, "vault": { - "message": "Сховішча" + "message": "Сховішча", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Увайсці з асноўным паролем" diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index ad03c2cc023..f27fb467c0c 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Научете повече" }, + "migrationsFailed": { + "message": "Възникна грешка при обновяването на настройките за шифроване." + }, + "updateEncryptionSettingsTitle": { + "message": "Обновете настройките си за шифроване" + }, + "updateEncryptionSettingsDesc": { + "message": "Новите препоръчани настройки за шифроване ще подобрят сигурността на акаунта Ви. Въведете главната си парола, за да ги обновите сега." + }, + "confirmIdentityToContinue": { + "message": "Потвърдете самоличността си, за да продължите" + }, + "enterYourMasterPassword": { + "message": "Въведете главната си парола" + }, + "updateSettings": { + "message": "Обновяване на настройките" + }, "featureUnavailable": { "message": "Функцията е недостъпна" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 ГБ пространство за файлове, които се шифроват." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ пространство за файлове, които се шифрират.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Частно двустепенно удостоверяване чрез YubiKey и Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Информация за контакт" }, + "send": { + "message": "Изпращане", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Всички изпращания", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Уверени ли сте, че искате да зададете стойност „Никога“? Това води до съхранение на шифриращия ключ за трезора във устройството ви. Ако използвате тази възможност, е много важно да имате надлежна защита на устройството си." }, "vault": { - "message": "Трезор" + "message": "Трезор", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Вписване с главната парола" diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index d6c61c1ab51..f9f072f290e 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "আরও জানুন" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "বৈশিষ্ট্য অনুপলব্ধ" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "ফাইল সংযুক্তির জন্য ১ জিবি এনক্রিপ্টেড স্থান।" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index 569f1072c4b..b8798320a98 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Saznajte više" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funkcija nije dostupna" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB šifriranog prostora za pohranu podataka." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Svi Send-ovi", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index de468f1e8b3..a7674cbc753 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Més informació" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Característica no disponible" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB d'emmagatzematge xifrat per als fitxers adjunts." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opcions propietàries de doble factor com ara YubiKey i Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Informació de contacte" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Tots els Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Esteu segur que voleu utilitzar l'opció \"Mai\"? En configurar les opcions de bloqueig a \"Mai\" s'emmagatzema la clau de xifratge de la vostra caixa forta al vostre dispositiu. Si utilitzeu aquesta opció, heu d'assegurar-vos que conserveu el dispositiu degudament protegit." }, "vault": { - "message": "Caixa forta" + "message": "Caixa forta", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Inici de sessió amb contrasenya mestra" diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index c02dbabbc93..b93e5d0f513 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Dozvědět se více" }, + "migrationsFailed": { + "message": "Došlo k chybě při aktualizaci nastavení šifrování." + }, + "updateEncryptionSettingsTitle": { + "message": "Aktualizovat nastavení šifrování" + }, + "updateEncryptionSettingsDesc": { + "message": "Nové doporučené nastavení šifrování zlepší bezpečnost Vašeho účtu. Pokud chcete aktualizovat nyní, zadejte hlavní heslo." + }, + "confirmIdentityToContinue": { + "message": "Pro pokračování potvrďte svou identitu" + }, + "enterYourMasterPassword": { + "message": "Zadejte své hlavní heslo" + }, + "updateSettings": { + "message": "Aktualizovat nastavení" + }, "featureUnavailable": { "message": "Funkce není dostupná" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrovaného uložiště pro přílohy." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrovaného úložiště pro přílohy.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Volby proprietálních dvoufázových přihlášení jako je YubiKey a Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Všechny Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Opravdu chcete použít volbu \"Nikdy\"? Nastavením volby uzamčení na \"Nikdy\" bude šifrovací klíč k trezoru uložen přímo ve Vašem zařízení. Pokud tuto možnost použijete, měli byste Vaše zařízení řádně zabezpečit a chránit." }, "vault": { - "message": "Trezor" + "message": "Trezor", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Přihlásit se pomocí hlavního hesla" diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index 25b52fcc101..5a00ad90bbd 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index 1d135a533f2..622c9e9187d 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Læs mere" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funktion utilgængelig" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB krypteret lagerplads til filvedhæftninger." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietære totrins-login muligheder, såsom YubiKey og Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alle Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Sikker på, at indstillingen \"Aldrig\" skal bruges? Sættes låseindstillinger til \"Aldrig\", gemmes din bokskrypteringsnøgle på enheden. Bruges denne indstilling, så sørg for at holde din enhed ordentligt beskyttet." }, "vault": { - "message": "Boks" + "message": "Boks", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log ind med hovedadgangskoden" diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 6fc220faded..2743ec21c8a 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Mehr erfahren" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funktion nicht verfügbar" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB verschlüsselter Speicherplatz für Dateianhänge." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ verschlüsselter Speicher für Dateianhänge.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietäre Optionen für die Zwei-Faktor Authentifizierung wie YubiKey und Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Kontaktinformationen" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alle Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Bist du sicher, dass du die Option \"Nie\" verwenden möchtest? Durch das Setzen der Sperroptionen zu \"Nie\" wird der Verschlüsselungscode deines Tresors auf deinem Gerät gespeichert. Wenn du diese Option verwendest, solltest du sicherstellen, dass dein Gerät ausreichend geschützt ist." }, "vault": { - "message": "Tresor" + "message": "Tresor", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Mit Master-Passwort anmelden" diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 0b869c1e02f..bd8269db4ea 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Μάθετε περισσότερα" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Μη διαθέσιμη λειτουργία" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB κρυπτογραφημένο αποθηκευτικό χώρο για συνημμένα αρχεία." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Ιδιόκτητες επιλογές σύνδεσης δύο βημάτων, όπως το YubiKey και το Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Στοιχεία επικοινωνίας" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Όλα τα Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Είστε βέβαιοι ότι θέλετε να χρησιμοποιήσετε την επιλογή \"Ποτέ\"; Ο ορισμός των επιλογών κλειδώματος σε \"Ποτέ\" αποθηκεύει το κλειδί κρυπτογράφησης του θησαυ/κίου σας στη συσκευή σας. Εάν χρησιμοποιήσετε αυτήν την επιλογή, θα πρέπει να διασφαλίσετε ότι θα διατηρείτε τη συσκευή σας κατάλληλα προστατευμένη." }, "vault": { - "message": "Κρύπτη" + "message": "Κρύπτη", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Συνδεθείτε με τον κύριο κωδικό πρόσβασης" diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index 16af69361c6..4e1f8569caf 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index c6f1253bb59..1413debe49c 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 28a9f3b8bce..5cb6995eeb6 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Lerni pli" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "La funkcio nedisponeblas" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Ĉiuj Send'oj", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Trezorejo" + "message": "Trezorejo", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Saluti per la ĉefa pasvorto" diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index 9966fa1064c..af90b40af65 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Más información" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Característica no disponible" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1GB de espacio en disco cifrado." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opciones de inicio de sesión con autenticación de dos pasos propietarios como YubiKey y Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Información de contacto" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Todos los Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "¿Está seguro de que quieres usar la opción \"Nunca\"? Al ajustar las opciones de bloqueo a \"Nunca\", la clave de cifrado de su caja fuerte se guardará en tu dispositivo. Si usas esta opción, asegúrate de mantener tu dispositivo debidamente protegido." }, "vault": { - "message": "Caja fuerte" + "message": "Caja fuerte", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Iniciar sesión con contraseña maestra" diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index d85c52bb763..8ab2818f7ea 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Loe edasi" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funktsioon pole saadaval" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB ulatuses krüpteeritud salvestusruum." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Eraomanduses kaheastmelise logimise valikud, nagu näiteks YubiKey ja Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Kõik Sendid", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Oled kindel, et soovid kasutada valikut \"Mitte kunagi\"? Sellega talletatakse sinu hoidla krüpteerimise võtit seadme mälus. Peaksid olema väga hoolas ja kindel, et seade on ohutu ja selles ei ole pahavara." }, "vault": { - "message": "Hoidla" + "message": "Hoidla", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Logi sisse ülemparooliga" diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 36401df0078..451e77c4ec0 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Gehiago ikasi" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Ezaugarria ez dago erabilgarri" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "Eranskinentzako 1GB-eko zifratutako biltegia." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Send guztiak", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Ziur zaude \"Inoiz ez\" aukera erabili nahi duzula? Zure blokeo aukerak \"Inoiz ez\" bezala konfiguratzeak kutxa gotorraren zifratze-gakoa gailuan gordetzen du. Aukera hau erabiltzen baduzu, gailua behar bezala babestuta duzula ziurtatu behar duzu." }, "vault": { - "message": "Kutxa gotorra" + "message": "Kutxa gotorra", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Hasi saioa pasahitz nagusiarekin" diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index ac0e83dd44d..f7dedc42542 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "بیشتر بدانید" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "ویژگی موجود نیست" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "۱ گیگابایت فضای ذخیره‌سازی رمزنگاری شده برای پرونده‌های پیوست." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "گزینه‌های ورود اضافی دو مرحله‌ای مانند YubiKey و Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "اطلاعات تماس" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "همه ارسال‌ها", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "آیا جداً می‌خواهید از گزینه \"هرگز\" استفاده کنید؟ تنظیم کردن گزینه قفل به \"هرگز\" کلیدهای رمزنگاری گاوصندوقتان را بر روی دستگاه شما ذخیره خواهد کرد. اگر از این گزینه استفاده می‌کنید باید اطمینان داشته باشید که دستگاه شما کاملا محافظت شده است." }, "vault": { - "message": "گاوصندوق" + "message": "گاوصندوق", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "با کلمه عبور اصلی وارد شوید" diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index e2952659d03..2021248bae4 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Lue lisää" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Ominaisuus ei ole käytettävissä" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 Gt salattua tallennustilaa tiedostoliitteille." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Kaksivaiheisen kirjautumisen erikoisvaihtoehdot, kuten YubiKey ja Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Yhteystiedot" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Kaikki Sendit", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Haluatko varmasti käyttää asetusta \"Ei koskaan\"? Se tallentaa holvisi salausavaimen laitteellesi. Jos käytät asetusta, varmista, että laite on suojattu hyvin." }, "vault": { - "message": "Holvi" + "message": "Holvi", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Kirjaudu pääsalasanalla" diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index 6eaa5577807..9c8bbaf0a34 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Matuto nang higit pa" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Hindi magagamit ang tampok" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB naka encrypt na imbakan para sa mga attachment ng file." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Lahat ng Mga Padala", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Sigurado ka bang gusto mong gamitin ang opsyon na \"Never\" Ang pagtatakda ng iyong mga pagpipilian sa lock sa \"Hindi kailanman\" ay nag iimbak ng key ng pag encrypt ng iyong vault sa iyong aparato. Kung gagamitin mo ang pagpipiliang ito dapat mong tiyakin na pinapanatili mong protektado nang maayos ang iyong aparato." }, "vault": { - "message": "Ayos" + "message": "Ayos", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Mag-login gamit ang pangunahing password" diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index 6cca98444b8..8f7bfc39c4a 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "En savoir plus" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Fonctionnalité non disponible" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 Go de stockage chiffré pour les fichiers joints." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Options de connexion propriétaires à deux facteurs telles que YubiKey et Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Informations de contact" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Tous les Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Êtes-vous sûr de vouloir utiliser l'option \"Jamais\" ? Définir le verrouillage sur \"Jamais\" stocke la clé de chiffrement de votre coffre sur votre appareil. Si vous utilisez cette option, vous devez vous assurer de correctement protéger votre appareil." }, "vault": { - "message": "Coffre" + "message": "Coffre", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Se connecter avec le mot de passe principal" diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index d607bb8d097..0211550b08d 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 868cd9ccbc5..5881405c190 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "למידע נוסף" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "יכולת זו לא זמינה" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 ג'יגה של מקום אחסון מוצפן עבור קבצים מצורפים." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "אפשרויות כניסה דו־שלבית קנייניות כגון YubiKey ו־Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "פרטי איש קשר" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "כל הסֵנְדים", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "האם אתה בטוח שברצונך להשתמש באפשרות \"לעולם לא\"? הגדרת אפשרויות הנעילה שלך ל\"לעולם לא\" מאחסנת את מפתח ההצפנה של הכספת שלך במכשיר שלך. אם אתה משתמש באפשרות זו עליך לוודא שאתה שומר על המכשיר שלך מוגן כראוי." }, "vault": { - "message": "כספת" + "message": "כספת", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "כניסה עם סיסמה ראשית" diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 2ab323eedc9..2fac0a369fd 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 0f7a8185118..07effb638b8 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Saznaj više" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Značajka nije dostupna" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB šifriranog prostora za pohranu podataka." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Mogućnosti za prijavu u dva koraka kao što su YubiKey i Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Kontaktne informacije" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Svi Sendovi", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Sigurno želiš koristiti opciju „Nikada”? Postavljanje opcija zaključavanja na „Nikada” pohranjuje šifru tvojeg trezora na tvom uređaju. Ako koristiš ovu opciju, trebalo bi osigurati da je uređaj pravilno zaštićen." }, "vault": { - "message": "Trezor" + "message": "Trezor", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Prijava glavnom lozinkom" diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 9a6dd787f8c..583d5b86a59 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "További információ" }, + "migrationsFailed": { + "message": "Hiba történt a titkosítási beállítások frissítésekor." + }, + "updateEncryptionSettingsTitle": { + "message": "A titkosítási beállítások frissítése" + }, + "updateEncryptionSettingsDesc": { + "message": "Az új ajánlott titkosítási beállítások javítják a fiók biztonságát. Adjuk meg a mesterjelszót a frissítéshez most." + }, + "confirmIdentityToContinue": { + "message": "A folytatáshoz meg kell erősíteni a személyazonosságot." + }, + "enterYourMasterPassword": { + "message": "Mesterjelszó megadása" + }, + "updateSettings": { + "message": "Beállítások frissítése" + }, "featureUnavailable": { "message": "Ez a funkció nem érhető el." }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB titkosított fájlmelléklet tárhely." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ titkosított tárhely a fájlmellékletekhez.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Saját kétlépcsős bejelentkezési lehetőségek mint a YubiKey és a Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Elérhetőségi adatok" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Összes küldés", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Biztosan szeretnénk használni a \"Soha\" opciót? A zárolási opciók \"Soha\" értékre állítása a széf titkosítási kulcsát az eszközön tárolja. Ennek az opciónak a használatakor célszerű az eszköz megfelelő védettségét biztosítani." }, "vault": { - "message": "Széf" + "message": "Széf", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Bejelentkezés mesterjelszóval" diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index 188ee153da1..fbbb1440990 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Pelajari lebih lanjut" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Fitur Tidak Tersedia" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB penyimpanan berkas yang dienkripsi." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Semua Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Brankas" + "message": "Brankas", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 8caf4982356..64e31e4136f 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Ulteriori informazioni" }, + "migrationsFailed": { + "message": "Si è verificato un errore durante l'aggiornamento delle impostazioni di cifratura." + }, + "updateEncryptionSettingsTitle": { + "message": "Aggiorna le impostazioni di crittografia" + }, + "updateEncryptionSettingsDesc": { + "message": "Le nuove impostazioni di crittografia consigliate miglioreranno la sicurezza del tuo account. Inserisci la tua password principale per aggiornare." + }, + "confirmIdentityToContinue": { + "message": "Conferma la tua identità per continuare" + }, + "enterYourMasterPassword": { + "message": "Inserisci la tua password principale" + }, + "updateSettings": { + "message": "Aggiorna impostazioni" + }, "featureUnavailable": { "message": "Funzionalità non disponibile" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB di spazio di archiviazione crittografato per gli allegati." }, + "premiumSignUpStorageV2": { + "message": "Archivio crittografato di $SIZE$ per allegati.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opzioni di verifica in due passaggi proprietarie come YubiKey e Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Informazioni di contatto" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Tutti i Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Sei sicuro di voler usare l'opzione \"Mai\"? Impostare le opzioni di blocco su \"Mai\" salverà la chiave di crittografia della cassaforte sul tuo dispositivo. Se usi questa opzione, assicurati di mantenere il tuo dispositivo adeguatamente protetto." }, "vault": { - "message": "Cassaforte" + "message": "Cassaforte", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Accedi con password principale" diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index ca50828b12c..5accef2b5ee 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "詳細情報" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "サービスが利用できません" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1GB の暗号化されたファイルストレージ。" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey、Duo などのプロプライエタリな2段階認証オプション。" }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "すべての Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "本当に「なし」オプションを使用しますか?ロックオプションを「なし」に設定すると、保管庫の暗号化キーがデバイスに保存されます。 このオプションを使用する場合は、デバイスを適切に保護する必要があります。" }, "vault": { - "message": "保管庫" + "message": "保管庫", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "マスターパスワードでログイン" diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 9337286d3fd..cca3ab548cf 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "გაიგეთ მეტი" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "საცავი" + "message": "საცავი", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index d607bb8d097..0211550b08d 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index d1375efee8c..4ef1f0edd05 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "ವೈಶಿಷ್ಟ್ಯ ಲಭ್ಯವಿಲ್ಲ" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "ಫೈಲ್ ಲಗತ್ತುಗಳಿಗಾಗಿ 1 ಜಿಬಿ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ಸಂಗ್ರಹ." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "ಎಲ್ಲಾ ಕಳುಹಿಸುತ್ತದೆ", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 2e40b8d7f23..9f6153cb314 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "더 알아보기" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "기능 사용할 수 없음" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1GB의 암호화된 파일 저장소." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "모든 Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "정말 \"잠그지 않음\" 옵션을 사용하시겠습니까? 잠금 옵션을 \"잠그지 않음\"으로 설정하면 사용자 보관함의 암호화 키를 사용자의 기기에 보관합니다. 이 옵션을 사용하기 전에 사용자의 기기가 잘 보호되어 있는 상태인지 확인하십시오." }, "vault": { - "message": "보관함" + "message": "보관함", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "마스터 비밀번호로 로그인" diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index 16f328d6240..d7612765f1a 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Sužinoti daugiau" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funkcija nepasiekiama" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB užšifruotos vietos diske failų prisegimams." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Patentuotos dviejų žingsnių prisijungimo parinktys, tokios kaip YubiKey ir Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Visi Sendai", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Ar jūs tikrai norite naudoti \"Niekada\" pasirinkimą? Nustačius savo užraktą į \"Niekada\", saugyklos šifravimo raktas bus laikomas jūsų įrenginyje. Jei norite naudotis šiuo pasirinkimu, užtikrinkite savo įrenginio saugą." }, "vault": { - "message": "Saugykla" + "message": "Saugykla", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Prisijungti su pagrindiniu slaptažodžiu" diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index 7800a4e9024..5624f89f5db 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Uzzināt vairāk" }, + "migrationsFailed": { + "message": "Atgadījās kļūda šifrēšanas iestatījumu atjaunināšanā." + }, + "updateEncryptionSettingsTitle": { + "message": "Atjaunini savus šifrēšanas iestatījumus" + }, + "updateEncryptionSettingsDesc": { + "message": "Jaunie ieteicamie šifrēšanas iestatījumi uzlabos Tava konta drošību. Jāievada sava galvenā parole, lai atjauninātu tagad." + }, + "confirmIdentityToContinue": { + "message": "Jāapliecina sava identitāte, lai turpinātu" + }, + "enterYourMasterPassword": { + "message": "Jāievada sava galvenā parole" + }, + "updateSettings": { + "message": "Atjaunināt Iestatījumus" + }, "featureUnavailable": { "message": "Iespēja nav pieejama" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrētas krātuves datņu pielikumiem." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrētas krātuves datņu pielikumiem.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Tādas slēgtā pirmavota divpakāpju pieteikšanās iespējas kā YubiKey un Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Saziņas informācija" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Visi Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Vai tiešām izmantot uzstādījumu \"Nekad\"? Uzstādot aizslēgšanas iespēju uz \"Nekad\", šifrēšanas atslēga tiek glabāta ierīcē. Ja šī iespēja tiek izmantota, jāpārliecinās, ka ierīce tiek pienācīgi aizsargāta." }, "vault": { - "message": "Glabātava" + "message": "Glabātava", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Pieteikties ar galveno paroli" diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 29e3cefee0c..684c4682aa0 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Saznaj više" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funkcija nije dostupna" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrovanog skladišta za priloge datoteka." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 662ce9a1fc6..e91ca21a686 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "കൂടുതൽ അറിയുക" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "സവിശേഷത ലഭ്യമല്ല" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "ഫയൽ അറ്റാച്ചുമെന്റുകൾക്കായി 1 GB എൻക്രിപ്റ്റുചെയ്‌ത സ്റ്റോറേജ്." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "എല്ലാം Send-കൾ", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index d607bb8d097..0211550b08d 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index bcbd26cede3..969e67d3560 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index 42fb6d479c0..35bd7750481 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Lær mer" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funksjonen er utilgjengelig" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB med kryptert fillagring." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Kontaktinformasjon" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alle Send-er", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Er du sikker på at du vil bruke alternativet «Aldri»? Ved å angi låsemulighetene til «Aldri» lagres hvelvets krypteringsnøkkel på enheten. Hvis du bruker dette alternativet, bør du sørge for at du holder enheten forsvarlig beskyttet." }, "vault": { - "message": "Hvelv" + "message": "Hvelv", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Logg inn med hovedpassord" diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index cce8f6a2ba5..b8038093f90 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 82b51b018c5..8833f59489a 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Meer informatie" }, + "migrationsFailed": { + "message": "Er is een fout opgetreden bij het bijwerken van de versleutelingsinstellingen." + }, + "updateEncryptionSettingsTitle": { + "message": "Je versleutelingsinstellingen bijwerken" + }, + "updateEncryptionSettingsDesc": { + "message": "De nieuwe aanbevolen versleutelingsinstellingen verbeteren de beveiliging van je account. Voer je hoofdwachtwoord in om nu bij te werken." + }, + "confirmIdentityToContinue": { + "message": "Bevestig je identiteit om door te gaan" + }, + "enterYourMasterPassword": { + "message": "Voer je hoofdwachtwoord in" + }, + "updateSettings": { + "message": "Instellingen bijwerken" + }, "featureUnavailable": { "message": "Functionaliteit niet beschikbaar" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB versleutelde opslag voor bijlagen." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ versleutelde opslag voor bijlagen.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Eigen opties voor tweestapsaanmelding zoals YubiKey en Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact informatie" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alle Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Weet je zeker dat je de optie \"Nooit\" wilt gebruiken? De vergrendelingsoptie \"Nooit\" bewaart de sleutel van je kluis op je apparaat. Als je deze optie gebruikt, moet je ervoor zorgen dat je je apparaat naar behoren beschermt." }, "vault": { - "message": "Kluis" + "message": "Kluis", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Inloggen met je hoofdwachtwoord" @@ -3631,7 +3663,7 @@ "message": "Import directly from browser" }, "browserProfile": { - "message": "Browser Profile" + "message": "Browserprofiel" }, "seeDetailedInstructions": { "message": "Zie gedetailleerde instructies op onze helpsite op", diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 08567979e8b..5264ce8c561 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Lær meir" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funksjon er utilgjengeleg" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alle Send-ar", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index 4ca05acaac5..b145306e14d 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index c05e7f05cb1..4cb6650e2c7 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Dowiedz się więcej" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funkcja jest niedostępna" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB miejsca na zaszyfrowane załączniki." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Specjalne opcje logowania dwustopniowego, takie jak YubiKey i Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Informacje kontaktowe" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Wszystkie wysyłki", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Czy na pewno chcesz użyć opcji „Nigdy”? Ustawienie blokady na „Nigdy” spowoduje przechowywanie klucza szyfrowania sejfu na urządzeniu. Upewnij się, że urządzenie jest odpowiednio chronione." }, "vault": { - "message": "Sejf" + "message": "Sejf", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Logowanie hasłem głównym" diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index e351bfb7dba..dc64f1b701b 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Saiba mais" }, + "migrationsFailed": { + "message": "Ocorreu um erro ao atualizar as configurações de criptografia." + }, + "updateEncryptionSettingsTitle": { + "message": "Atualize suas configurações de criptografia" + }, + "updateEncryptionSettingsDesc": { + "message": "As novas configurações de criptografia recomendadas melhorarão a segurança da sua conta. Digite sua senha principal para atualizar agora." + }, + "confirmIdentityToContinue": { + "message": "Confirme sua identidade para continuar" + }, + "enterYourMasterPassword": { + "message": "Digite sua senha principal" + }, + "updateSettings": { + "message": "Atualizar configurações" + }, "featureUnavailable": { "message": "Recurso indisponível" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB de armazenamento criptografado para anexos de arquivos." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ de armazenamento criptografado para anexos de arquivo.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opções proprietárias de autenticação em duas etapas como YubiKey e Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Informações de contato" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Todos os Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Você tem certeza que deseja usar a opção \"Nunca\"? Ao usar o \"Nunca\", a chave de criptografia do seu cofre é armazenada no seu dispositivo. Se você usar esta opção, deve garantir que mantém seu dispositivo devidamente protegido." }, "vault": { - "message": "Cofre" + "message": "Cofre", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Conectar-se com senha principal" diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index de0427ddab0..c0e396c63c4 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Saber mais" }, + "migrationsFailed": { + "message": "Ocorreu um erro ao atualizar as definições de encriptação." + }, + "updateEncryptionSettingsTitle": { + "message": "Atualize as suas definições de encriptação" + }, + "updateEncryptionSettingsDesc": { + "message": "As novas definições de encriptação recomendadas irão melhorar a segurança da sua conta. Introduza a sua palavra-passe mestra para atualizar agora." + }, + "confirmIdentityToContinue": { + "message": "Confirme a sua identidade para continuar" + }, + "enterYourMasterPassword": { + "message": "Introduza a sua palavra-passe mestra" + }, + "updateSettings": { + "message": "Atualizar definições" + }, "featureUnavailable": { "message": "Funcionalidade indisponível" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB de armazenamento encriptado para anexos de ficheiros." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ de armazenamento encriptado para anexos de ficheiros.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opções proprietárias de verificação de dois passos, como YubiKey e Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Informações de contacto" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Todos os Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Tem a certeza de que deseja utilizar a opção \"Nunca\"? Ao definir as opções de bloqueio para \"Nunca\" armazena a chave de encriptação do seu cofre no seu dispositivo. Se utilizar esta opção deve assegurar-se de que mantém o seu dispositivo devidamente protegido." }, "vault": { - "message": "Cofre" + "message": "Cofre", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Iniciar sessão com a palavra-passe mestra" @@ -3048,7 +3080,7 @@ "message": "Será notificado quando o pedido for aprovado" }, "needAnotherOption": { - "message": "O início de sessão com o dispositivo deve ser ativado nas definições da aplicação Bitwarden. Precisa de outra opção?" + "message": "O início de sessão com o dispositivo deve ser ativado nas definições da app Bitwarden. Precisa de outra opção?" }, "viewAllLogInOptions": { "message": "Ver todas as opções de início de sessão" diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index a72ce3547e9..d2e589836e0 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Aflați mai multe" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funcție indisponibilă" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB spațiu de stocare criptat pentru atașamente de fișiere." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Toate Send-urile", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Sunteți sigur că doriți să folosiți opțiunea „Niciodată”? Setarea opțiunilor de blocare la „Niciodată” stochează cheia de criptare a seifului pe dispozitivul dumneavoastră. Dacă utilizați această opțiune, trebuie să vă asigurați că vă păstrați dispozitivul protejat corespunzător." }, "vault": { - "message": "Seif" + "message": "Seif", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Autentificați-vă cu parola principală" diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 914bb603630..a59ae2282d5 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Подробнее" }, + "migrationsFailed": { + "message": "Произошла ошибка при обновлении настроек шифрования." + }, + "updateEncryptionSettingsTitle": { + "message": "Обновите настройки шифрования" + }, + "updateEncryptionSettingsDesc": { + "message": "Новые рекомендуемые настройки шифрования повысят безопасность вашего аккаунта. Введите мастер-пароль, чтобы обновить сейчас." + }, + "confirmIdentityToContinue": { + "message": "Подтвердите вашу личность, чтобы продолжить" + }, + "enterYourMasterPassword": { + "message": "Введите ваш мастер-пароль" + }, + "updateSettings": { + "message": "Обновить настройки" + }, "featureUnavailable": { "message": "Функция недоступна" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 ГБ зашифрованного хранилища для вложенных файлов." }, + "premiumSignUpStorageV2": { + "message": "Зашифрованного хранилища для вложенных файлов: $SIZE$", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Проприетарные варианты двухэтапной аутентификации, такие как YubiKey или Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Контактная информация" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Все Send’ы", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Вы действительно хотите отключить блокировку хранилища? В этом случае ключ шифрования вашего хранилища будет сохранен на вашем устройстве. Отключая блокировку, вы должны убедиться, что ваше устройство надежно защищено." }, "vault": { - "message": "Хранилище" + "message": "Хранилище", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Войти с мастер-паролем" diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index a83b2cbf536..51333386f8a 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 0b14b961bbb..0e62a8ee8b0 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Zistiť viac" }, + "migrationsFailed": { + "message": "Pri aktualizácii nastavení šifrovania došlo k chybe." + }, + "updateEncryptionSettingsTitle": { + "message": "Aktualizujte nastavenie šifrovania" + }, + "updateEncryptionSettingsDesc": { + "message": "Nové odporúčané nastavenia šifrovania zlepšia bezpečnosť vášho účtu. Ak ich chcete aktualizovať teraz, zadajte hlavné heslo." + }, + "confirmIdentityToContinue": { + "message": "Ak chcete pokračovať, potvrďte svoju identitu" + }, + "enterYourMasterPassword": { + "message": "Zadajte hlavné heslo" + }, + "updateSettings": { + "message": "Aktualizovať nastavenia" + }, "featureUnavailable": { "message": "Funkcia nie je k dispozícii" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrovaného úložiska." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrovaného úložiska na prílohy.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietárne možnosti dvojstupňového prihlásenia ako napríklad YubiKey a Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Kontaktné informácie" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Všetky Sendy", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Ste si istí, že chcete použiť možnosť \"Nikdy\"? Táto predvoľba ukladá šifrovací kľúč od trezora priamo na zariadení. Ak použijete túto možnosť, mali by ste svoje zariadenie náležite zabezpečiť." }, "vault": { - "message": "Trezor" + "message": "Trezor", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Prihlásenie pomocou hlavného hesla" diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index 353c6858afa..c640320ab1a 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Več o tem" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Funkcija ni na voljo" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Vsi Sendsi", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 1bc4a0ed016..4e69efe726f 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Сазнај више" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Функција је недоступна" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1ГБ шифровано складиште за прилоге." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Приоритарне опције пријаве у два корака као што су YubiKey и Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Контакт подаци" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Сва слања", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Да ли сте сигурни да желите да користите опцију „Никад“? Ако поставите опције закључавања на „Никада“, на вашем уређају се чува кључ за шифровање сефа. Ако користите ову опцију, осигурајте да је уређај правилно заштићен." }, "vault": { - "message": "Сеф" + "message": "Сеф", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Пријавите се са главном лозинком" diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 93d56419ae3..6f3e68c8959 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Läs mer" }, + "migrationsFailed": { + "message": "Ett fel inträffade när krypteringsinställningarna skulle uppdateras." + }, + "updateEncryptionSettingsTitle": { + "message": "Uppdatera dina krypteringsinställningar" + }, + "updateEncryptionSettingsDesc": { + "message": "De nya rekommenderade krypteringsinställningarna kommer att förbättra säkerheten för ditt konto. Ange ditt huvudlösenord för att uppdatera nu." + }, + "confirmIdentityToContinue": { + "message": "Bekräfta din identitet för att fortsätta" + }, + "enterYourMasterPassword": { + "message": "Ange ditt huvudlösenord" + }, + "updateSettings": { + "message": "Uppdatera inställningar" + }, "featureUnavailable": { "message": "Funktion ej tillgänglig" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB krypterad lagring." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ krypterad lagring för filbilagor.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Premium-alternativ för tvåstegsverifiering, såsom YubiKey och Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Kontaktinformation" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Alla Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Är du säker på att du vill använda alternativet ”Aldrig”? Att ställa in låsnings-alternativet till ”Aldrig” lagrar valvets krypteringsnyckel på datorn. Om du använder det här alternativet bör du se till att du håller datorn ordentligt skyddad." }, "vault": { - "message": "Valv" + "message": "Valv", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Logga in med huvudlösenord" diff --git a/apps/desktop/src/locales/ta/messages.json b/apps/desktop/src/locales/ta/messages.json index 2f9d12917d6..a83867a9eff 100644 --- a/apps/desktop/src/locales/ta/messages.json +++ b/apps/desktop/src/locales/ta/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "மேலும் அறியவும்" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "வசதி கிடைக்கவில்லை" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "கோப்பு இணைப்புகளுக்கு 1 GB குறியாக்கப்பட்ட சேமிப்பகம்." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey மற்றும் Duo போன்ற பிரத்யேக இரண்டு-படி உள்நுழைவு விருப்பங்கள்." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "தொடர்புத் தகவல்" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "அனைத்து அனுப்புதல்களும்", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "\"ஒருபோதும் இல்லை\" விருப்பத்தைப் பயன்படுத்த விரும்புகிறீர்களா? உங்கள் பூட்டு விருப்பங்களை \"ஒருபோதும் இல்லை\" என அமைப்பது உங்கள் வால்ட்டின் குறியாக்க சாவியை உங்கள் சாதனத்தில் சேமிக்கிறது. இந்த விருப்பத்தைப் பயன்படுத்தினால், உங்கள் சாதனத்தை நீங்கள் சரியாகப் பாதுகாப்பதை உறுதி செய்ய வேண்டும்." }, "vault": { - "message": "வால்ட்" + "message": "வால்ட்", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "முதன்மை கடவுச்சொல்லுடன் உள்நுழைக" diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index d607bb8d097..0211550b08d 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "All Sends", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index d794ace629c..f5bbde79a86 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "เรียนรู้เพิ่มเติม" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Feature Unavailable" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 GB of encrypted file storage." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Contact information" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "ส่งทั้งหมด", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." }, "vault": { - "message": "Vault" + "message": "Vault", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Log in with master password" diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index ac67b177cbf..bb0b6f2fd51 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Daha fazla bilgi al" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Özellik kullanılamıyor" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "Dosya ekleri için 1 GB şifrelenmiş depolama." }, + "premiumSignUpStorageV2": { + "message": "Dosya ekleri için $SIZE$ şifrelenmiş depolama.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey ve Duo gibi marka bazlı iki aşamalı giriş seçenekleri." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "İletişim bilgileri" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Tüm Send'ler", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "\"Asla\" seçeneğini kullanmak istediğinizden emin misiniz? Kilit seçeneklerinizi \"Asla\" olarak ayarlarsanız kasanızın şifreleme anahtarı cihazınızda saklanacaktır. Bu seçeneği kullanırsanız cihazınızı çok iyi korumalısınız." }, "vault": { - "message": "Kasa" + "message": "Kasa", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Ana parola ile giriş yap" diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index 7ed0710ca74..bed09352f03 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Докладніше" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Функція недоступна" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1 ГБ зашифрованого сховища для файлів." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Додаткові можливості двоетапної авторизації, як-от YubiKey та Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Контактна інформація" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Усі відправлення", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Ви впевнені, що ніколи не хочете блокувати? Встановивши параметр блокування \"Ніколи\", ключ шифрування сховища зберігатиметься на вашому пристрої. Користуючись цим параметром, ви маєте бути впевнені в тому, що ваш пристрій надійно захищений." }, "vault": { - "message": "Сховище" + "message": "Сховище", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Увійти з головним паролем" diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 8bf88aba458..30038f046db 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "Tìm hiểu thêm" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "Tính năng không có sẵn" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "1GB bộ nhớ lưu trữ được mã hóa cho các tệp đính kèm." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Các tùy chọn xác minh hai bước như YubiKey và Duo." }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "Thông tin liên hệ" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "Tất cả Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "Bạn có chắc chắn muốn chọn \"Không bao giờ\" không? Lựa chọn này sẽ lưu khóa mã hóa kho của bạn trực tiếp trên thiết bị. Hãy nhớ bảo vệ thiết bị của bạn thật cẩn thận nếu bạn chọn tùy chọn này." }, "vault": { - "message": "Kho lưu trữ" + "message": "Kho lưu trữ", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "Đăng nhập bằng mật khẩu chính" diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 70711c7aa4e..80965415475 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "进一步了解" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "功能不可用" }, @@ -1488,7 +1506,16 @@ "message": "注册高级会员将获得:" }, "premiumSignUpStorage": { - "message": "1 GB 文件附件加密存储。" + "message": "1 GB 文件附件加密存储空间。" + }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ 文件附件加密存储空间。", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } }, "premiumSignUpTwoStepOptions": { "message": "专有的两步登录选项,如 YubiKey 和 Duo。" @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "联系信息" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "所有的 Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "确定要使用「从不」选项吗?将锁定选项设置为「从不」会将密码库的加密密钥存储在您的设备上。如果使用此选项,您必须确保您的设备安全。" }, "vault": { - "message": "密码库" + "message": "密码库", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "使用主密码登录" diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 61fc00543ed..e412adf9e5b 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -1093,6 +1093,24 @@ "learnMore": { "message": "了解更多" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "featureUnavailable": { "message": "功能不可用" }, @@ -1490,6 +1508,15 @@ "premiumSignUpStorage": { "message": "用於檔案附件的 1 GB 的加密檔案儲存空間。" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "專有的兩步驟登入選項,例如 YubiKey 和 Duo。" }, @@ -2228,6 +2255,10 @@ "contactInfo": { "message": "聯絡資訊" }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, "allSends": { "message": "所有 Send", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." @@ -2991,7 +3022,8 @@ "message": "您確定要使用「永不」選項嗎?將鎖定選項設定為「永不」會將密碼庫的加密金鑰儲存在您的裝置上。如果使用此選項,應確保您的裝置是安全的。" }, "vault": { - "message": "密碼庫" + "message": "密碼庫", + "description": "'Vault' is a noun and refers to the Bitwarden Vault feature." }, "loginWithMasterPassword": { "message": "使用主密碼登入" From e5fa527af1754760373adfb9df9dbd66f8dff7db Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 12:32:12 +0100 Subject: [PATCH 28/89] Autosync the updated translations (#17825) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 30 ++++++++++ apps/browser/src/_locales/az/messages.json | 42 +++++++++++-- apps/browser/src/_locales/be/messages.json | 30 ++++++++++ apps/browser/src/_locales/bg/messages.json | 30 ++++++++++ apps/browser/src/_locales/bn/messages.json | 30 ++++++++++ apps/browser/src/_locales/bs/messages.json | 30 ++++++++++ apps/browser/src/_locales/ca/messages.json | 30 ++++++++++ apps/browser/src/_locales/cs/messages.json | 30 ++++++++++ apps/browser/src/_locales/cy/messages.json | 30 ++++++++++ apps/browser/src/_locales/da/messages.json | 30 ++++++++++ apps/browser/src/_locales/de/messages.json | 34 ++++++++++- apps/browser/src/_locales/el/messages.json | 30 ++++++++++ apps/browser/src/_locales/en_GB/messages.json | 30 ++++++++++ apps/browser/src/_locales/en_IN/messages.json | 30 ++++++++++ apps/browser/src/_locales/es/messages.json | 30 ++++++++++ apps/browser/src/_locales/et/messages.json | 30 ++++++++++ apps/browser/src/_locales/eu/messages.json | 30 ++++++++++ apps/browser/src/_locales/fa/messages.json | 30 ++++++++++ apps/browser/src/_locales/fi/messages.json | 30 ++++++++++ apps/browser/src/_locales/fil/messages.json | 30 ++++++++++ apps/browser/src/_locales/fr/messages.json | 30 ++++++++++ apps/browser/src/_locales/gl/messages.json | 30 ++++++++++ apps/browser/src/_locales/he/messages.json | 30 ++++++++++ apps/browser/src/_locales/hi/messages.json | 30 ++++++++++ apps/browser/src/_locales/hr/messages.json | 30 ++++++++++ apps/browser/src/_locales/hu/messages.json | 30 ++++++++++ apps/browser/src/_locales/id/messages.json | 30 ++++++++++ apps/browser/src/_locales/it/messages.json | 42 +++++++++++-- apps/browser/src/_locales/ja/messages.json | 30 ++++++++++ apps/browser/src/_locales/ka/messages.json | 30 ++++++++++ apps/browser/src/_locales/km/messages.json | 30 ++++++++++ apps/browser/src/_locales/kn/messages.json | 30 ++++++++++ apps/browser/src/_locales/ko/messages.json | 30 ++++++++++ apps/browser/src/_locales/lt/messages.json | 30 ++++++++++ apps/browser/src/_locales/lv/messages.json | 30 ++++++++++ apps/browser/src/_locales/ml/messages.json | 30 ++++++++++ apps/browser/src/_locales/mr/messages.json | 30 ++++++++++ apps/browser/src/_locales/my/messages.json | 30 ++++++++++ apps/browser/src/_locales/nb/messages.json | 30 ++++++++++ apps/browser/src/_locales/ne/messages.json | 30 ++++++++++ apps/browser/src/_locales/nl/messages.json | 30 ++++++++++ apps/browser/src/_locales/nn/messages.json | 30 ++++++++++ apps/browser/src/_locales/or/messages.json | 30 ++++++++++ apps/browser/src/_locales/pl/messages.json | 30 ++++++++++ apps/browser/src/_locales/pt_BR/messages.json | 30 ++++++++++ apps/browser/src/_locales/pt_PT/messages.json | 30 ++++++++++ apps/browser/src/_locales/ro/messages.json | 30 ++++++++++ apps/browser/src/_locales/ru/messages.json | 30 ++++++++++ apps/browser/src/_locales/si/messages.json | 30 ++++++++++ apps/browser/src/_locales/sk/messages.json | 30 ++++++++++ apps/browser/src/_locales/sl/messages.json | 30 ++++++++++ apps/browser/src/_locales/sr/messages.json | 30 ++++++++++ apps/browser/src/_locales/sv/messages.json | 30 ++++++++++ apps/browser/src/_locales/ta/messages.json | 30 ++++++++++ apps/browser/src/_locales/te/messages.json | 30 ++++++++++ apps/browser/src/_locales/th/messages.json | 30 ++++++++++ apps/browser/src/_locales/tr/messages.json | 30 ++++++++++ apps/browser/src/_locales/uk/messages.json | 30 ++++++++++ apps/browser/src/_locales/vi/messages.json | 60 ++++++++++++++----- apps/browser/src/_locales/zh_CN/messages.json | 32 +++++++++- apps/browser/src/_locales/zh_TW/messages.json | 30 ++++++++++ 61 files changed, 1860 insertions(+), 30 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 03d5eb0a9f6..452cbafe6d5 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "معرفة المزيد" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "مفتاح المصادقة (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 جيغابايت وحدة تخزين مشفرة لمرفقات الملفات." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "الوصول الطارئ." }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 7dbd1ba3e7c..c4197f831d3 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -586,7 +586,7 @@ "message": "Arxivlənmiş elementlər ümumi axtarış nəticələrindən və avto-doldurma təkliflərindən xaric ediləcək. Bu elementi arxivləmək istədiyinizə əminsiniz?" }, "upgradeToUseArchive": { - "message": "A premium membership is required to use Archive." + "message": "Arxivi istifadə etmək üçün premium üzvlük tələb olunur." }, "edit": { "message": "Düzəliş et" @@ -598,7 +598,7 @@ "message": "Hamısına bax" }, "showAll": { - "message": "Show all" + "message": "Hamısını göstər" }, "viewLess": { "message": "Daha azına bax" @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Daha ətraflı" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Kimlik doğrulayıcı açarı (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "Fayl qoşmaları üçün 1 GB şifrələnmiş anbar sahəsi" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Fövqəladə hal erişimi." }, @@ -1874,7 +1904,7 @@ "message": "Son istifadə ili" }, "monthly": { - "message": "month" + "message": "ay" }, "expiration": { "message": "Bitmə vaxtı" @@ -4912,7 +4942,7 @@ "message": "Premium" }, "unlockFeaturesWithPremium": { - "message": "Unlock reporting, emergency access, and more security features with Premium." + "message": "Premium ilə şikayət göndərmə, fövqəladə hal erişimi və daha çox təhlükəsizlik özəlliyinin kilidini açın." }, "freeOrgsCannotUseAttachments": { "message": "Ödənişsiz təşkilatlar qoşmaları istifadə edə bilməz" @@ -5825,10 +5855,10 @@ "message": "\"Premium\"a yüksəlt" }, "unlockAdvancedSecurity": { - "message": "Unlock advanced security features" + "message": "Qabaqcıl təhlükəsizlik özəlliklərinin kilidini aç" }, "unlockAdvancedSecurityDesc": { - "message": "A Premium subscription gives you more tools to stay secure and in control" + "message": "Premium abunəlik, güvəndə qalmağınız və nəzarəti əlinizdə saxlamağınız üçün sizə daha çox alət verir" }, "explorePremium": { "message": "Premium-u kəşf et" diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 89651f0038e..806aedfab27 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Даведацца больш" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Ключ аўтэнтыфікацыі (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 ГБ зашыфраванага сховішча для далучаных файлаў." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Экстранны доступ." }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index b40f4b91cb4..76b20f8bd2e 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Научете повече" }, + "migrationsFailed": { + "message": "Възникна грешка при обновяването на настройките за шифроване." + }, + "updateEncryptionSettingsTitle": { + "message": "Обновете настройките си за шифроване" + }, + "updateEncryptionSettingsDesc": { + "message": "Новите препоръчани настройки за шифроване ще подобрят сигурността на акаунта Ви. Въведете главната си парола, за да ги обновите сега." + }, + "confirmIdentityToContinue": { + "message": "Потвърдете самоличността си, за да продължите" + }, + "enterYourMasterPassword": { + "message": "Въведете главната си парола" + }, + "updateSettings": { + "message": "Обновяване на настройките" + }, + "later": { + "message": "По-късно" + }, "authenticatorKeyTotp": { "message": "Удостоверителен ключ (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB пространство за файлове, които се шифрират." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ пространство за файлове, които се шифрират.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Авариен достъп" }, diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 4f8e7054305..4845282e825 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "আরও জানুন" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "প্রমাণীকরণকারী কী (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "ফাইল সংযুক্তির জন্য ১ জিবি এনক্রিপ্টেড স্থান।" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 9d5631c47e2..cff1dd150cb 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 255263a6da7..ff0e2de51af 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Més informació" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Clau d'autenticació (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB d'emmagatzematge xifrat per als fitxers adjunts." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Accés d’emergència." }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index eff2c6c0ea7..fa8dc426c05 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Dozvědět se více" }, + "migrationsFailed": { + "message": "Došlo k chybě při aktualizaci nastavení šifrování." + }, + "updateEncryptionSettingsTitle": { + "message": "Aktualizovat nastavení šifrování" + }, + "updateEncryptionSettingsDesc": { + "message": "Nové doporučené nastavení šifrování zlepší bezpečnost Vašeho účtu. Pokud chcete aktualizovat nyní, zadejte hlavní heslo." + }, + "confirmIdentityToContinue": { + "message": "Pro pokračování potvrďte svou identitu" + }, + "enterYourMasterPassword": { + "message": "Zadejte své hlavní heslo" + }, + "updateSettings": { + "message": "Aktualizovat nastavení" + }, + "later": { + "message": "Později" + }, "authenticatorKeyTotp": { "message": "Autentizační klíč (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB šifrovaného úložiště pro přílohy." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrovaného úložiště pro přílohy.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Nouzový přístup" }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 99fcdffcc97..45f91f5ccc7 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Dysgu mwy" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "Storfa 1GB wedi'i hamgryptio ar gyfer atodiadau ffeiliau." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 865e6ff7dda..50d79ff1f9d 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Lær mere" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Autentificeringsnøgle (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB krypteret lager til vedhæftede filer." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Nødadgang" }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index c013e4516ed..969f8c63de3 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Erfahre mehr" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authentifizierungsschlüssel (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB verschlüsselter Speicherplatz für Dateianhänge." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ verschlüsselter Speicher für Dateianhänge.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Notfallzugriff." }, @@ -2446,7 +2476,7 @@ } }, "topLayerHijackWarning": { - "message": "Diese Seite stört die Bitwarden-Nutzung. Das Bitwarden Inline-Menü wurde aus Sicherheitsgründen vorübergehend deaktiviert." + "message": "Diese Seite beeinträchtigt die Nutzung von Bitwarden. Das Bitwarden Inline-Menü wurde aus Sicherheitsgründen vorübergehend deaktiviert." }, "setMasterPassword": { "message": "Master-Passwort festlegen" @@ -5813,7 +5843,7 @@ "message": "Notfallzugriff" }, "breachMonitoring": { - "message": "Datenleck-Überwachung" + "message": "Datendiebstahl-Überwachung" }, "andMoreFeatures": { "message": "Und mehr!" diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 476a6165a8e..2be53da65ec 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Μάθετε περισσότερα" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Κλειδί επαλήθευσης (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB κρυπτογραφημένο αποθηκευτικό χώρο για συνημμένα αρχεία." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Πρόσβαση έκτακτης ανάγκης." }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 103d45f0685..63d9214632a 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access" }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 2713381986c..9ef5cb2a061 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access" }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index e19bd11ba28..92f6226a3de 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Más información" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Clave de autenticación (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB de espacio cifrado en disco para adjuntos." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Acceso de emergencia." }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 7a9737f71ff..bade6b0dff9 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Loe edasi" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Autentimise võti (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB ulatuses krüpteeritud salvestusruum." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index b61213da989..90cfc13f6ef 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Gehiago ikasi" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Autentifikazio-gakoa (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "Eranskinentzako 1GB-eko zifratutako biltegia." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 550de006cf6..7a4c8744429 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "بیشتر بدانید" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "کلید احراز هویت (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "۱ گیگابایت فضای ذخیره‌سازی رمزگذاری شده برای پیوست‌های پرونده." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "دسترسی اضطراری." }, diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index bdf2ebd641c..d7f0f600b9e 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Lue lisää" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Todennusavain (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 Gt salattua tallennustilaa tiedostoliitteille." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Varmuuskäyttö" }, diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 31284265b2e..50964716ad0 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Matuto nang higit pa" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Susi ng Authenticator (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage para sa mga file attachment." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index dadcd0c041e..6ddf7ea5873 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "En savoir plus" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Clé Authenticator (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 Go de stockage chiffré pour les fichiers joints." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Accès d'urgence." }, diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index bd657b9d4b7..5695ae16035 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Máis información" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Clave de autenticación (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB de almacenamento cifrado para arquivos anexos." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Acceso de emerxencia." }, diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 2e9243206b9..67ca71338b2 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "למידע נוסף" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "מפתח מאמת (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 ג'יגה של מקום אחסון עבור קבצים מצורפים." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "גישת חירום." }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 58db7ac8ad6..b839e31cd96 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "अधिक जानें" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator Key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB of encrypted file storage." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index 8a5a09aec9c..da78924b1eb 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Saznaj više" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Ključ autentifikatora (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB šifriranog prostora za pohranu podataka." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Pristup u nuždi." }, diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index bacda584ba1..388a069e05a 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Tudjon meg többet" }, + "migrationsFailed": { + "message": "Hiba történt a titkosítási beállítások frissítésekor." + }, + "updateEncryptionSettingsTitle": { + "message": "A titkosítási beállítások frissítése" + }, + "updateEncryptionSettingsDesc": { + "message": "Az új ajánlott titkosítási beállítások javítják a fiók biztonságát. Adjuk meg a mesterjelszót a frissítéshez most." + }, + "confirmIdentityToContinue": { + "message": "A folytatáshoz meg kell erősíteni a személyazonosságot." + }, + "enterYourMasterPassword": { + "message": "Mesterjelszó megadása" + }, + "updateSettings": { + "message": "Beállítások frissítése" + }, + "later": { + "message": "Később" + }, "authenticatorKeyTotp": { "message": "Hitelesítő kulcs (egyszeri időalapú)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB titkosított tárhely a fájlmellékleteknek." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ titkosított tárhely a fájlmellékletekhez.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Sürgősségi hozzáférés" }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 88147f804d1..d18b25c51ed 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Pelajari lebih lanjut" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Kunci Otentikasi (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB penyimpanan berkas yang dienkripsi." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Akses darurat." }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index d4d032737b8..9bb75d7f449 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -35,7 +35,7 @@ "message": "La tua organizzazione richiede un accesso Single Sign-On (SSO)." }, "welcomeBack": { - "message": "Bentornato/a" + "message": "Bentornato" }, "setAStrongPassword": { "message": "Imposta una password robusta" @@ -586,7 +586,7 @@ "message": "Gli elementi archiviati sono esclusi dai risultati di ricerca e suggerimenti di autoriempimento. Vuoi davvero archiviare questo elemento?" }, "upgradeToUseArchive": { - "message": "A premium membership is required to use Archive." + "message": "Per utilizzare Archivio è necessario un abbonamento premium." }, "edit": { "message": "Modifica" @@ -598,7 +598,7 @@ "message": "Mostra tutto" }, "showAll": { - "message": "Show all" + "message": "Mostra tutto" }, "viewLess": { "message": "Vedi meno" @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Ulteriori informazioni" }, + "migrationsFailed": { + "message": "Si è verificato un errore durante l'aggiornamento delle impostazioni di cifratura." + }, + "updateEncryptionSettingsTitle": { + "message": "Aggiorna le impostazioni di crittografia" + }, + "updateEncryptionSettingsDesc": { + "message": "Le nuove impostazioni di crittografia consigliate miglioreranno la sicurezza del tuo account. Inserisci la tua password principale per aggiornare." + }, + "confirmIdentityToContinue": { + "message": "Conferma la tua identità per continuare" + }, + "enterYourMasterPassword": { + "message": "Inserisci la tua password principale" + }, + "updateSettings": { + "message": "Aggiorna impostazioni" + }, + "later": { + "message": "Più tardi" + }, "authenticatorKeyTotp": { "message": "Chiave di autenticazione (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB di spazio di archiviazione crittografato per gli allegati." }, + "premiumSignUpStorageV2": { + "message": "Archivio crittografato di $SIZE$ per allegati.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Accesso di emergenza." }, @@ -1874,7 +1904,7 @@ "message": "Anno di scadenza" }, "monthly": { - "message": "month" + "message": "mese" }, "expiration": { "message": "Scadenza" @@ -5825,10 +5855,10 @@ "message": "Aggiorna a Premium" }, "unlockAdvancedSecurity": { - "message": "Unlock advanced security features" + "message": "Sblocca funzionalità di sicurezza avanzate" }, "unlockAdvancedSecurityDesc": { - "message": "A Premium subscription gives you more tools to stay secure and in control" + "message": "Un abbonamento Premium ti offre più strumenti per rimanere sicuro e in controllo" }, "explorePremium": { "message": "Scopri Premium" diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index c13b139e13a..0b0883beaf3 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "さらに詳しく" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "認証キー (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1GB の暗号化されたファイルストレージ" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "緊急アクセス" }, diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index a54a0f2c657..ebb01f095f3 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "გაიგეთ მეტი" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index f829937ac51..684a04d9175 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index bd2be23828c..05ea413b522 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "ದೃಢೀಕರಣ ಕೀ (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "ಫೈಲ್ ಲಗತ್ತುಗಳಿಗಾಗಿ 1 ಜಿಬಿ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ಸಂಗ್ರಹ." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 1ad08accfc9..b35fe8283f7 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "더 알아보기" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "인증 키 (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1GB의 암호화된 파일 저장소." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "비상 접근" }, diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 46ffb24e3df..7fcc2df0330 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Sužinoti daugiau" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Vienkartinio autentifikavimo raktas (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB užšifruotos vietos diske bylų prisegimams." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 754781dc4f7..a719320fc8c 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Uzzināt vairāk" }, + "migrationsFailed": { + "message": "Atgadījās kļūda šifrēšanas iestatījumu atjaunināšanā." + }, + "updateEncryptionSettingsTitle": { + "message": "Atjaunini savus šifrēšanas iestatījumus" + }, + "updateEncryptionSettingsDesc": { + "message": "Jaunie ieteicamie šifrēšanas iestatījumi uzlabos Tava konta drošību. Jāievada sava galvenā parole, lai atjauninātu tagad." + }, + "confirmIdentityToContinue": { + "message": "Jāapliecina sava identitāte, lai turpinātu" + }, + "enterYourMasterPassword": { + "message": "Jāievada sava galvenā parole" + }, + "updateSettings": { + "message": "Atjaunināt Iestatījumus" + }, + "later": { + "message": "Vēlāk" + }, "authenticatorKeyTotp": { "message": "Autentificētāja atslēga (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB šifrētas krātuves datņu pielikumiem." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrētas krātuves datņu pielikumiem.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Ārkārtas piekļuve" }, diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 2f7f8d30e74..b72d82cd93f 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "കൂടുതലറിവ് നേടുക" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "ഓതന്റിക്കേറ്റർ കീ (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "ഫയൽ അറ്റാച്ചുമെന്റുകൾക്കായി 1 ജിബി എൻക്രിപ്റ്റുചെയ്‌ത സംഭരണം." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index 70f8fe5393c..03c3b4a70ae 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index f829937ac51..684a04d9175 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 0eba9c953a3..6226d26312f 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Lær mer" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Autentiseringsnøkkel (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB med kryptert fillagring for filvedlegg." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Nødtilgang." }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index f829937ac51..684a04d9175 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 601aac16f94..04e6e1bb7f3 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Meer informatie" }, + "migrationsFailed": { + "message": "Er is een fout opgetreden bij het bijwerken van de versleutelingsinstellingen." + }, + "updateEncryptionSettingsTitle": { + "message": "Je versleutelingsinstellingen bijwerken" + }, + "updateEncryptionSettingsDesc": { + "message": "De nieuwe aanbevolen versleutelingsinstellingen verbeteren de beveiliging van je account. Voer je hoofdwachtwoord in om nu bij te werken." + }, + "confirmIdentityToContinue": { + "message": "Bevestig je identiteit om door te gaan" + }, + "enterYourMasterPassword": { + "message": "Voer je hoofdwachtwoord in" + }, + "updateSettings": { + "message": "Instellingen bijwerken" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticatiecode (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB versleutelde opslag voor bijlagen." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ versleutelde opslag voor bijlagen.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Noodtoegang." }, diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index f829937ac51..684a04d9175 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index f829937ac51..684a04d9175 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 9741f94da36..24729a2331b 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Dowiedz się więcej" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Klucz uwierzytelniający (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB miejsca na zaszyfrowane załączniki." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Dostęp awaryjny." }, diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index 319d415b612..c7a5300a873 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Saiba mais" }, + "migrationsFailed": { + "message": "Ocorreu um erro ao atualizar as configurações de criptografia." + }, + "updateEncryptionSettingsTitle": { + "message": "Atualize suas configurações de criptografia" + }, + "updateEncryptionSettingsDesc": { + "message": "As novas configurações de criptografia recomendadas melhorarão a segurança da sua conta. Digite sua senha principal para atualizar agora." + }, + "confirmIdentityToContinue": { + "message": "Confirme sua identidade para continuar" + }, + "enterYourMasterPassword": { + "message": "Digite sua senha principal" + }, + "updateSettings": { + "message": "Atualizar configurações" + }, + "later": { + "message": "Depois" + }, "authenticatorKeyTotp": { "message": "Chave do autenticador (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB de armazenamento criptografado para anexo de arquivos." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ de armazenamento criptografado para anexos de arquivo.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Acesso de emergência." }, diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 6b8568ddb1b..c03f3038f98 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Saber mais" }, + "migrationsFailed": { + "message": "Ocorreu um erro ao atualizar as definições de encriptação." + }, + "updateEncryptionSettingsTitle": { + "message": "Atualize as suas definições de encriptação" + }, + "updateEncryptionSettingsDesc": { + "message": "As novas definições de encriptação recomendadas irão melhorar a segurança da sua conta. Introduza a sua palavra-passe mestra para atualizar agora." + }, + "confirmIdentityToContinue": { + "message": "Confirme a sua identidade para continuar" + }, + "enterYourMasterPassword": { + "message": "Introduza a sua palavra-passe mestra" + }, + "updateSettings": { + "message": "Atualizar definições" + }, + "later": { + "message": "Mais tarde" + }, "authenticatorKeyTotp": { "message": "Chave de autenticação (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB de armazenamento encriptado para anexos de ficheiros." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ de armazenamento encriptado para anexos de ficheiros.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Acesso de emergência." }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index db7a1b8c657..85db8d8a4f3 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Aflați mai multe" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Cheie de autentificare (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB spațiu de stocare criptat pentru atașamente de fișiere." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 0535027daa9..58f2b372459 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Подробнее" }, + "migrationsFailed": { + "message": "Произошла ошибка при обновлении настроек шифрования." + }, + "updateEncryptionSettingsTitle": { + "message": "Обновите настройки шифрования" + }, + "updateEncryptionSettingsDesc": { + "message": "Новые рекомендуемые настройки шифрования повысят безопасность вашего аккаунта. Введите мастер-пароль, чтобы обновить сейчас." + }, + "confirmIdentityToContinue": { + "message": "Подтвердите вашу личность, чтобы продолжить" + }, + "enterYourMasterPassword": { + "message": "Введите ваш мастер-пароль" + }, + "updateSettings": { + "message": "Обновить настройки" + }, + "later": { + "message": "Позже" + }, "authenticatorKeyTotp": { "message": "Ключ аутентификатора (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 ГБ зашифрованного хранилища для вложенных файлов." }, + "premiumSignUpStorageV2": { + "message": "Зашифрованного хранилища для вложенных файлов: $SIZE$", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Экстренный доступ" }, diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index bb46b283322..ead646d0ac0 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "වැඩිදුර ඉගෙන ගන්න" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "සත්යාපන යතුර (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "ගොනු ඇමුණුම් සඳහා 1 GB සංකේතාත්මක ගබඩා." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 283442d95da..70620e6c5e5 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Zistiť viac" }, + "migrationsFailed": { + "message": "Pri aktualizácii nastavení šifrovania došlo k chybe." + }, + "updateEncryptionSettingsTitle": { + "message": "Aktualizujte nastavenie šifrovania" + }, + "updateEncryptionSettingsDesc": { + "message": "Nové odporúčané nastavenia šifrovania zlepšia bezpečnosť vášho účtu. Ak ich chcete aktualizovať teraz, zadajte hlavné heslo." + }, + "confirmIdentityToContinue": { + "message": "Ak chcete pokračovať, potvrďte svoju identitu" + }, + "enterYourMasterPassword": { + "message": "Zadajte hlavné heslo" + }, + "updateSettings": { + "message": "Aktualizovať nastavenia" + }, + "later": { + "message": "Neskôr" + }, "authenticatorKeyTotp": { "message": "Overovací kľúč (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB šifrovaného úložiska na prílohy." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrovaného úložiska na prílohy.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Núdzový prístup." }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 2d20050d7f1..4867f4b89f2 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Več o tem" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Ključ avtentikatorja (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB šifriranega prostora za shrambo podatkov." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 0c7562987fc..c04c113caca 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Сазнај више" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Једнократни код" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1ГБ шифровано складиште за прилоге." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Хитан приступ." }, diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index f5d55585b80..a6cf12541fd 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Läs mer" }, + "migrationsFailed": { + "message": "Ett fel inträffade när krypteringsinställningarna skulle uppdateras." + }, + "updateEncryptionSettingsTitle": { + "message": "Uppdatera dina krypteringsinställningar" + }, + "updateEncryptionSettingsDesc": { + "message": "De nya rekommenderade krypteringsinställningarna kommer att förbättra säkerheten för ditt konto. Ange ditt huvudlösenord för att uppdatera nu." + }, + "confirmIdentityToContinue": { + "message": "Bekräfta din identitet för att fortsätta" + }, + "enterYourMasterPassword": { + "message": "Ange ditt huvudlösenord" + }, + "updateSettings": { + "message": "Uppdatera inställningar" + }, + "later": { + "message": "Senare" + }, "authenticatorKeyTotp": { "message": "Autentiseringsnyckel (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB lagring av krypterade filer." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ krypterad lagring för filbilagor.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Nödåtkomst." }, diff --git a/apps/browser/src/_locales/ta/messages.json b/apps/browser/src/_locales/ta/messages.json index 4d185501855..934cb8e1a01 100644 --- a/apps/browser/src/_locales/ta/messages.json +++ b/apps/browser/src/_locales/ta/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "மேலும் அறிக" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "அங்கீகரிப்பு விசை (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "கோப்பு இணைப்புகளுக்கு 1 GB என்க்ரிப்ட் செய்யப்பட்ட ஸ்டோரேஜ்." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "அவசர அணுகல்." }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index f829937ac51..684a04d9175 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index ef6ba5b2077..bade59ad99b 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "เรียนรู้เพิ่มเติม" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Authenticator Key (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 GB of encrypted file storage." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Emergency access." }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index e6004ef387f..0ba7e2ffec3 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Daha fazla bilgi al" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Kimlik doğrulama anahtarı (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "Dosya ekleri için 1 GB şifrelenmiş depolama." }, + "premiumSignUpStorageV2": { + "message": "Dosya ekleri için $SIZE$ şifrelenmiş depolama.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Acil durum erişimi." }, diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index a1922a5abd8..147e63cce02 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Докладніше" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Ключ автентифікації (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1 ГБ зашифрованого сховища для файлів." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Екстрений доступ." }, diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 415cf474af0..a94a38ffb63 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -586,7 +586,7 @@ "message": "Các mục đã lưu trữ sẽ bị loại khỏi kết quả tìm kiếm chung và gợi ý tự động điền. Bạn có chắc chắn muốn lưu trữ mục này không?" }, "upgradeToUseArchive": { - "message": "A premium membership is required to use Archive." + "message": "Cần là thành viên premium để sử dụng Archive." }, "edit": { "message": "Sửa" @@ -598,10 +598,10 @@ "message": "Xem tất cả" }, "showAll": { - "message": "Show all" + "message": "Hiện tất cả" }, "viewLess": { - "message": "View less" + "message": "Ẩn bớt" }, "viewLogin": { "message": "Xem đăng nhập" @@ -806,10 +806,10 @@ "message": "Mỗi khi khóa máy" }, "onIdle": { - "message": "On system idle" + "message": "Khi hệ thống rãnh rỗi" }, "onSleep": { - "message": "On system sleep" + "message": "Khi hệ thống ngủ" }, "onRestart": { "message": "Mỗi khi khởi động lại trình duyệt" @@ -1406,6 +1406,27 @@ "learnMore": { "message": "Tìm hiểu thêm" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "Khóa xác thực (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "1GB bộ nhớ lưu trữ được mã hóa cho các tệp đính kèm." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ bộ nhớ lưu trữ được mã hóa cho các tệp đính kèm.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "Truy cập khẩn cấp." }, @@ -1874,7 +1904,7 @@ "message": "Năm hết hạn" }, "monthly": { - "message": "month" + "message": "tháng" }, "expiration": { "message": "Hết hạn" @@ -2446,7 +2476,7 @@ } }, "topLayerHijackWarning": { - "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + "message": "Trang này đang cản trở trải nghiệm Bitwarden. Menu nội tuyến Bitwarden đã tạm thời bị vô hiệu hóa như một biện pháp an toàn." }, "setMasterPassword": { "message": "Đặt mật khẩu chính" @@ -4912,7 +4942,7 @@ "message": "Cao cấp" }, "unlockFeaturesWithPremium": { - "message": "Unlock reporting, emergency access, and more security features with Premium." + "message": "Mở khóa tính năng báo cáo, quyền truy cập khẩn cấp và nhiều tính năng bảo mật khác với Premium." }, "freeOrgsCannotUseAttachments": { "message": "Các tổ chức miễn phí không thể sử dụng tệp đính kèm" @@ -4999,7 +5029,7 @@ } }, "defaultLabelWithValue": { - "message": "Default ( $VALUE$ )", + "message": "Mặc định ( $VALUE$ )", "description": "A label that indicates the default value for a field with the current default value in parentheses.", "placeholders": { "value": { @@ -5825,19 +5855,19 @@ "message": "Nâng cấp lên gói Cao cấp" }, "unlockAdvancedSecurity": { - "message": "Unlock advanced security features" + "message": "Mở khóa các tính năng bảo mật nâng cao" }, "unlockAdvancedSecurityDesc": { - "message": "A Premium subscription gives you more tools to stay secure and in control" + "message": "Đăng ký Premium cung cấp cho bạn nhiều công cụ hơn để luôn an toàn và kiểm soát" }, "explorePremium": { - "message": "Explore Premium" + "message": "Khám phá Premium" }, "loadingVault": { - "message": "Loading vault" + "message": "Đang tải kho" }, "vaultLoaded": { - "message": "Vault loaded" + "message": "Đã tải kho" }, "settingDisabledByPolicy": { "message": "Cài đặt này bị vô hiệu hóa bởi chính sách tổ chức của bạn.", @@ -5850,6 +5880,6 @@ "message": "Số thẻ" }, "sessionTimeoutSettingsAction": { - "message": "Timeout action" + "message": "Hành động sau khi đóng kho" } } diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 7a0662fb9f8..fd4b6380b1b 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "进一步了解" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "验证器密钥 (TOTP)" }, @@ -1473,7 +1494,16 @@ "message": "注册高级会员将获得:" }, "ppremiumSignUpStorage": { - "message": "1 GB 文件附件加密存储。" + "message": "1 GB 文件附件加密存储空间。" + }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ 文件附件加密存储空间。", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } }, "premiumSignUpEmergency": { "message": "紧急访问。" diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 38fb50d6c8b..de78e415fa6 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -1406,6 +1406,27 @@ "learnMore": { "message": "深入了解" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, + "later": { + "message": "Later" + }, "authenticatorKeyTotp": { "message": "驗證器金鑰 (TOTP)" }, @@ -1475,6 +1496,15 @@ "ppremiumSignUpStorage": { "message": "用於檔案附件的 1 GB 加密儲存空間。" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpEmergency": { "message": "緊急存取" }, From 110c955cff8defb7c4654a31908c49db9be8f93a Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 12:44:46 +0100 Subject: [PATCH 29/89] Autosync the updated translations (#17827) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ar/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/az/messages.json | 47 +++++++++++++++++++---- apps/web/src/locales/be/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/bg/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/bn/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/bs/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ca/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/cs/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/cy/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/da/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/de/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/el/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/en_GB/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/en_IN/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/eo/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/es/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/et/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/eu/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/fa/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/fi/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/fil/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/fr/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/gl/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/he/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/hi/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/hr/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/hu/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/id/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/it/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ja/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ka/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/km/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/kn/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ko/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/lv/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ml/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/mr/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/my/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/nb/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ne/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/nl/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/nn/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/or/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/pl/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/pt_BR/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/pt_PT/messages.json | 41 ++++++++++++++++++-- apps/web/src/locales/ro/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/ru/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/si/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/sk/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/sl/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/sr_CS/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/sr_CY/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/sv/messages.json | 49 ++++++++++++++++++++---- apps/web/src/locales/ta/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/te/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/th/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/tr/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/uk/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/vi/messages.json | 39 +++++++++++++++++-- apps/web/src/locales/zh_CN/messages.json | 45 +++++++++++++++++++--- apps/web/src/locales/zh_TW/messages.json | 39 +++++++++++++++++-- 63 files changed, 2281 insertions(+), 202 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 0fc3ebe06d9..923e65fbf99 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GG geënkripteerde berging vir lêeraanhegsels." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Bykomende berging (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Leer meer" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index acd669d462e..4999534a5f6 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "تخزين إضافي (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "معرفة المزيد" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 9fa7411f199..409d2a4edde 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "Fayl qoşmaları üçün 1 GB şifrələnmiş saxlama sahəsi." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey və Duo kimi mülkiyyətçi iki addımlı giriş seçimləri." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Əlavə saxlama sahəsi (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Daha ətraflı" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Güncəlləmə ayarları" + }, "deleteRecoverDesc": { "message": "Hesabınızı geri qaytarmaq və silmək üçün e-poçtunuzu aşağıda daxil edin." }, @@ -11668,7 +11704,7 @@ "message": "Bitwarden uzantısı quraşdırıldı!" }, "bitwardenExtensionIsInstalled": { - "message": "Bitwarden extension is installed!" + "message": "Bitwarden uzantısı quraşdırıldı!" }, "openExtensionToAutofill": { "message": "Giriş etmək üçün uzantını aç və avto-doldurmağa başla." @@ -11685,11 +11721,11 @@ "description": "This will be displayed as part of a larger sentence. The whole sentence reads: 'For tips on getting started with Bitwarden visit the Learning Center and Help Center'" }, "openExtensionFromToolbarPart1": { - "message": "If the extension didn't open, you may need to open Bitwarden from the icon ", + "message": "Uzantı açılmasa, alət çubuğundakı ikondan Bitwarden-i açmağınız ", "description": "This will be used as part of a larger sentence, broken up to include the Bitwarden icon. The full sentence will read 'If the extension didn't open, you may need to open Bitwarden from the icon [Bitwarden Icon] on the toolbar.'" }, "openExtensionFromToolbarPart2": { - "message": " on the toolbar.", + "message": " lazımdır.", "description": "This will be used as part of a larger sentence, broken up to include the Bitwarden icon. The full sentence will read 'If the extension didn't open, you may need to open Bitwarden from the icon [Bitwarden Icon] on the toolbar.'" }, "gettingStartedWithBitwardenPart3": { @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Şifrələmə ayarlarınızı güncəlləyin" }, - "updateSettings": { - "message": "Güncəlləmə ayarları" - }, "algorithm": { "message": "Alqoritm" }, @@ -12173,6 +12206,6 @@ "message": "Davam etmək istədiyinizə əminsiniz?" }, "userVerificationFailed": { - "message": "User verification failed." + "message": "İstifadəçi doğrulaması uğursuz oldu." } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 20142bf95d1..d0de973f30f 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 ГБ зашыфраванага сховішча для далучаных файлаў." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Прапрыетарныя варыянты двухэтапнага ўваходу, такія як YubiKey, FIDO U2F і Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Дадатковая сховішча (ГБ)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Даведацца больш" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Увядзіце адрас сваёй электроннай ніжэй, каб аднавіць і выдаліць ваш уліковы запіс." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index 3267ebc3385..e058bdee1bd 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB пространство за файлове, които се шифрират." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ пространство за файлове, които се шифрират.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Частно двустепенно удостоверяване чрез YubiKey и Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Вашият абонамент за платения план е приключил" + }, + "premiumSubscriptionEndedDesc": { + "message": "Ако искате отново да получите достъп до архива си, трябва да подновите платения си абонамент. Ако редактирате данните за архивиран елемент преди подновяването, той ще бъде върнат в трезора." + }, + "restartPremium": { + "message": "Подновяване на платения абонамент" + }, "additionalStorageGb": { "message": "Допълнително място [GB]" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Научете повече" }, + "migrationsFailed": { + "message": "Възникна грешка при обновяването на настройките за шифроване." + }, + "updateEncryptionSettingsTitle": { + "message": "Обновете настройките си за шифроване" + }, + "updateEncryptionSettingsDesc": { + "message": "Новите препоръчани настройки за шифроване ще подобрят сигурността на акаунта Ви. Въведете главната си парола, за да ги обновите сега." + }, + "confirmIdentityToContinue": { + "message": "Потвърдете самоличността си, за да продължите" + }, + "enterYourMasterPassword": { + "message": "Въведете главната си парола" + }, + "updateSettings": { + "message": "Обновяване на настройките" + }, "deleteRecoverDesc": { "message": "Въведете адреса на електронната си поща, за да възстановите и да изтриете абонамента си." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Обновете настройките си за шифроване" }, - "updateSettings": { - "message": "Обновяване на настройките" - }, "algorithm": { "message": "Алгоритъм" }, diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index f302bd08e24..915f2bff970 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "ফাইল সংযুক্তির জন্য ১ জিবি এনক্রিপ্টেড স্থান।" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "আরও জানুন" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index dce29d875db..4c3005bda33 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index dc3f4994c67..8b3e85e936e 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB d'emmagatzematge xifrat per als fitxers adjunts." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opcions propietàries de doble factor com ara YubiKey i Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Emmagatzematge suplementari (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Més informació" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Introduïu la vostra adreça de correu electrònic a continuació per recuperar i eliminar el vostre compte." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index b4016223c73..aceb40291df 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrovaného úložiště pro přílohy." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrovaného úložiště pro přílohy.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Volby proprietálních dvoufázových přihlášení jako je YubiKey a Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Vaše předplatné Premium skončilo" + }, + "premiumSubscriptionEndedDesc": { + "message": "Chcete-li získat přístup k Vašemu archivu, restartujte předplatné Premium. Pokud upravíte detaily archivované položky před restartováním, bude přesunuta zpět do Vašeho trezoru." + }, + "restartPremium": { + "message": "Restartovat Premium" + }, "additionalStorageGb": { "message": "Další úložiště (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Dozvědět se více" }, + "migrationsFailed": { + "message": "Došlo k chybě při aktualizaci nastavení šifrování." + }, + "updateEncryptionSettingsTitle": { + "message": "Aktualizovat nastavení šifrování" + }, + "updateEncryptionSettingsDesc": { + "message": "Nové doporučené nastavení šifrování zlepší bezpečnost Vašeho účtu. Pokud chcete aktualizovat nyní, zadejte hlavní heslo." + }, + "confirmIdentityToContinue": { + "message": "Pro pokračování potvrďte svou identitu" + }, + "enterYourMasterPassword": { + "message": "Zadejte své hlavní heslo" + }, + "updateSettings": { + "message": "Aktualizovat nastavení" + }, "deleteRecoverDesc": { "message": "Zadejte svou e-mailovou adresu níže pro obnovení a smazání účtu." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Aktualizujte nastavení šifrování" }, - "updateSettings": { - "message": "Aktualizovat nastavení" - }, "algorithm": { "message": "Algoritmus" }, diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index 46876fa947c..108b1ebe23a 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 0316c1d2f0c..904dc69a0e3 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB krypteret lager til vedhæftede filer." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietære totrins-login muligheder, såsom YubiKey og Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Ekstra lagerplads (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Få mere at vide" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Indtast din e-mailadresse nedenfor for at gendanne og slette din konto." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index b2eb06a720e..6c354cd9064 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB verschlüsselter Speicherplatz für Dateianhänge." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietäre Optionen für die Zwei-Faktor Authentifizierung wie YubiKey und Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Zusätzlicher Speicher (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Erfahre mehr" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Einstellungen aktualisieren" + }, "deleteRecoverDesc": { "message": "Geben Sie hier Ihre E-Mail-Adresse ein, um Ihr Konto wiederherzustellen und zu löschen." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Aktualisiere deine Verschlüsselungseinstellungen" }, - "updateSettings": { - "message": "Einstellungen aktualisieren" - }, "algorithm": { "message": "Algorithmus" }, diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 3a23bb286ea..f6e8abfd612 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB κρυπτογραφημένο αποθηκευτικό χώρο για συνημμένα αρχεία." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Επιπλέον χώρος αποθήκευσης (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Μάθετε περισσότερα" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Εισάγετε την παρακάτω διεύθυνση email για να ανακτήσετε και να διαγράψετε το λογαριασμό σας." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 643601f54fe..be621369c77 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 29271d771d2..aafb9a01f3e 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index da4490d0495..220d9492c67 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB ĉifrita stokado por dosieraj aldonaĵoj." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Aldona Stokado (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Lernu pli" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enigu vian retpoŝtan adreson sube por rekuperi kaj forigi vian konton." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index ac5ca868b0f..b0a3716cf60 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB de almacenamiento de archivos cifrados." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opciones de inicio de sesión con autenticación de dos pasos propietarios como YubiKey y Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Almacenamiento adicional (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Más información" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Introduce tu correo electrónico debajo para recuperar y eliminar tu cuenta." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 186c0f1f256..1388e25bc13 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB ulatuses krüpteeritud salvestusruum." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Eraomanduses kaheastmelise logimise valikud, nagu näiteks YubiKey ja Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Lisaruum (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Rohkem teavet" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Sisesta e-posti aadress oma konto taastamiseks ja kustutamiseks." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index e494c663b74..c2fa69d56b8 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "Eranskinentzako 1GB-eko zifratutako biltegia." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Biltegi gehigarria (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Gehiago ikasi" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Sartu zure emaila jarraian, zure kontua berreskuratu eta ezabatzeko." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index ff39b14c05f..c8623050394 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "۱ گیگابایت فضای ذخیره‌سازی رمزنگاری شده برای پرونده‌های پیوست." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "گزینه های ورود اضافی دو مرحله ای مانند YubiKey و Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "ذخیره‌سازی های اضافی (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "بیشتر بدانید" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "نشانی ایمیل خود را در زیر برای بازیابی و حذف حساب خود وارد کنید." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 9710db5f285..181c8d4f125 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 Gt salattua tallennustilaa tiedostoliitteille." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Kaksivaiheisen kirjautumisen erikoisvaihtoehdot, kuten YubiKey ja Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Lisää tallennustilaa (Gt)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Lue lisää" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Kirjoita sähköpostiosoitteesi alle palauttaaksesi ja poistaaksesi tilisi." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index 85b5797e634..f3542368044 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1GB na naka-encrypt na storage para sa mga file attachment." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Karagdagang storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Matuto nang higit pa" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Ipasok ang iyong email address sa ibaba upang mabawi at tanggalin ang iyong account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index 8103dcde46e..e5fcf929f0d 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 Go de stockage chiffré pour les fichiers joints." }, + "premiumSignUpStorageV2": { + "message": "Stockage chiffré de $SIZE$ pour les pièces jointes.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Options de connexion propriétaires à deux facteurs telles que YubiKey et Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Votre abonnement Premium est terminé" + }, + "premiumSubscriptionEndedDesc": { + "message": "Pour récupérer l'accès à vos archives, redémarrez votre abonnement Premium. Si vous modifiez les détails d'un élément archivé avant de le redémarrer, il sera déplacé dans votre coffre." + }, + "restartPremium": { + "message": "Redémarrer Premium" + }, "additionalStorageGb": { "message": "Stockage additionnel (Go)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "En savoir plus" }, + "migrationsFailed": { + "message": "Une erreur s'est produite lors de la mise à jour des paramètres de chiffrement." + }, + "updateEncryptionSettingsTitle": { + "message": "Mettre à jour vos paramètres de chiffrement" + }, + "updateEncryptionSettingsDesc": { + "message": "Les nouveaux paramètres de chiffrement recommandés amélioreront la sécurité de votre compte. Entrez votre mot de passe principal pour faire la mise à jour maintenant." + }, + "confirmIdentityToContinue": { + "message": "Confirmez votre identité pour continuer" + }, + "enterYourMasterPassword": { + "message": "Entrez votre mot de passe principal" + }, + "updateSettings": { + "message": "Mettre à jour les paramètres" + }, "deleteRecoverDesc": { "message": "Saisissez votre adresse électronique ci-dessous pour récupérer et supprimer votre compte." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Mettre à jour vos paramètres de chiffrement" }, - "updateSettings": { - "message": "Mettre à jour les paramètres" - }, "algorithm": { "message": "Algorithme" }, diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index ce34dee8f42..f7a848bd025 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 6560e2f2222..d723cb42140 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 ג'יגה של מקום אחסון מוצפן עבור קבצים מצורפים." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "אפשרויות כניסה דו־שלבית קנייניות כגון YubiKey ו־Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "אחסון נוסף (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "למידע נוסף" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "עדכן הגדרות" + }, "deleteRecoverDesc": { "message": "הזן את כתובת האימייל שלך כדי לשחזר ולמחוק את החשבון שלך." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "עדכן את הגדרות ההצפנה שלך" }, - "updateSettings": { - "message": "עדכן הגדרות" - }, "algorithm": { "message": "אלגוריתם" }, diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 67dede6f1e7..1c5a211aaca 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 8c548a71dee..f357718bab0 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB šifriranog prostora za pohranu podataka." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Mogućnosti za prijavu u dva koraka kao što su YubiKey i Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Dodatni prostor za pohranu (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Saznaj više" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Ažuriraj postavke" + }, "deleteRecoverDesc": { "message": "Unesi svoju e-poštu za oporavak i brisanje svojeg računa." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Ažuriraj svoje postakve šifriranja" }, - "updateSettings": { - "message": "Ažuriraj postavke" - }, "algorithm": { "message": "Algoritam" }, diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index f626e348e73..3d360541b93 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB titkosított tárhely a fájlmellékleteknek." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ titkosított tárhely a fájlmellékletekhez.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Saját kétlépcsős bejelentkezési lehetőségek mint a YubiKey és a Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "A Prémium előfizetés véget ért." + }, + "premiumSubscriptionEndedDesc": { + "message": "Az archívumhoz hozzáférés visszaszerzéséhez indítsuk újra a Prémium előfizetést. Ha az újraindítás előtt szerkesztjük egy archivált elem adatait, akkor az visszakerül a széfbe." + }, + "restartPremium": { + "message": "Prémium előfizetés újraindítása" + }, "additionalStorageGb": { "message": "Kiegészítő tárhely (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "További információ" }, + "migrationsFailed": { + "message": "Hiba történt a titkosítási beállítások frissítésekor." + }, + "updateEncryptionSettingsTitle": { + "message": "A titkosítási beállítások frissítése" + }, + "updateEncryptionSettingsDesc": { + "message": "Az új ajánlott titkosítási beállítások javítják a fiók biztonságát. Adjuk meg a mesterjelszót a frissítéshez most." + }, + "confirmIdentityToContinue": { + "message": "A folytatáshoz meg kell erősíteni a személyazonosságot." + }, + "enterYourMasterPassword": { + "message": "Mesterjelszó megadása" + }, + "updateSettings": { + "message": "Beállítások frissítése" + }, "deleteRecoverDesc": { "message": "Az email cím megadása lentebb a fiók helyreállításához és törléséhez." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Frissítsük a titkosítási beállításokat." }, - "updateSettings": { - "message": "Beállítások frissítése" - }, "algorithm": { "message": "Algoritmus" }, diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 639063ca304..4dc41e8f928 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "Penyimpanan terenkripsi 1 GB untuk lampiran file." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opsi login dua langkah eksklusif seperti YubiKey dan Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Tambahan Penyimpanan (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Pelajari lebih lanjut" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Masukkan alamat email Anda di bawah ini untuk memulihkan dan menghapus akun Anda." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 14da6d6be56..459f1dfd3a4 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB di spazio di archiviazione crittografato per gli allegati." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opzioni di verifica in due passaggi proprietarie come YubiKey e Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Spazio di archiviazione aggiuntivo (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Ulteriori informazioni" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Aggiorna le impostazioni" + }, "deleteRecoverDesc": { "message": "Inserisci la tua email per recuperare ed eliminare il tuo account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Aggiorna le impostazioni di crittografia" }, - "updateSettings": { - "message": "Aggiorna le impostazioni" - }, "algorithm": { "message": "Algoritmo" }, diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 7143e958f99..33535634bc8 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1GB の暗号化されたファイルストレージ" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey、Duo などのプロプライエタリな2段階認証オプション。" }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "追加ストレージ容量(GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "詳細" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "メールアドレスを入力してアカウントを削除します。" }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 108df6dcddb..47a46367feb 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 0d08d207748..608215f8155 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index c3b4fe8ebd3..2f0759ff939 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "ಫೈಲ್ ಲಗತ್ತುಗಳಿಗಾಗಿ 1 ಜಿಬಿ ಎನ್‌ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ ಸಂಗ್ರಹ." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "ಹೆಚ್ಚುವರಿ ಸಂಗ್ರಹಣೆ (ಜಿಬಿ)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "ನಿಮ್ಮ ಖಾತೆಯನ್ನು ಮರುಪಡೆಯಲು ಮತ್ತು ಅಳಿಸಲು ನಿಮ್ಮ ಇಮೇಲ್ ವಿಳಾಸವನ್ನು ಕೆಳಗೆ ನಮೂದಿಸಿ." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 4063e7c62da..aaef9d378e9 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1GB의 암호화된 파일 저장소." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey, Duo와 같은 \b상용 2단계 로그인 방법." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "추가 저장소 용량 (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "더 알아보기" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "계정을 복구하거나 삭제하려면 아래에 이메일 주소를 입력하십시오." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 120b06b8024..d627835b1f4 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrētas krātuves datņu pielikumiem." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ šifrētas krātuves datņu pielikumiem.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Tādas slēgtā pirmavota divpakāpju pieteikšanās iespējas kā YubiKey un Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Tavs Premium abonements beidzās" + }, + "premiumSubscriptionEndedDesc": { + "message": "Lai atgūtu piekļuvi savam arhīvam, jāatsāk Premium abonements. Ja labosi arhivēta vienuma informāciju pirms atsākšanas, tas tiks pārvietots atpakaļ Tavā glabātavā." + }, + "restartPremium": { + "message": "Atsākt Premium" + }, "additionalStorageGb": { "message": "Papildu krātuve (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Uzzināt vairāk" }, + "migrationsFailed": { + "message": "Atgadījās kļūda šifrēšanas iestatījumu atjaunināšanā." + }, + "updateEncryptionSettingsTitle": { + "message": "Atjaunini savus šifrēšanas iestatījumus" + }, + "updateEncryptionSettingsDesc": { + "message": "Jaunie ieteicamie šifrēšanas iestatījumi uzlabos Tava konta drošību. Jāievada sava galvenā parole, lai atjauninātu tagad." + }, + "confirmIdentityToContinue": { + "message": "Jāapliecina sava identitāte, lai turpinātu" + }, + "enterYourMasterPassword": { + "message": "Jāievada sava galvenā parole" + }, + "updateSettings": { + "message": "Atjaunināt Iestatījumus" + }, "deleteRecoverDesc": { "message": "Jāievada e-pasta adrese zemāk esošajā laukā, lai atkoptu un izdzēstu savu kontu." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Atjaunini savus šifrēšanas iestatījumus" }, - "updateSettings": { - "message": "Atjaunināt Iestatījumus" - }, "algorithm": { "message": "Algoritms" }, diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 5d7c304216c..8d49e35690e 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "ഫയൽ അറ്റാച്ചുമെന്റുകൾക്കായി 1 GB എൻക്രിപ്റ്റുചെയ്‌ത സ്റ്റോറേജ്." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional Storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "കൂടുതൽ അറിയുക" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "നിങ്ങളുടെ അക്കൗണ്ട് വീണ്ടെടുക്കുന്നതിനും ഇല്ലാതാക്കുന്നതിനും ചുവടെ നിങ്ങളുടെ ഇമെയിൽ വിലാസം നൽകുക." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index 82585984958..6ba6661c478 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index 0d08d207748..608215f8155 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 87664f952a1..042444814e6 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB med kryptert fillagring." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Ytterligere lagringsplass (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Lær mer" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Skriv inn din E-postadresse nedenfor for å få tilbake tilgangen til og å slette din konto." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index e2e310d7031..31367740728 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index fadbaa923d5..333df664f77 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB versleutelde opslag voor bijlagen." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ versleutelde opslag voor bijlagen.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Gepatenteerde 2 stap login opties zoals YubiKey en Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Je Premium-abonnement is afgelopen" + }, + "premiumSubscriptionEndedDesc": { + "message": "Herstart je Premium-abonnement om toegang tot je archief te krijgen. Als je de details wijzigt voor een gearchiveerd item voor het opnieuw opstarten, zal het terug naar je kluis worden verplaatst." + }, + "restartPremium": { + "message": "Premium herstarten" + }, "additionalStorageGb": { "message": "Extra opslagruimte (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Meer informatie" }, + "migrationsFailed": { + "message": "Er is een fout opgetreden bij het bijwerken van de versleutelingsinstellingen." + }, + "updateEncryptionSettingsTitle": { + "message": "Je versleutelingsinstellingen bijwerken" + }, + "updateEncryptionSettingsDesc": { + "message": "De nieuwe aanbevolen versleutelingsinstellingen verbeteren de beveiliging van je account. Voer je hoofdwachtwoord in om nu bij te werken." + }, + "confirmIdentityToContinue": { + "message": "Bevestig je identiteit om door te gaan" + }, + "enterYourMasterPassword": { + "message": "Voer je hoofdwachtwoord in" + }, + "updateSettings": { + "message": "Instellingen bijwerken" + }, "deleteRecoverDesc": { "message": "Voer hieronder je e-mailadres in om je account te herstellen en te verwijderen." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Je versleutelingsinstellingen bijwerken" }, - "updateSettings": { - "message": "Instellingen bijwerken" - }, "algorithm": { "message": "Algoritme" }, diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 8dc4b88b647..32c452cf657 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index 0d08d207748..608215f8155 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 5db5acc944f..f5e6b898bff 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB przestrzeni na zaszyfrowane załączniki." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Własnościowe opcje logowania dwuetapowego, takie jak YubiKey i Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Dodatkowa przestrzeń (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Dowiedz się więcej" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Wpisz adres e-mail poniżej, aby odzyskać i usunąć konto." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 653518431dc..ff5686cbba8 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB de armazenamento criptografado para anexo de arquivos." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ de armazenamento criptografado para anexos de arquivo.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opções de autenticação em duas etapas proprietárias como YubiKey e Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Sua assinatura Premium terminou" + }, + "premiumSubscriptionEndedDesc": { + "message": "Para recuperar o seu acesso ao seu arquivo, retoma sua assinatura Premium. Se editar detalhes de um item arquivado antes de retomar, ele será movido de volta para o seu cofre." + }, + "restartPremium": { + "message": "Retomar Premium" + }, "additionalStorageGb": { "message": "Armazenamento adicional (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Saiba mais" }, + "migrationsFailed": { + "message": "Ocorreu um erro ao atualizar as configurações de criptografia." + }, + "updateEncryptionSettingsTitle": { + "message": "Atualize suas configurações de criptografia" + }, + "updateEncryptionSettingsDesc": { + "message": "As novas configurações de criptografia recomendadas melhorarão a segurança da sua conta. Digite sua senha principal para atualizar agora." + }, + "confirmIdentityToContinue": { + "message": "Confirme sua identidade para continuar" + }, + "enterYourMasterPassword": { + "message": "Digite sua senha principal" + }, + "updateSettings": { + "message": "Atualizar configurações" + }, "deleteRecoverDesc": { "message": "Digite seu endereço de e-mail abaixo para recuperar e apagar sua conta." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Atualize suas configurações de criptografia" }, - "updateSettings": { - "message": "Atualizar configurações" - }, "algorithm": { "message": "Algoritmo" }, diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 2227710d093..73ba923b416 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -1375,7 +1375,7 @@ "message": "Iniciar sessão com o dispositivo" }, "loginWithDeviceEnabledNote": { - "message": "O início de sessão com o dispositivo deve ser ativado nas definições da aplicação Bitwarden. Precisa de outra opção?" + "message": "O início de sessão com o dispositivo deve ser ativado nas definições da app Bitwarden. Precisa de outra opção?" }, "needAnotherOptionV1": { "message": "Precisa de outra opção?" @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB de armazenamento encriptado para anexos de ficheiros." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ de armazenamento encriptado para anexos de ficheiros.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Opções proprietárias de verificação de dois passos, como YubiKey e Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "A sua subscrição Premium terminou" + }, + "premiumSubscriptionEndedDesc": { + "message": "Para recuperar o acesso ao seu arquivo, reinicie a sua subscrição Premium. Se editar os detalhes de um item arquivado antes de reiniciar, ele será movido de volta para o seu cofre." + }, + "restartPremium": { + "message": "Reiniciar Premium" + }, "additionalStorageGb": { "message": "Armazenamento adicional (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Saber mais" }, + "migrationsFailed": { + "message": "Ocorreu um erro ao atualizar as definições de encriptação." + }, + "updateEncryptionSettingsTitle": { + "message": "Atualize as suas definições de encriptação" + }, + "updateEncryptionSettingsDesc": { + "message": "As novas definições de encriptação recomendadas irão melhorar a segurança da sua conta. Introduza a sua palavra-passe mestra para atualizar agora." + }, + "confirmIdentityToContinue": { + "message": "Confirme a sua identidade para continuar" + }, + "enterYourMasterPassword": { + "message": "Introduza a sua palavra-passe mestra" + }, + "updateSettings": { + "message": "Atualizar definições" + }, "deleteRecoverDesc": { "message": "Introduza o seu endereço de e-mail abaixo para recuperar e eliminar a sua conta." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Atualize as suas definições de encriptação" }, - "updateSettings": { - "message": "Atualizar definições" - }, "algorithm": { "message": "Algoritmo" }, diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index c3c2b7d9c4b..8efd88e49aa 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB stocare criptată pentru fișiere atașate." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Stocare adițională (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Aflați mai multe" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Introduceți adresa de e-mail mai jos pentru a vă recupera și șterge contul." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index c1b2e3f1dc1..0691b4e654b 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 ГБ зашифрованного хранилища для вложенных файлов." }, + "premiumSignUpStorageV2": { + "message": "Зашифрованного хранилища для вложенных файлов: $SIZE$", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Проприетарные варианты двухэтапной аутентификации, такие как YubiKey или Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Ваша подписка Премиум закончилась" + }, + "premiumSubscriptionEndedDesc": { + "message": "Чтобы восстановить доступ к своему архиву, подключите подписку Премиум повторно. Если вы измените сведения об архивированном элементе перед переподключением, он будет перемещен обратно в ваше хранилище." + }, + "restartPremium": { + "message": "Переподключить Премиум" + }, "additionalStorageGb": { "message": "Дополнительное место (ГБ)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Подробнее" }, + "migrationsFailed": { + "message": "Произошла ошибка при обновлении настроек шифрования." + }, + "updateEncryptionSettingsTitle": { + "message": "Обновите настройки шифрования" + }, + "updateEncryptionSettingsDesc": { + "message": "Новые рекомендуемые настройки шифрования повысят безопасность вашего аккаунта. Введите мастер-пароль, чтобы обновить сейчас." + }, + "confirmIdentityToContinue": { + "message": "Подтвердите вашу личность, чтобы продолжить" + }, + "enterYourMasterPassword": { + "message": "Введите ваш мастер-пароль" + }, + "updateSettings": { + "message": "Обновить настройки" + }, "deleteRecoverDesc": { "message": "Введите свой адрес email, чтобы восстановить и удалить ваш аккаунт." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Обновите настройки шифрования" }, - "updateSettings": { - "message": "Обновить настройки" - }, "algorithm": { "message": "Алгоритм" }, diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index 03f68be3c03..d4c4d143600 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 3e19422e07e..70578e5bf59 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB šifrovaného úložiska pre prílohy." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietárne možnosti dvojstupňového prihlásenia ako napríklad YubiKey a Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Dodatočné úložisko (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Zistiť viac" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Zadajte vašu emailovú adresu ak chcete obnoviť a zrušiť vaše konto." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 09a882fe7e5..10c734ec6b7 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Dodatna hramba (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Več o tem" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 367d4ddbace..0f8a2760370 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Saznaj više" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/sr_CY/messages.json b/apps/web/src/locales/sr_CY/messages.json index aea5a1d9733..f1f7dd3ca73 100644 --- a/apps/web/src/locales/sr_CY/messages.json +++ b/apps/web/src/locales/sr_CY/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1ГБ шифровано складиште за прилоге." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Приоритарне опције пријаве у два корака као што су YubiKey и Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Додатно складиште (ГБ)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Сазнај више" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Ажурирај подешавања" + }, "deleteRecoverDesc": { "message": "Унесите свој имејл да бисте опоравили и избрисали налог." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Ажурирајте своје поставке за шифровање" }, - "updateSettings": { - "message": "Ажурирај подешавања" - }, "algorithm": { "message": "Алгоритам" }, diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index 6432029d219..7f1275ee75c 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -236,7 +236,7 @@ "message": "Applikationer markerade som kritiska" }, "criticalApplicationsMarkedSuccess": { - "message": "$COUNT$ applications marked as critical", + "message": "$COUNT$ applikationer markerade som kritiska", "placeholders": { "count": { "content": "$1", @@ -269,7 +269,7 @@ "message": "These members have access to vulnerable items for critical applications." }, "membersWithAtRiskPasswords": { - "message": "Members with at-risk passwords" + "message": "Medlemmar med lösenord i riskzonen" }, "membersWillReceiveSecurityTask": { "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB krypterad lagring." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Premium-alternativ för tvåstegsverifiering, såsom YubiKey och Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Starta om Premium" + }, "additionalStorageGb": { "message": "Ytterligare lagring (GB)" }, @@ -4482,7 +4500,7 @@ "message": "Sammanställer insikter..." }, "loadingProgress": { - "message": "Loading progress" + "message": "Inläsningsförlopp" }, "thisMightTakeFewMinutes": { "message": "Detta kan ta några minuter." @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Läs mer" }, + "migrationsFailed": { + "message": "Ett fel inträffade när krypteringsinställningarna skulle uppdateras." + }, + "updateEncryptionSettingsTitle": { + "message": "Uppdatera dina krypteringsinställningar" + }, + "updateEncryptionSettingsDesc": { + "message": "De nya rekommenderade krypteringsinställningarna kommer att förbättra säkerheten för ditt konto. Ange ditt huvudlösenord för att uppdatera nu." + }, + "confirmIdentityToContinue": { + "message": "Bekräfta din identitet för att fortsätta" + }, + "enterYourMasterPassword": { + "message": "Ange ditt huvudlösenord" + }, + "updateSettings": { + "message": "Uppdatera inställningar" + }, "deleteRecoverDesc": { "message": "Ange din e-postadress nedan för att återställa och radera ditt konto." }, @@ -6614,7 +6650,7 @@ "message": "Ditt huvudlösenord uppfyller inte en eller flera av organisationens policyer. För att få tillgång till valvet måste du uppdatera ditt huvudlösenord nu. Om du fortsätter loggas du ut från din nuvarande session och måste logga in igen. Aktiva sessioner på andra enheter kan fortsätta att vara aktiva i upp till en timme." }, "automaticAppLoginWithSSO": { - "message": "Automatic login with SSO" + "message": "Automatisk inloggning med SSO" }, "automaticAppLoginWithSSODesc": { "message": "Extend SSO security and convenience to unmanaged apps. When users launch an app from your identity provider, their login details are automatically filled and submitted, creating a one-click, secure flow from the identity provider to the app." @@ -7393,7 +7429,7 @@ "message": "Åtkomst nekad. Du har inte behörighet att visa den här sidan." }, "noPageAccess": { - "message": "You do not have access to this page" + "message": "Du har inte tillgång till denna sida" }, "masterPassword": { "message": "Huvudlösenord" @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Uppdatera dina krypteringsinställningar" }, - "updateSettings": { - "message": "Uppdatera inställningar" - }, "algorithm": { "message": "Algoritm" }, diff --git a/apps/web/src/locales/ta/messages.json b/apps/web/src/locales/ta/messages.json index d6154ae9fcb..98970962d69 100644 --- a/apps/web/src/locales/ta/messages.json +++ b/apps/web/src/locales/ta/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "கோப்பு இணைப்புகளுக்கு 1 GB என்க்ரிப்ட் செய்யப்பட்ட சேமிப்பகம்." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey மற்றும் Duo போன்ற தனியுரிம இரண்டு-படி உள்நுழைவு விருப்பங்கள்." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "கூடுதல் சேமிப்பகம் (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "மேலும் அறிக" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "உங்கள் கணக்கை மீட்டு நீக்க, கீழே உங்கள் மின்னஞ்சல் முகவரியை உள்ளிடவும்." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index 0d08d207748..608215f8155 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index fca56729464..c20cc2e5d8c 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 GB encrypted storage for file attachments." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Proprietary two-step login options such as YubiKey and Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Additional storage (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Learn more" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Enter your email address below to recover and delete your account." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 70136be6086..829c0ca17dc 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "Dosya ekleri için 1 GB şifrelenmiş depolama." }, + "premiumSignUpStorageV2": { + "message": "Dosya ekleri için $SIZE$ şifrelenmiş depolama.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "YubiKey ve Duo gibi marka bazlı iki aşamalı giriş seçenekleri." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Ek depolama alanı (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Daha fazla bilgi al" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Ayarları güncelle" + }, "deleteRecoverDesc": { "message": "Hesabınızı kurtarmak ve silmek için e-posta adresinizi yazın." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Şifreleme ayarlarınızı güncelleyin" }, - "updateSettings": { - "message": "Ayarları güncelle" - }, "algorithm": { "message": "Algoritma" }, diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 1ccabaeddfb..be571b0c146 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1 ГБ зашифрованого сховища для файлів." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Додаткові можливості двоетапної авторизації, як-от YubiKey та Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Додаткове сховище (ГБ)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Докладніше" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Update settings" + }, "deleteRecoverDesc": { "message": "Введіть свою адресу е-пошти внизу, щоб відновити і видалити обліковий запис." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Update your encryption settings" }, - "updateSettings": { - "message": "Update settings" - }, "algorithm": { "message": "Algorithm" }, diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 370ca0f5ad4..35e7db50023 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "1GB bộ nhớ lưu trữ được mã hóa cho các tệp đính kèm." }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "Các tùy chọn xác minh hai bước như YubiKey và Duo." }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "Dung lượng lưu trữ bổ sung (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "Tìm hiểu thêm" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "Cập nhật cài đặt" + }, "deleteRecoverDesc": { "message": "Nhập địa chỉ email của bạn vào bên dưới để khôi phục và xóa tài khoản của bạn." }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "Cập nhật cài đặt mã hóa của bạn" }, - "updateSettings": { - "message": "Cập nhật cài đặt" - }, "algorithm": { "message": "Thuật toán" }, diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 53ec5f10185..7d898c79952 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -3060,7 +3060,16 @@ "message": "将您的账户升级为高级会员,将解锁一些强大的附加功能。" }, "premiumSignUpStorage": { - "message": "1 GB 文件附件加密存储。" + "message": "1 GB 文件附件加密存储空间。" + }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ 文件附件加密存储空间。", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } }, "premiumSignUpTwoStepOptions": { "message": "专有的两步登录选项,如 YubiKey 和 Duo。" @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "附加存储 (GB)" }, @@ -3350,7 +3368,7 @@ "message": "GB 存储空间将增加" }, "gbStorageRemove": { - "message": "GB 存储空间将删除" + "message": "GB 存储空间将移除" }, "storageAddNote": { "message": "添加存储空间将会调整计费总金额,并立即通过您的付款方式进行扣款。第一笔费用将按当前计费周期的剩余时间按比例分配。" @@ -3541,7 +3559,7 @@ "message": "创建不限数量的集合" }, "gbEncryptedFileStorage": { - "message": "$SIZE$ 加密文件存储", + "message": "$SIZE$ 加密文件存储空间", "placeholders": { "size": { "content": "$1", @@ -4608,6 +4626,24 @@ "learnMore": { "message": "进一步了解" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "更新设置" + }, "deleteRecoverDesc": { "message": "请在下面输入您的电子邮箱地址以恢复和删除您的账户。" }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "更新您的加密设置" }, - "updateSettings": { - "message": "更新设置" - }, "algorithm": { "message": "算法" }, diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 19456fed39d..95c345f74d7 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -3062,6 +3062,15 @@ "premiumSignUpStorage": { "message": "用於檔案附件的 1 GB 的加密檔案儲存空間。" }, + "premiumSignUpStorageV2": { + "message": "$SIZE$ encrypted storage for file attachments.", + "placeholders": { + "size": { + "content": "$1", + "example": "1 GB" + } + } + }, "premiumSignUpTwoStepOptions": { "message": "專有的兩步驟登入選項,例如 YubiKey 和 Duo。" }, @@ -3124,6 +3133,15 @@ } } }, + "premiumSubscriptionEnded": { + "message": "Your Premium subscription ended" + }, + "premiumSubscriptionEndedDesc": { + "message": "To regain access to your archive, restart your Premium subscription. If you edit details for an archived item before restarting, it'll be moved back into your vault." + }, + "restartPremium": { + "message": "Restart Premium" + }, "additionalStorageGb": { "message": "額外儲存空間 (GB)" }, @@ -4608,6 +4626,24 @@ "learnMore": { "message": "深入了解" }, + "migrationsFailed": { + "message": "An error occurred updating the encryption settings." + }, + "updateEncryptionSettingsTitle": { + "message": "Update your encryption settings" + }, + "updateEncryptionSettingsDesc": { + "message": "The new recommended encryption settings will improve your account security. Enter your master password to update now." + }, + "confirmIdentityToContinue": { + "message": "Confirm your identity to continue" + }, + "enterYourMasterPassword": { + "message": "Enter your master password" + }, + "updateSettings": { + "message": "更新設定" + }, "deleteRecoverDesc": { "message": "請在下方輸入您的電子郵件地址以復原及刪除您的帳戶。" }, @@ -12093,9 +12129,6 @@ "updateYourEncryptionSettings": { "message": "更新您的加密設定" }, - "updateSettings": { - "message": "更新設定" - }, "algorithm": { "message": "演算法" }, From ff7b625851cf4c23b8e02f1ed1186448fa645601 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 5 Dec 2025 13:06:03 +0100 Subject: [PATCH 30/89] [CL-946] Migrate ToggleGroup to OnPush (#17718) Migrates the ToggleGroup and Toggle components to use OnPush. --- .../toggle-group.component.spec.ts | 19 +- .../toggle-group/toggle-group.component.ts | 39 ++-- .../src/toggle-group/toggle.component.html | 12 +- .../src/toggle-group/toggle.component.spec.ts | 64 ++++++- .../src/toggle-group/toggle.component.ts | 166 +++++++++--------- 5 files changed, 178 insertions(+), 122 deletions(-) diff --git a/libs/components/src/toggle-group/toggle-group.component.spec.ts b/libs/components/src/toggle-group/toggle-group.component.spec.ts index 3a9d35b862b..5c1345df6f6 100644 --- a/libs/components/src/toggle-group/toggle-group.component.spec.ts +++ b/libs/components/src/toggle-group/toggle-group.component.spec.ts @@ -1,4 +1,4 @@ -import { Component } from "@angular/core"; +import { ChangeDetectionStrategy, Component, signal, WritableSignal } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { By } from "@angular/platform-browser"; @@ -30,31 +30,29 @@ describe("Button", () => { }); it("should select second element when setting selected to second", () => { - testAppComponent.selected = "second"; + testAppComponent.selected.set("second"); fixture.detectChanges(); - expect(buttonElements[1].selected).toBe(true); + expect(buttonElements[1].selected()).toBe(true); }); it("should not select second element when setting selected to third", () => { - testAppComponent.selected = "third"; + testAppComponent.selected.set("third"); fixture.detectChanges(); - expect(buttonElements[1].selected).toBe(false); + expect(buttonElements[1].selected()).toBe(false); }); it("should emit new value when changing selection by clicking on radio button", () => { - testAppComponent.selected = "first"; + testAppComponent.selected.set("first"); fixture.detectChanges(); radioButtons[1].click(); - expect(testAppComponent.selected).toBe("second"); + expect(testAppComponent.selected()).toBe("second"); }); }); -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ selector: "test-app", template: ` @@ -65,7 +63,8 @@ describe("Button", () => { `, imports: [ToggleGroupModule], + changeDetection: ChangeDetectionStrategy.OnPush, }) class TestAppComponent { - selected?: string; + readonly selected: WritableSignal = signal(undefined); } diff --git a/libs/components/src/toggle-group/toggle-group.component.ts b/libs/components/src/toggle-group/toggle-group.component.ts index bde8f0ea9b6..ee619eb15d7 100644 --- a/libs/components/src/toggle-group/toggle-group.component.ts +++ b/libs/components/src/toggle-group/toggle-group.component.ts @@ -1,39 +1,44 @@ import { booleanAttribute, + ChangeDetectionStrategy, Component, - EventEmitter, - HostBinding, - Output, + computed, input, model, } from "@angular/core"; let nextId = 0; -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ selector: "bit-toggle-group", templateUrl: "./toggle-group.component.html", + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + role: "radiogroup", + "[class]": "classlist()", + }, }) export class ToggleGroupComponent { - private id = nextId++; - name = `bit-toggle-group-${this.id}`; + private readonly id = nextId++; + readonly name = `bit-toggle-group-${this.id}`; + + /** + * Whether the toggle group should take up the full width of its container. + * When true, each toggle button will be equally sized to fill the available space. + */ readonly fullWidth = input(undefined, { transform: booleanAttribute }); - readonly selected = model(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() selectedChange = new EventEmitter(); - @HostBinding("attr.role") role = "radiogroup"; - @HostBinding("class") - get classList() { - return ["tw-flex"].concat(this.fullWidth() ? ["tw-w-full", "[&>*]:tw-flex-1"] : []); - } + /** + * The selected value in the toggle group. + */ + readonly selected = model(); + + protected readonly classlist = computed(() => + ["tw-flex"].concat(this.fullWidth() ? ["tw-w-full", "[&>*]:tw-flex-1"] : []), + ); onInputInteraction(value: TValue) { this.selected.set(value); - this.selectedChange.emit(value); } } diff --git a/libs/components/src/toggle-group/toggle.component.html b/libs/components/src/toggle-group/toggle.component.html index d036b1751ba..5104fbb8646 100644 --- a/libs/components/src/toggle-group/toggle.component.html +++ b/libs/components/src/toggle-group/toggle.component.html @@ -1,16 +1,16 @@ -