From 922de469f41b882dedb6d256af5be676c91907ba Mon Sep 17 00:00:00 2001 From: SmithThe4th Date: Wed, 4 Oct 2023 22:56:27 -0400 Subject: [PATCH 01/33] [PM-2169] Update Password Reprompt Modal to use Component Library (#5720) * update password reprompt to use the dialog CL * Override showPasswordPrompt and submit method on web child classes from base classes to allow dialog work on web and modal on other clients * Override showPasswordPrompt and submit method on web child classes from base classes to allow dialog work on web and modal on other clients * Fixed lint issues * Corrected comments * Refactored passwored reprompt to use dialog service after changes to make the dialog service work on the desktop and browser * Changed access modifier from protected to protected * Refactored passwprd reprompt component to a stand alone component and fixed all references * fix merge changes * fix import aliases in password-reprompt.component.ts * fix alias typo in browser tsconfig * import from root vault alias * revert tsconfig changes * remove service abstraction and update imports * remove component from imports * Removed unneccesary show password toggle * renamed selector to use vault prefix * removed unnecessary data dismiss * merged and fixed conflicts * remove reintroduced file * Added appAutoFocus to reprompt dialog * delayed validation until submit happens --------- Co-authored-by: William Martin --- apps/browser/src/popup/app.module.ts | 2 - .../src/popup/services/services.module.ts | 3 - .../components/action-buttons.component.ts | 2 +- .../password-reprompt.component.html | 55 --------------- .../components/password-reprompt.component.ts | 8 --- .../components/vault/add-edit.component.ts | 2 +- .../components/vault/current-tab.component.ts | 2 +- .../popup/components/vault/view.component.ts | 2 +- .../services/password-reprompt.service.ts | 10 --- apps/browser/tsconfig.json | 2 +- apps/desktop/src/app/app.module.ts | 2 - .../src/app/services/services.module.ts | 3 - .../password-reprompt.component.html | 57 ---------------- .../components/password-reprompt.component.ts | 8 --- .../src/vault/app/vault/add-edit.component.ts | 2 +- .../src/vault/app/vault/vault.component.ts | 2 +- .../src/vault/app/vault/view.component.ts | 2 +- .../services/password-reprompt.service.ts | 10 --- .../exposed-passwords-report.component.ts | 2 +- .../inactive-two-factor-report.component.ts | 2 +- .../reused-passwords-report.component.ts | 2 +- .../unsecured-websites-report.component.ts | 2 +- .../tools/weak-passwords-report.component.ts | 2 +- .../emergency-add-edit.component.ts | 2 +- apps/web/src/app/core/core.module.ts | 6 -- .../reports/pages/cipher-report.component.ts | 2 +- .../exposed-passwords-report.component.ts | 2 +- .../inactive-two-factor-report.component.ts | 2 +- .../reused-passwords-report.component.ts | 2 +- .../unsecured-websites-report.component.ts | 2 +- .../pages/weak-passwords-report.component.ts | 2 +- .../src/app/shared/loose-components.module.ts | 3 - .../password-reprompt.component.html | 53 --------------- .../components/password-reprompt.component.ts | 8 --- .../vault-cipher-row.component.html | 1 + .../vault-items/vault-cipher-row.component.ts | 2 +- .../vault/core/password-reprompt.service.ts | 10 --- .../individual-vault/add-edit.component.ts | 2 +- .../vault/individual-vault/vault.component.ts | 2 +- .../app/vault/org-vault/add-edit.component.ts | 2 +- .../app/vault/org-vault/vault.component.ts | 2 +- .../src/services/jslib-services.module.ts | 6 +- .../vault/components/add-edit.component.ts | 2 +- .../components/password-reprompt.component.ts | 42 ------------ .../src/vault/components/view.component.ts | 2 +- .../abstractions/password-reprompt.service.ts | 5 -- .../password-reprompt.component.html | 31 +++++++++ .../components/password-reprompt.component.ts | 68 +++++++++++++++++++ libs/vault/src/index.ts | 1 + .../password-reprompt.service.spec.ts | 11 ++- .../services/password-reprompt.service.ts | 19 +++--- 51 files changed, 144 insertions(+), 332 deletions(-) delete mode 100644 apps/browser/src/vault/popup/components/password-reprompt.component.html delete mode 100644 apps/browser/src/vault/popup/components/password-reprompt.component.ts delete mode 100644 apps/browser/src/vault/popup/services/password-reprompt.service.ts delete mode 100644 apps/desktop/src/vault/app/components/password-reprompt.component.html delete mode 100644 apps/desktop/src/vault/app/components/password-reprompt.component.ts delete mode 100644 apps/desktop/src/vault/services/password-reprompt.service.ts delete mode 100644 apps/web/src/app/vault/components/password-reprompt.component.html delete mode 100644 apps/web/src/app/vault/components/password-reprompt.component.ts delete mode 100644 apps/web/src/app/vault/core/password-reprompt.service.ts delete mode 100644 libs/angular/src/vault/components/password-reprompt.component.ts delete mode 100644 libs/common/src/vault/abstractions/password-reprompt.service.ts create mode 100644 libs/vault/src/components/password-reprompt.component.html create mode 100644 libs/vault/src/components/password-reprompt.component.ts rename libs/{angular/src/vault => vault/src}/services/password-reprompt.service.spec.ts (70%) rename libs/{angular/src/vault => vault/src}/services/password-reprompt.service.ts (61%) diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 32eb7670f3c..9dbd87cff57 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -39,7 +39,6 @@ import { SendTypeComponent } from "../tools/popup/send/send-type.component"; import { ExportComponent } from "../tools/popup/settings/export.component"; import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component"; import { CipherRowComponent } from "../vault/popup/components/cipher-row.component"; -import { PasswordRepromptComponent } from "../vault/popup/components/password-reprompt.component"; import { AddEditCustomFieldsComponent } from "../vault/popup/components/vault/add-edit-custom-fields.component"; import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component"; import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component"; @@ -125,7 +124,6 @@ import "../platform/popup/locales"; GeneratorComponent, PasswordGeneratorHistoryComponent, PasswordHistoryComponent, - PasswordRepromptComponent, PopOutComponent, PremiumComponent, PrivateModeWarningComponent, diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index c0597e29e44..6770e152504 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -80,7 +80,6 @@ import { FolderService, InternalFolderService, } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { DialogService } from "@bitwarden/components"; @@ -104,7 +103,6 @@ import BrowserMessagingService from "../../platform/services/browser-messaging.s import { BrowserStateService } from "../../platform/services/browser-state.service"; import { BrowserSendService } from "../../services/browser-send.service"; import { BrowserSettingsService } from "../../services/browser-settings.service"; -import { PasswordRepromptService } from "../../vault/popup/services/password-reprompt.service"; import { BrowserFolderService } from "../../vault/services/browser-folder.service"; import { VaultFilterService } from "../../vault/services/vault-filter.service"; @@ -409,7 +407,6 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("logService"), deps: [], }, - { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService }, { provide: OrganizationService, useFactory: (stateService: StateServiceAbstraction) => { diff --git a/apps/browser/src/vault/popup/components/action-buttons.component.ts b/apps/browser/src/vault/popup/components/action-buttons.component.ts index 110e4ef32a5..ff8b7cab0d1 100644 --- a/apps/browser/src/vault/popup/components/action-buttons.component.ts +++ b/apps/browser/src/vault/popup/components/action-buttons.component.ts @@ -6,10 +6,10 @@ import { EventType } from "@bitwarden/common/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; @Component({ selector: "app-action-buttons", diff --git a/apps/browser/src/vault/popup/components/password-reprompt.component.html b/apps/browser/src/vault/popup/components/password-reprompt.component.html deleted file mode 100644 index 730e96fab96..00000000000 --- a/apps/browser/src/vault/popup/components/password-reprompt.component.html +++ /dev/null @@ -1,55 +0,0 @@ - diff --git a/apps/browser/src/vault/popup/components/password-reprompt.component.ts b/apps/browser/src/vault/popup/components/password-reprompt.component.ts deleted file mode 100644 index f63da5ed48e..00000000000 --- a/apps/browser/src/vault/popup/components/password-reprompt.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from "@angular/core"; - -import { PasswordRepromptComponent as BasePasswordRepromptComponent } from "@bitwarden/angular/vault/components/password-reprompt.component"; - -@Component({ - templateUrl: "password-reprompt.component.html", -}) -export class PasswordRepromptComponent extends BasePasswordRepromptComponent {} diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts index f4e9fad5634..fd75b2e8c58 100644 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts +++ b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts @@ -17,10 +17,10 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { BrowserApi } from "../../../../platform/browser/browser-api"; import { PopupUtilsService } from "../../../../popup/services/popup-utils.service"; diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts index 4b2c62a0e0d..4f1ceb466de 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts @@ -11,11 +11,11 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service"; import { BrowserApi } from "../../../../platform/browser/browser-api"; diff --git a/apps/browser/src/vault/popup/components/vault/view.component.ts b/apps/browser/src/vault/popup/components/vault/view.component.ts index 19c37fc985e..6c9f3967d56 100644 --- a/apps/browser/src/vault/popup/components/vault/view.component.ts +++ b/apps/browser/src/vault/popup/components/vault/view.component.ts @@ -20,11 +20,11 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service"; import { BrowserApi } from "../../../../platform/browser/browser-api"; diff --git a/apps/browser/src/vault/popup/services/password-reprompt.service.ts b/apps/browser/src/vault/popup/services/password-reprompt.service.ts deleted file mode 100644 index 22bbcf44d7f..00000000000 --- a/apps/browser/src/vault/popup/services/password-reprompt.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from "@angular/core"; - -import { PasswordRepromptService as BasePasswordRepromptService } from "@bitwarden/angular/vault/services/password-reprompt.service"; - -import { PasswordRepromptComponent } from "../components/password-reprompt.component"; - -@Injectable() -export class PasswordRepromptService extends BasePasswordRepromptService { - component = PasswordRepromptComponent; -} diff --git a/apps/browser/tsconfig.json b/apps/browser/tsconfig.json index ecb2f996e55..357be6c5281 100644 --- a/apps/browser/tsconfig.json +++ b/apps/browser/tsconfig.json @@ -16,7 +16,7 @@ "@bitwarden/components": ["../../libs/components/src"], "@bitwarden/exporter/*": ["../../libs/exporter/src/*"], "@bitwarden/importer": ["../../libs/importer/src"], - "@bitwarden/vault": ["../../libs/auth/src"] + "@bitwarden/vault": ["../../libs/vault/src"] }, "useDefineForClassFields": false }, diff --git a/apps/desktop/src/app/app.module.ts b/apps/desktop/src/app/app.module.ts index d14c40854cc..172447822c9 100644 --- a/apps/desktop/src/app/app.module.ts +++ b/apps/desktop/src/app/app.module.ts @@ -24,7 +24,6 @@ import { TwoFactorOptionsComponent } from "../auth/two-factor-options.component" import { TwoFactorComponent } from "../auth/two-factor.component"; import { UpdateTempPasswordComponent } from "../auth/update-temp-password.component"; import { PremiumComponent } from "../vault/app/accounts/premium.component"; -import { PasswordRepromptComponent } from "../vault/app/components/password-reprompt.component"; import { AddEditCustomFieldsComponent } from "../vault/app/vault/add-edit-custom-fields.component"; import { AddEditComponent } from "../vault/app/vault/add-edit.component"; import { AttachmentsComponent } from "../vault/app/vault/attachments.component"; @@ -79,7 +78,6 @@ import { SendComponent } from "./tools/send/send.component"; GeneratorComponent, PasswordGeneratorHistoryComponent, PasswordHistoryComponent, - PasswordRepromptComponent, PremiumComponent, RegisterComponent, RemovePasswordComponent, diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index c6fd0049901..f4841073c9c 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -35,7 +35,6 @@ import { MemoryStorageService } from "@bitwarden/common/platform/services/memory import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { DialogService } from "@bitwarden/components"; import { LoginGuard } from "../../auth/guards/login.guard"; @@ -52,7 +51,6 @@ import { I18nService } from "../../platform/services/i18n.service"; import { EncryptedMessageHandlerService } from "../../services/encrypted-message-handler.service"; import { NativeMessageHandlerService } from "../../services/native-message-handler.service"; import { NativeMessagingService } from "../../services/native-messaging.service"; -import { PasswordRepromptService } from "../../vault/services/password-reprompt.service"; import { SearchBarService } from "../layout/search/search-bar.service"; import { DesktopFileDownloadService } from "./desktop-file-download.service"; @@ -113,7 +111,6 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK"); StateServiceAbstraction, ], }, - { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService }, { provide: StateServiceAbstraction, useClass: ElectronStateService, diff --git a/apps/desktop/src/vault/app/components/password-reprompt.component.html b/apps/desktop/src/vault/app/components/password-reprompt.component.html deleted file mode 100644 index 1ff853c278c..00000000000 --- a/apps/desktop/src/vault/app/components/password-reprompt.component.html +++ /dev/null @@ -1,57 +0,0 @@ - diff --git a/apps/desktop/src/vault/app/components/password-reprompt.component.ts b/apps/desktop/src/vault/app/components/password-reprompt.component.ts deleted file mode 100644 index f63da5ed48e..00000000000 --- a/apps/desktop/src/vault/app/components/password-reprompt.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from "@angular/core"; - -import { PasswordRepromptComponent as BasePasswordRepromptComponent } from "@bitwarden/angular/vault/components/password-reprompt.component"; - -@Component({ - templateUrl: "password-reprompt.component.html", -}) -export class PasswordRepromptComponent extends BasePasswordRepromptComponent {} diff --git a/apps/desktop/src/vault/app/vault/add-edit.component.ts b/apps/desktop/src/vault/app/vault/add-edit.component.ts index 8a90d6a7e1a..00ae8022b16 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.ts +++ b/apps/desktop/src/vault/app/vault/add-edit.component.ts @@ -16,8 +16,8 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; const BroadcasterSubscriptionId = "AddEditComponent"; diff --git a/apps/desktop/src/vault/app/vault/vault.component.ts b/apps/desktop/src/vault/app/vault/vault.component.ts index 0b419b5088f..7930663499d 100644 --- a/apps/desktop/src/vault/app/vault/vault.component.ts +++ b/apps/desktop/src/vault/app/vault/vault.component.ts @@ -22,13 +22,13 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { SearchBarService } from "../../../app/layout/search/search-bar.service"; import { GeneratorComponent } from "../../../app/tools/generator.component"; diff --git a/apps/desktop/src/vault/app/vault/view.component.ts b/apps/desktop/src/vault/app/vault/view.component.ts index b6bf63d6e64..adb72dbfe33 100644 --- a/apps/desktop/src/vault/app/vault/view.component.ts +++ b/apps/desktop/src/vault/app/vault/view.component.ts @@ -23,9 +23,9 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; const BroadcasterSubscriptionId = "ViewComponent"; diff --git a/apps/desktop/src/vault/services/password-reprompt.service.ts b/apps/desktop/src/vault/services/password-reprompt.service.ts deleted file mode 100644 index ebff838d5ca..00000000000 --- a/apps/desktop/src/vault/services/password-reprompt.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from "@angular/core"; - -import { PasswordRepromptService as BasePasswordRepromptService } from "@bitwarden/angular/vault/services/password-reprompt.service"; - -import { PasswordRepromptComponent } from "../app/components/password-reprompt.component"; - -@Injectable() -export class PasswordRepromptService extends BasePasswordRepromptService { - component = PasswordRepromptComponent; -} diff --git a/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts index cf721098a2c..415bd6516c2 100644 --- a/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts @@ -6,9 +6,9 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; // eslint-disable-next-line no-restricted-imports import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent } from "../../../reports/pages/exposed-passwords-report.component"; diff --git a/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts index 9d62073e066..4cc68b1f9d0 100644 --- a/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts @@ -6,8 +6,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; // eslint-disable-next-line no-restricted-imports import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent } from "../../../reports/pages/inactive-two-factor-report.component"; diff --git a/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts index b410b63e0ff..93652239a11 100644 --- a/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts @@ -6,9 +6,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; // eslint-disable-next-line no-restricted-imports import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent } from "../../../reports/pages/reused-passwords-report.component"; diff --git a/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts index 53ce0304507..e8fbc0ed5e6 100644 --- a/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts @@ -5,8 +5,8 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; // eslint-disable-next-line no-restricted-imports import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent } from "../../../reports/pages/unsecured-websites-report.component"; diff --git a/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts index 68619b27514..540f71d91dc 100644 --- a/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts @@ -6,9 +6,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; // eslint-disable-next-line no-restricted-imports import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from "../../../reports/pages/weak-passwords-report.component"; diff --git a/apps/web/src/app/auth/settings/emergency-access/emergency-add-edit.component.ts b/apps/web/src/app/auth/settings/emergency-access/emergency-add-edit.component.ts index 925ebbf3ea6..fdb72518b19 100644 --- a/apps/web/src/app/auth/settings/emergency-access/emergency-add-edit.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/emergency-add-edit.component.ts @@ -15,9 +15,9 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { AddEditComponent as BaseAddEditComponent } from "../../../vault/individual-vault/add-edit.component"; diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index b2e44d7e3db..4df6557fac5 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -21,13 +21,11 @@ import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/p import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service"; -import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { PolicyListService } from "../admin-console/core/policy-list.service"; import { HtmlStorageService } from "../core/html-storage.service"; import { I18nService } from "../core/i18n.service"; import { CollectionAdminService } from "../vault/core/collection-admin.service"; -import { PasswordRepromptService } from "../vault/core/password-reprompt.service"; import { BroadcasterMessagingService } from "./broadcaster-messaging.service"; import { EventService } from "./event.service"; @@ -87,10 +85,6 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service"; provide: BaseStateServiceAbstraction, useExisting: StateService, }, - { - provide: PasswordRepromptServiceAbstraction, - useClass: PasswordRepromptService, - }, { provide: FileDownloadService, useClass: WebFileDownloadService, diff --git a/apps/web/src/app/reports/pages/cipher-report.component.ts b/apps/web/src/app/reports/pages/cipher-report.component.ts index c6af91fb962..80c41b0c252 100644 --- a/apps/web/src/app/reports/pages/cipher-report.component.ts +++ b/apps/web/src/app/reports/pages/cipher-report.component.ts @@ -3,9 +3,9 @@ import { Directive, ViewChild, ViewContainerRef } from "@angular/core"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { AddEditComponent } from "../../vault/individual-vault/add-edit.component"; import { AddEditComponent as OrgAddEditComponent } from "../../vault/org-vault/add-edit.component"; diff --git a/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts b/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts index 38b18dae160..dec2f707d4a 100644 --- a/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/exposed-passwords-report.component.ts @@ -4,9 +4,9 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts b/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts index a70ede0102e..ad257d7e596 100644 --- a/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts +++ b/apps/web/src/app/reports/pages/inactive-two-factor-report.component.ts @@ -5,9 +5,9 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/reused-passwords-report.component.ts b/apps/web/src/app/reports/pages/reused-passwords-report.component.ts index 95851eca1b7..431b571fa16 100644 --- a/apps/web/src/app/reports/pages/reused-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/reused-passwords-report.component.ts @@ -4,9 +4,9 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts b/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts index 14bc961e347..42ddb3b1d5d 100644 --- a/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts +++ b/apps/web/src/app/reports/pages/unsecured-websites-report.component.ts @@ -3,9 +3,9 @@ import { Component, OnInit } from "@angular/core"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts index ddea66a6a91..b5bad708afd 100644 --- a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts @@ -4,10 +4,10 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { BadgeTypes } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { CipherReportComponent } from "./cipher-report.component"; diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index 08f14a5cce9..86c0da0d908 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -79,7 +79,6 @@ import { PasswordGeneratorHistoryComponent } from "../tools/password-generator-h import { AccessComponent } from "../tools/send/access.component"; import { AddEditComponent as SendAddEditComponent } from "../tools/send/add-edit.component"; import { ToolsComponent } from "../tools/tools.component"; -import { PasswordRepromptComponent } from "../vault/components/password-reprompt.component"; import { PremiumBadgeComponent } from "../vault/components/premium-badge.component"; import { AddEditCustomFieldsComponent } from "../vault/individual-vault/add-edit-custom-fields.component"; import { AddEditComponent } from "../vault/individual-vault/add-edit.component"; @@ -159,7 +158,6 @@ import { SharedModule } from "./shared.module"; OrgWeakPasswordsReportComponent, GeneratorComponent, PasswordGeneratorHistoryComponent, - PasswordRepromptComponent, PreferencesComponent, PremiumBadgeComponent, ProfileComponent, @@ -246,7 +244,6 @@ import { SharedModule } from "./shared.module"; OrgWeakPasswordsReportComponent, GeneratorComponent, PasswordGeneratorHistoryComponent, - PasswordRepromptComponent, PreferencesComponent, PremiumBadgeComponent, ProfileComponent, diff --git a/apps/web/src/app/vault/components/password-reprompt.component.html b/apps/web/src/app/vault/components/password-reprompt.component.html deleted file mode 100644 index ebd81976566..00000000000 --- a/apps/web/src/app/vault/components/password-reprompt.component.html +++ /dev/null @@ -1,53 +0,0 @@ - diff --git a/apps/web/src/app/vault/components/password-reprompt.component.ts b/apps/web/src/app/vault/components/password-reprompt.component.ts deleted file mode 100644 index f63da5ed48e..00000000000 --- a/apps/web/src/app/vault/components/password-reprompt.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from "@angular/core"; - -import { PasswordRepromptComponent as BasePasswordRepromptComponent } from "@bitwarden/angular/vault/components/password-reprompt.component"; - -@Component({ - templateUrl: "password-reprompt.component.html", -}) -export class PasswordRepromptComponent extends BasePasswordRepromptComponent {} 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 07d061311cf..934062fa699 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 @@ -22,6 +22,7 @@ queryParamsHandling="merge" title="{{ 'editItemWithName' | i18n : cipher.name }}" type="button" + appStopProp > {{ cipher.name }} 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 7bd9677c759..7c70a797437 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 @@ -55,7 +55,7 @@ export class VaultCipherRowComponent { @HostListener("click") protected click() { this.router.navigate([], { - queryParams: { cipherId: this.cipher.id }, + queryParams: { itemId: this.cipher.id }, queryParamsHandling: "merge", }); } diff --git a/apps/web/src/app/vault/core/password-reprompt.service.ts b/apps/web/src/app/vault/core/password-reprompt.service.ts deleted file mode 100644 index 22bbcf44d7f..00000000000 --- a/apps/web/src/app/vault/core/password-reprompt.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from "@angular/core"; - -import { PasswordRepromptService as BasePasswordRepromptService } from "@bitwarden/angular/vault/services/password-reprompt.service"; - -import { PasswordRepromptComponent } from "../components/password-reprompt.component"; - -@Injectable() -export class PasswordRepromptService extends BasePasswordRepromptService { - component = PasswordRepromptComponent; -} diff --git a/apps/web/src/app/vault/individual-vault/add-edit.component.ts b/apps/web/src/app/vault/individual-vault/add-edit.component.ts index 61dd6124b41..74e7a9e6e30 100644 --- a/apps/web/src/app/vault/individual-vault/add-edit.component.ts +++ b/apps/web/src/app/vault/individual-vault/add-edit.component.ts @@ -17,10 +17,10 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; @Component({ selector: "app-vault-add-edit", diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 69cc909cab7..3b8d60d263b 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -52,7 +52,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; @@ -60,6 +59,7 @@ import { CollectionDetailsResponse } from "@bitwarden/common/vault/models/respon import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { DialogService, Icons } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { CollectionDialogAction, diff --git a/apps/web/src/app/vault/org-vault/add-edit.component.ts b/apps/web/src/app/vault/org-vault/add-edit.component.ts index bea55856a4a..c8a37c087ad 100644 --- a/apps/web/src/app/vault/org-vault/add-edit.component.ts +++ b/apps/web/src/app/vault/org-vault/add-edit.component.ts @@ -16,10 +16,10 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { AddEditComponent as BaseAddEditComponent } from "../individual-vault/add-edit.component"; diff --git a/apps/web/src/app/vault/org-vault/vault.component.ts b/apps/web/src/app/vault/org-vault/vault.component.ts index 48f927e4d01..dcdd73da3c4 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.ts +++ b/apps/web/src/app/vault/org-vault/vault.component.ts @@ -47,12 +47,12 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { DialogService, Icons } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { GroupService, GroupView } from "../../admin-console/organizations/core"; import { openEntityEventsDialog } from "../../admin-console/organizations/manage/entity-events.component"; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index bbea250bcdf..e2019c7d33f 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -136,7 +136,6 @@ import { FolderService as FolderServiceAbstraction, InternalFolderService, } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction"; import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; @@ -156,13 +155,13 @@ import { ImportService, ImportServiceAbstraction, } from "@bitwarden/importer"; +import { PasswordRepromptService } from "@bitwarden/vault"; import { AuthGuard } from "../auth/guards/auth.guard"; import { UnauthGuard } from "../auth/guards/unauth.guard"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "../platform/abstractions/form-validation-errors.service"; import { BroadcasterService } from "../platform/services/broadcaster.service"; import { FormValidationErrorsService } from "../platform/services/form-validation-errors.service"; -import { PasswordRepromptService } from "../vault/services/password-reprompt.service"; import { LOCALES_DIRECTORY, @@ -186,6 +185,8 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; AuthGuard, UnauthGuard, ModalService, + PasswordRepromptService, + { provide: WINDOW, useValue: window }, { provide: LOCALE_ID, @@ -603,7 +604,6 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; UserVerificationApiServiceAbstraction, ], }, - { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService }, { provide: OrganizationServiceAbstraction, useClass: OrganizationService, diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts index 3aca51e44a8..fb065587bf9 100644 --- a/libs/angular/src/vault/components/add-edit.component.ts +++ b/libs/angular/src/vault/components/add-edit.component.ts @@ -21,7 +21,6 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; @@ -34,6 +33,7 @@ import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; @Directive() export class AddEditComponent implements OnInit, OnDestroy { diff --git a/libs/angular/src/vault/components/password-reprompt.component.ts b/libs/angular/src/vault/components/password-reprompt.component.ts deleted file mode 100644 index 1094b379316..00000000000 --- a/libs/angular/src/vault/components/password-reprompt.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Directive } from "@angular/core"; - -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; - -import { ModalRef } from "../../components/modal/modal.ref"; - -/** - * Used to verify the user's Master Password for the "Master Password Re-prompt" feature only. - * See UserVerificationComponent for any other situation where you need to verify the user's identity. - */ -@Directive() -export class PasswordRepromptComponent { - showPassword = false; - masterPassword = ""; - - constructor( - private modalRef: ModalRef, - private cryptoService: CryptoService, - private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService - ) {} - - togglePassword() { - this.showPassword = !this.showPassword; - } - - async submit() { - const storedMasterKey = await this.cryptoService.getOrDeriveMasterKey(this.masterPassword); - if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, storedMasterKey))) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("invalidMasterPassword") - ); - return; - } - - this.modalRef.close(true); - } -} diff --git a/libs/angular/src/vault/components/view.component.ts b/libs/angular/src/vault/components/view.component.ts index 40523afd850..781034aa9f3 100644 --- a/libs/angular/src/vault/components/view.component.ts +++ b/libs/angular/src/vault/components/view.component.ts @@ -27,7 +27,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { EncArrayBuffer } from "@bitwarden/common/platform/models/domain/enc-array-buffer"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.view"; @@ -35,6 +34,7 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { DialogService } from "@bitwarden/components"; +import { PasswordRepromptService } from "@bitwarden/vault"; const BroadcasterSubscriptionId = "ViewComponent"; diff --git a/libs/common/src/vault/abstractions/password-reprompt.service.ts b/libs/common/src/vault/abstractions/password-reprompt.service.ts deleted file mode 100644 index 6253425b34d..00000000000 --- a/libs/common/src/vault/abstractions/password-reprompt.service.ts +++ /dev/null @@ -1,5 +0,0 @@ -export abstract class PasswordRepromptService { - protectedFields: () => string[]; - showPasswordPrompt: () => Promise; - enabled: () => Promise; -} diff --git a/libs/vault/src/components/password-reprompt.component.html b/libs/vault/src/components/password-reprompt.component.html new file mode 100644 index 00000000000..4ee1c16238d --- /dev/null +++ b/libs/vault/src/components/password-reprompt.component.html @@ -0,0 +1,31 @@ +
+ + + {{ "passwordConfirmation" | i18n }} + + + {{ "passwordConfirmationDesc" | i18n }} + + + {{ "masterPass" | i18n }} + + + + + + + + + + +
diff --git a/libs/vault/src/components/password-reprompt.component.ts b/libs/vault/src/components/password-reprompt.component.ts new file mode 100644 index 00000000000..fd8da6c574a --- /dev/null +++ b/libs/vault/src/components/password-reprompt.component.ts @@ -0,0 +1,68 @@ +import { DialogRef } from "@angular/cdk/dialog"; +import { Component } from "@angular/core"; +import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { + AsyncActionsModule, + ButtonModule, + DialogModule, + FormFieldModule, + IconButtonModule, +} from "@bitwarden/components"; + +/** + * Used to verify the user's Master Password for the "Master Password Re-prompt" feature only. + * See UserVerificationComponent for any other situation where you need to verify the user's identity. + */ +@Component({ + standalone: true, + selector: "vault-password-reprompt", + imports: [ + JslibModule, + AsyncActionsModule, + ButtonModule, + DialogModule, + FormFieldModule, + IconButtonModule, + ReactiveFormsModule, + ], + templateUrl: "password-reprompt.component.html", +}) +export class PasswordRepromptComponent { + formGroup = this.formBuilder.group({ + masterPassword: ["", { validators: [Validators.required], updateOn: "submit" }], + }); + + constructor( + protected cryptoService: CryptoService, + protected platformUtilsService: PlatformUtilsService, + protected i18nService: I18nService, + protected formBuilder: FormBuilder, + protected dialogRef: DialogRef + ) {} + + submit = async () => { + const storedMasterKey = await this.cryptoService.getOrDeriveMasterKey( + this.formGroup.value.masterPassword + ); + if ( + !(await this.cryptoService.compareAndUpdateKeyHash( + this.formGroup.value.masterPassword, + storedMasterKey + )) + ) { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("invalidMasterPassword") + ); + return; + } + + this.dialogRef.close(true); + }; +} diff --git a/libs/vault/src/index.ts b/libs/vault/src/index.ts index e69de29bb2d..bf6b7f91c23 100644 --- a/libs/vault/src/index.ts +++ b/libs/vault/src/index.ts @@ -0,0 +1 @@ +export { PasswordRepromptService } from "./services/password-reprompt.service"; diff --git a/libs/angular/src/vault/services/password-reprompt.service.spec.ts b/libs/vault/src/services/password-reprompt.service.spec.ts similarity index 70% rename from libs/angular/src/vault/services/password-reprompt.service.spec.ts rename to libs/vault/src/services/password-reprompt.service.spec.ts index f2fb64bac3a..300b98215c2 100644 --- a/libs/angular/src/vault/services/password-reprompt.service.spec.ts +++ b/libs/vault/src/services/password-reprompt.service.spec.ts @@ -1,8 +1,7 @@ import { MockProxy, mock } from "jest-mock-extended"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; - -import { ModalService } from "../../services/modal.service"; +import { UserVerificationService } from "@bitwarden/common/src/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { DialogService } from "@bitwarden/components"; import { PasswordRepromptService } from "./password-reprompt.service"; @@ -10,13 +9,13 @@ describe("PasswordRepromptService", () => { let passwordRepromptService: PasswordRepromptService; let userVerificationService: MockProxy; - let modalService: MockProxy; + let dialogService: MockProxy; beforeEach(() => { - modalService = mock(); + dialogService = mock(); userVerificationService = mock(); - passwordRepromptService = new PasswordRepromptService(modalService, userVerificationService); + passwordRepromptService = new PasswordRepromptService(dialogService, userVerificationService); }); describe("enabled()", () => { diff --git a/libs/angular/src/vault/services/password-reprompt.service.ts b/libs/vault/src/services/password-reprompt.service.ts similarity index 61% rename from libs/angular/src/vault/services/password-reprompt.service.ts rename to libs/vault/src/services/password-reprompt.service.ts index 7a06771a456..4b4a7a65f67 100644 --- a/libs/angular/src/vault/services/password-reprompt.service.ts +++ b/libs/vault/src/services/password-reprompt.service.ts @@ -1,9 +1,9 @@ import { Injectable } from "@angular/core"; +import { lastValueFrom } from "rxjs"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; +import { DialogService } from "@bitwarden/components"; -import { ModalService } from "../../services/modal.service"; import { PasswordRepromptComponent } from "../components/password-reprompt.component"; /** @@ -11,11 +11,9 @@ import { PasswordRepromptComponent } from "../components/password-reprompt.compo * See UserVerificationService for any other situation where you need to verify the user's identity. */ @Injectable() -export class PasswordRepromptService implements PasswordRepromptServiceAbstraction { - protected component = PasswordRepromptComponent; - +export class PasswordRepromptService { constructor( - private modalService: ModalService, + private dialogService: DialogService, private userVerificationService: UserVerificationService ) {} @@ -28,13 +26,12 @@ export class PasswordRepromptService implements PasswordRepromptServiceAbstracti return true; } - const ref = this.modalService.open(this.component, { allowMultipleModals: true }); + const dialog = this.dialogService.open(PasswordRepromptComponent, { + ariaModal: true, + }); - if (ref == null) { - return false; - } + const result = await lastValueFrom(dialog.closed); - const result = await ref.onClosedPromise(); return result === true; } From 7190bad1b0e81c6178b468dcdd8b6e7533ffe7ee Mon Sep 17 00:00:00 2001 From: Vince Grassia <593223+vgrassia@users.noreply.github.com> Date: Thu, 5 Oct 2023 15:14:10 -0400 Subject: [PATCH 02/33] Standardize Snapcraft commands in workflows (#6351) --- .github/workflows/release-cli.yml | 4 +--- .github/workflows/release-desktop.yml | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 73c0f24affd..04a8a04f4f5 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -157,8 +157,6 @@ jobs: - name: Install Snap uses: samuelmeuli/action-snapcraft@d33c176a9b784876d966f80fb1b461808edc0641 # v2.1.1 - with: - snapcraft_token: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }} - name: Download artifacts if: ${{ github.event.inputs.release_type != 'Dry Run' }} @@ -185,7 +183,7 @@ jobs: env: SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }} run: | - snapcraft push bw_${{ env._PKG_VERSION }}_amd64.snap --release stable + snapcraft upload bw_${{ env._PKG_VERSION }}_amd64.snap --release stable snapcraft logout choco: diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 28314e8e9c1..b9ffa80e512 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -270,8 +270,6 @@ jobs: - name: Install Snap uses: samuelmeuli/action-snapcraft@d33c176a9b784876d966f80fb1b461808edc0641 # v2.1.1 - env: - SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }} - name: Setup run: mkdir dist @@ -302,8 +300,8 @@ jobs: env: SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }} run: | - /snap/bin/snapcraft upload bitwarden_${{ env._PKG_VERSION }}_amd64.snap --release stable - /snap/bin/snapcraft logout + snapcraft upload bitwarden_${{ env._PKG_VERSION }}_amd64.snap --release stable + snapcraft logout working-directory: apps/desktop/dist choco: From a8d0ca7aafbb76dbb649d00b4287ebd208c8f5b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:31:50 +0000 Subject: [PATCH 03/33] Autosync the updated translations (#6523) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 6 ++ apps/web/src/locales/ar/messages.json | 6 ++ apps/web/src/locales/az/messages.json | 10 +- apps/web/src/locales/be/messages.json | 8 +- apps/web/src/locales/bg/messages.json | 6 ++ apps/web/src/locales/bn/messages.json | 6 ++ apps/web/src/locales/bs/messages.json | 6 ++ apps/web/src/locales/ca/messages.json | 6 ++ apps/web/src/locales/cs/messages.json | 6 ++ apps/web/src/locales/cy/messages.json | 6 ++ apps/web/src/locales/da/messages.json | 6 ++ apps/web/src/locales/de/messages.json | 6 ++ apps/web/src/locales/el/messages.json | 6 ++ apps/web/src/locales/en_GB/messages.json | 6 ++ apps/web/src/locales/en_IN/messages.json | 6 ++ apps/web/src/locales/eo/messages.json | 6 ++ apps/web/src/locales/es/messages.json | 6 ++ apps/web/src/locales/et/messages.json | 6 ++ apps/web/src/locales/eu/messages.json | 6 ++ apps/web/src/locales/fa/messages.json | 116 ++++++++++++----------- apps/web/src/locales/fi/messages.json | 14 ++- apps/web/src/locales/fil/messages.json | 6 ++ apps/web/src/locales/fr/messages.json | 8 +- apps/web/src/locales/gl/messages.json | 6 ++ apps/web/src/locales/he/messages.json | 6 ++ apps/web/src/locales/hi/messages.json | 6 ++ apps/web/src/locales/hr/messages.json | 6 ++ apps/web/src/locales/hu/messages.json | 6 ++ apps/web/src/locales/id/messages.json | 6 ++ apps/web/src/locales/it/messages.json | 6 ++ apps/web/src/locales/ja/messages.json | 6 ++ apps/web/src/locales/ka/messages.json | 6 ++ apps/web/src/locales/km/messages.json | 6 ++ apps/web/src/locales/kn/messages.json | 6 ++ apps/web/src/locales/ko/messages.json | 6 ++ apps/web/src/locales/lv/messages.json | 6 ++ apps/web/src/locales/ml/messages.json | 6 ++ apps/web/src/locales/mr/messages.json | 6 ++ apps/web/src/locales/my/messages.json | 6 ++ apps/web/src/locales/nb/messages.json | 6 ++ apps/web/src/locales/ne/messages.json | 6 ++ apps/web/src/locales/nl/messages.json | 6 ++ apps/web/src/locales/nn/messages.json | 6 ++ apps/web/src/locales/or/messages.json | 6 ++ apps/web/src/locales/pl/messages.json | 6 ++ apps/web/src/locales/pt_BR/messages.json | 6 ++ apps/web/src/locales/pt_PT/messages.json | 6 ++ apps/web/src/locales/ro/messages.json | 6 ++ apps/web/src/locales/ru/messages.json | 6 ++ apps/web/src/locales/si/messages.json | 6 ++ apps/web/src/locales/sk/messages.json | 6 ++ apps/web/src/locales/sl/messages.json | 6 ++ apps/web/src/locales/sr/messages.json | 10 +- apps/web/src/locales/sr_CS/messages.json | 6 ++ apps/web/src/locales/sv/messages.json | 6 ++ apps/web/src/locales/te/messages.json | 6 ++ apps/web/src/locales/th/messages.json | 6 ++ apps/web/src/locales/tr/messages.json | 6 ++ apps/web/src/locales/uk/messages.json | 10 +- apps/web/src/locales/vi/messages.json | 6 ++ apps/web/src/locales/zh_CN/messages.json | 16 +++- apps/web/src/locales/zh_TW/messages.json | 6 ++ 62 files changed, 444 insertions(+), 72 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 0f57c449591..8eaf6e1f011 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index b21a4e49d18..cd5c185c172 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 151d237b91e..1822746405e 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -7170,12 +7170,18 @@ "message": "Beta" }, "baseUrl": { - "message": "Server URL" + "message": "Server URL-si" }, "aliasDomain": { - "message": "Alias domain" + "message": "Domen ləqəbi" }, "alreadyHaveAccount": { "message": "Artıq bir hesabınız var?" + }, + "customBillingStart": { + "message": "Özəl faktura əks olunmur. Son faktura üçün " + }, + "customBillingEnd": { + "message": " səhifəni ziyarət edin." } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 8ead5f134b1..fbefebf78a1 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -226,7 +226,7 @@ "message": "Праверце, ці не скампраметаваны пароль." }, "passwordExposed": { - "message": "Гэты пароль быў скампраметаваны наступную колькасць разоў: $VALUE$. Вы павінны змяніць яго.", + "message": "Гэты пароль быў скампраметаваны наступную колькасць раз(оў): $VALUE$. Вы павінны змяніць яго.", "placeholders": { "value": { "content": "$1", @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Ужо маеце ўліковы запіс?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index f8c2bd5c15b..f6036998998 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Вече имате регистрация?" + }, + "customBillingStart": { + "message": "Персонализираното таксуване не е отразено. Посетете страницата за " + }, + "customBillingEnd": { + "message": " за последните фактури." } } diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index 2d5a3f43794..25f2a837f52 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 220ad900cc8..7fa48aeaa5e 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index a2276a8443c..30ee2f589f3 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Ja tens un compte?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index 1ca1c246d2f..24e3817f615 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Už máte účet?" + }, + "customBillingStart": { + "message": "Vlastní fakturace není zahrnuta. Navštivte stránku " + }, + "customBillingEnd": { + "message": " pro nejnovější faktury." } } diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index ca615764d5c..8de532e7e26 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Har allerede en konto?" + }, + "customBillingStart": { + "message": "Tilpasset fakturering vises ikke. Besøg siden " + }, + "customBillingEnd": { + "message": " for seneste fakturering." } } diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index f48baa55bcf..09c18f83434 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Hast du bereits ein Konto?" + }, + "customBillingStart": { + "message": "Eine individuelle Abrechnung wird nicht berücksichtigt. Besuche die " + }, + "customBillingEnd": { + "message": " Seite für die aktuelle Rechnung." } } diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index b146e47ddc5..5004408eafa 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 0810036fc16..be316df1621 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 3df21cfb599..277641ca9a0 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index b96027b9d4e..77407c53c8f 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index f313f9ba16d..18d85d28661 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "¿Ya tienes una cuenta?" + }, + "customBillingStart": { + "message": "Facturación personalizada no reflejada. Visite el " + }, + "customBillingEnd": { + "message": " para la última facturación." } } diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 1a56831f0fd..97f5c17bf81 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index e50570a9b68..92d3823cd1e 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index 51e292d2d9e..e564086f871 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -709,7 +709,7 @@ "message": "یک خطای غیر منتظره رخ داده است." }, "expirationDateError": { - "message": "Please select an expiration date that is in the future." + "message": "لطفاً تاریخ انقضایی را انتخاب کنید که در آینده است." }, "emailAddress": { "message": "نشانی ایمیل" @@ -952,7 +952,7 @@ "message": "کپی کد تأیید" }, "copyUuid": { - "message": "Copy UUID" + "message": "کپی UUID" }, "warning": { "message": "هشدار" @@ -1291,19 +1291,19 @@ "message": "خطا در رمزگشایی پرونده‌ی درون ریزی شده. کلید رمزگذاری شما با کلید رمزگذاری استفاده شده برای درون ریزی داده‌ها مطابقت ندارد." }, "importDestination": { - "message": "Import destination" + "message": "مقصد برون ریزی" }, "learnAboutImportOptions": { - "message": "Learn about your import options" + "message": "درباره گزینه‌های برون ریزی خود بیاموزید" }, "selectImportFolder": { - "message": "Select a folder" + "message": "یک پوشه انتخاب کنید" }, "selectImportCollection": { - "message": "Select a collection" + "message": "انتخاب یک مجموعه" }, "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", + "message": "اگر می‌خواهید محتوای فایل وارد شده به $DESTINATION$ منتقل شود، این گزینه را انتخاب کنید", "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", "placeholders": { "destination": { @@ -1313,7 +1313,7 @@ } }, "importUnassignedItemsError": { - "message": "File contains unassigned items." + "message": "فایل حاوی موارد اختصاص نیافته است." }, "selectFormat": { "message": "فرمت پرونده‌ی درون ریزی را انتخاب کنید" @@ -1423,10 +1423,10 @@ "message": "با درخواست یک مرحله اضافی هنگام ورود، حساب خود را ایمن کنید." }, "twoStepLoginTeamsDesc": { - "message": "Enable two-step login for your organization." + "message": "ورود دو مرحله ای را برای سازمان خود فعال کنید." }, "twoStepLoginEnterpriseDescStart": { - "message": "Enforce Bitwarden Two-step Login options for members by using the ", + "message": "گزینه‌های ورود دو مرحله ای Bitwarden را برای اعضا اعمال کنید با استفاده از ", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Enforce Bitwarden Two-step Login options for members by using the Two-step Login Policy.'" }, "twoStepLoginPolicy": { @@ -1925,7 +1925,7 @@ "message": "۱ گیگابایت فضای ذخیره‌سازی رمزنگاری شده برای پرونده‌های پیوست." }, "premiumSignUpTwoStepOptions": { - "message": "Proprietary two-step login options such as YubiKey and Duo." + "message": "گزینه های ورود اضافی دو مرحله ای مانند YubiKey و Duo." }, "premiumSignUpEmergency": { "message": "دسترسی اضطراری" @@ -2041,7 +2041,7 @@ } }, "paymentChargedWithUnpaidSubscription": { - "message": "Your payment method will be charged for any unpaid subscriptions." + "message": "روش پرداخت شما برای هرگونه اشتراک پرداخت نشده شارژ خواهد شد." }, "paymentChargedWithTrial": { "message": "طرح شما با یک دوره آزمایشی رایگان ۷ روزه همراه است. تا پایان دوره آزمایشی از روش پرداخت شما هزینه ای کسر نمی‌شود. هر زمان که مایل بودید می‌توانید آن را لغو کنید." @@ -3477,7 +3477,7 @@ "message": "کلید رمزگذاری را به‌روز کنید" }, "updateEncryptionSchemeDesc": { - "message": "We've changed the encryption scheme to provide better security. Update your encryption key now by entering your master password below." + "message": "ما طرح رمزگذاری را برای ارائه امنیت بهتر تغییر داده‌ایم. کلید رمزگذاری خود را اکنون با وارد کردن کلمه اصلی خود در زیر به روز کنید." }, "updateEncryptionKeyWarning": { "message": "پس از به‌روزرسانی کلید رمزگذاری، باید از سیستم خارج شوید و دوباره به همه برنامه‌های Bitwarden که در حال حاضر استفاده می‌کنید (مانند برنامه تلفن همراه یا برنامه‌های افزودنی مرورگر) وارد شوید. عدم خروج و ورود مجدد (که کلید رمزگذاری جدید شما را دانلود می‌کند) ممکن است منجر به خراب شدن داده‌ها شود. ما سعی خواهیم کرد شما را به طور خودکار از سیستم خارج کنیم، اما ممکن است با تأخیر انجام شود." @@ -3534,7 +3534,7 @@ "message": "انتخاب کنید که گاو‌صندوق شما چه زمانی عمل توقف زمانی گاوصندوق را انجام دهد." }, "vaultTimeoutLogoutDesc": { - "message": "Choose when your vault will be logged out." + "message": "انتخاب کنید که گاوصندوق شما چه زمانی از سیستم خارج می‌شود." }, "oneMinute": { "message": "۱ دقیقه" @@ -3625,7 +3625,7 @@ "message": "این مورد دارای پرونده های پیوست قدیمی است که باید اصلاح شوند." }, "attachmentFixDescription": { - "message": "This attachment uses outdated encryption. Select 'Fix' to download, re-encrypt, and re-upload the attachment." + "message": "این پیوست از رمزگذاری قدیمی استفاده می‌کند. برای دانلود، رمزگذاری مجدد، و بارگذاری مجدد پیوست، «اصلاح» را انتخاب کنید." }, "fix": { "message": "اصلاح", @@ -4721,7 +4721,7 @@ "message": "خطا" }, "accountRecoveryManageUsers": { - "message": "Manage users must also be granted with the manage account recovery permission" + "message": "مدیر کاربران همچنین باید مجوز مدیریت بازیابی حساب کاربری را داشته باشد" }, "setupProvider": { "message": "راه اندازی ارائه دهنده" @@ -4933,7 +4933,7 @@ "message": "حذف برون ریزی گاوصندوق شخصی" }, "disablePersonalVaultExportDescription": { - "message": "Do not allow members to export data from their individual vault." + "message": "به اعضا اجازه ندهید که داده‌های گاوصندوق شخصی خود را برون ریزی کنند." }, "vaultExportDisabled": { "message": "برون ریزی گاوصندوق غیرفعال شده است" @@ -5437,7 +5437,7 @@ "message": "در حال برون ریزی گاوصندوق سازمان" }, "exportingIndividualVaultDescription": { - "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.", + "message": "فقط موارد شخصی گاوصندوق مرتبط با $EMAIL$ برون ریزی خواهند شد. موارد گاوصندوق سازمان شامل نخواهد شد. فقط اطلاعات مورد گاوصندوق برون ریزی خواهد شد و شامل تاریخچه کلمه عبور مرتبط یا پیوست نمی‌شود.", "placeholders": { "email": { "content": "$1", @@ -5446,7 +5446,7 @@ } }, "exportingOrganizationVaultDesc": { - "message": "Only the organization vault associated with $ORGANIZATION$ will be exported. Items in individual vaults or other organizations will not be included.", + "message": "فقط گاوصدوق سازمان مرتبط با $ORGANIZATION$ برون ریزی خواهد شد. موارد موجود در گاوصندوق‌های فردی یا سایر سازمان‌ها شامل نمی‌شوند.", "placeholders": { "organization": { "content": "$1", @@ -6836,58 +6836,58 @@ "message": "تنظیمات KDF را به‌روز کنید" }, "loginInitiated": { - "message": "Login initiated" + "message": "ورود به سیستم آغاز شد" }, "deviceApprovalRequired": { - "message": "Device approval required. Select an approval option below:" + "message": "تأیید دستگاه لازم است. یک روش تأیید انتخاب کنید:" }, "rememberThisDevice": { - "message": "Remember this device" + "message": "این دستگاه را به خاطر بسپار" }, "uncheckIfPublicDevice": { - "message": "Uncheck if using a public device" + "message": "اگر از دستگاه عمومی استفاده می‌کنید علامت را بردارید" }, "approveFromYourOtherDevice": { - "message": "Approve from your other device" + "message": "تأیید با دستگاه دیگرتان" }, "requestAdminApproval": { - "message": "Request admin approval" + "message": "درخواست تأیید مدیر" }, "approveWithMasterPassword": { - "message": "Approve with master password" + "message": "تأیید با کلمه عبور اصلی" }, "trustedDeviceEncryption": { - "message": "Trusted device encryption" + "message": "رمزگذاری دستگاه مورد اعتماد" }, "trustedDevices": { - "message": "Trusted devices" + "message": "دستگاه‌های مورد اعتماد" }, "memberDecryptionOptionTdeDescriptionPartOne": { - "message": "Once authenticated, members will decrypt vault data using a key stored on their device. The", + "message": "پس از احراز هویت، اعضا با استفاده از کلید ذخیره شده در دستگاه خود، داده‌های گاوصندوق را رمزگشایی می‌کنند.", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO Required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionOptionTdeDescriptionLinkOne": { - "message": "single organization", + "message": "سازمان واحد", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionOptionTdeDescriptionPartTwo": { - "message": "policy,", + "message": "سیاست‌ها", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionOptionTdeDescriptionLinkTwo": { - "message": "SSO required", + "message": "SSO الزامی است", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionOptionTdeDescriptionPartThree": { - "message": "policy, and", + "message": "سیاست‌ها و", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionOptionTdeDescriptionLinkThree": { - "message": "account recovery administration", + "message": "مدیریت بازیابی حساب کاربری", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionOptionTdeDescriptionPartFour": { - "message": "policy with automatic enrollment will turn on when this option is used.", + "message": "سیاست‌ها با ثبت نام خودکار زمانی که از این گزینه استفاده می‌شود روشن می‌شود.", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Once authenticated, members will decrypt vault data using a key stored on their device. The single organization policy, SSO required policy, and account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "notFound": { @@ -6978,7 +6978,7 @@ "message": "حذف اعضایی که کلمه عبور اصلی ندارند بدون تعیین کلمه عبور برای آنها ممکن است دسترسی به حساب کامل آن‌ها را محدود کند." }, "approvedAuthRequest": { - "message": "Approved device for $ID$.", + "message": "دستگاه تأیید شده برای $ID$.", "placeholders": { "id": { "content": "$1", @@ -6987,7 +6987,7 @@ } }, "rejectedAuthRequest": { - "message": "Denied device for $ID$.", + "message": "دستگاه رد شده برای $ID$.", "placeholders": { "id": { "content": "$1", @@ -6996,7 +6996,7 @@ } }, "requestedDeviceApproval": { - "message": "Requested device approval." + "message": "تأیید دستگاه درخواست." }, "startYour7DayFreeTrialOfBitwardenFor": { "message": "نسخه آزمایشی رایگان ۷ روزه Bitwarden را با $ORG$ شروع کنید", @@ -7014,28 +7014,28 @@ "message": "پرچم منطقه انتخاب شد" }, "accountSuccessfullyCreated": { - "message": "Account successfully created!" + "message": "حساب کاربری با موفقیت ایجاد شد!" }, "adminApprovalRequested": { - "message": "Admin approval requested" + "message": "تأیید مدیر درخواست شد" }, "adminApprovalRequestSentToAdmins": { - "message": "Your request has been sent to your admin." + "message": "درخواست شما به مدیرتان فرستاده شد." }, "youWillBeNotifiedOnceApproved": { - "message": "You will be notified once approved." + "message": "به محض تأیید مطلع خواهید شد." }, "troubleLoggingIn": { - "message": "Trouble logging in?" + "message": "در ورود مشکلی دارید؟" }, "loginApproved": { - "message": "Login approved" + "message": "ورود تأیید شد" }, "userEmailMissing": { - "message": "User email missing" + "message": "ایمیل کاربر وجود ندارد" }, "deviceTrusted": { - "message": "Device trusted" + "message": "دستگاه مورد اعتماد است" }, "sendsNoItemsTitle": { "message": "ارسال‌های فعالی نیست", @@ -7106,7 +7106,7 @@ "message": "حساب‌های خدمات اضافی" }, "includedServiceAccounts": { - "message": "Your plan comes with $COUNT$ service accounts.", + "message": "طرح شما با حساب خدمات $COUNT$ همراه است.", "placeholders": { "count": { "content": "$1", @@ -7115,7 +7115,7 @@ } }, "addAdditionalServiceAccounts": { - "message": "You can add additional service accounts for $COST$ per month.", + "message": "می‌توانید سرویس اضافی حساب‌ها را با $COST$ در ماه اضافه کنید.", "placeholders": { "cost": { "content": "$1", @@ -7148,10 +7148,10 @@ "message": "حداکثر هزینه حساب خدمات بالقوه" }, "loggedInExclamation": { - "message": "Logged in!" + "message": "وارد شده!" }, "smBetaEndedDesc": { - "message": "The Secrets Manager Beta ended $BETA_ENDING_DATE$. You have $DAYS$ days left to add Secrets Manager to your paid subscription and maintain access to Secrets Manager data. Contact Customer Success to add Secrets Manager to your subscription.", + "message": "بتای مدیر اسرار $BETA_ENDING_DATE$ به پایان رسید. $DAYS$ روز فرصت دارید تا بتا مدیر اسرار را به اشتراک پولی خود اضافه کنید و دسترسی به داده‌های مدیر اسرار را حفظ کنید. برای افزودن مدیر اسرار به اشتراک خود، با پشتیبانی مشتری تماس بگیرید.", "placeholders": { "beta_ending_date": { "content": "$1", @@ -7164,18 +7164,24 @@ } }, "betaEnding": { - "message": "Beta Ending" + "message": "آزمایشی در حال اتمام است" }, "beta": { - "message": "Beta" + "message": "آزمایشی" }, "baseUrl": { - "message": "Server URL" + "message": "نشانی اینترنتی سرور" }, "aliasDomain": { - "message": "Alias domain" + "message": "دامنه مستعار" }, "alreadyHaveAccount": { - "message": "Already have an account?" + "message": "پیشتر حساب کاربری داشته اید؟" + }, + "customBillingStart": { + "message": "صورتحساب سفارشی منعکس نمی‌شود. بازدید کنید " + }, + "customBillingEnd": { + "message": " صفحه برای آخرین صورتحساب" } } diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 07e3bb4cc8a..bb2d7ae1995 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -1341,7 +1341,7 @@ } }, "options": { - "message": "Asetukset" + "message": "Valinnat" }, "preferences": { "message": "Asetukset" @@ -6591,13 +6591,13 @@ "message": "Tallenna lisenssi" }, "projectPeopleDescription": { - "message": "Myönnä ryhmille tai henkilöille tämän projektin käyttöoikeus." + "message": "Myönnä ryhmille tai henkilöille käyttöoikeus projektiin." }, "projectPeopleSelectHint": { "message": "Syötä tai valitse henkilöitä tai ryhmiä" }, "projectServiceAccountsDescription": { - "message": "Myönnä palvelutileille tämän projektin käyttöoikeus." + "message": "Myönnä palvelutileille käyttöoikeus projektiin." }, "projectServiceAccountsSelectHint": { "message": "Syötä tai valitse palvelutilit" @@ -7164,7 +7164,7 @@ } }, "betaEnding": { - "message": "Beta päättyy" + "message": "Beta on päättynyt" }, "beta": { "message": "Beta" @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Onko sinulla jo tili?" + }, + "customBillingStart": { + "message": "Mukautettu laskutus ei näy. Löydät viimeisimmän laskutuksen " + }, + "customBillingEnd": { + "message": " -sivulta." } } diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index 062195bdaf9..b68a81ca3e7 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index aaa39033815..d02cfef1541 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -2535,7 +2535,7 @@ "message": "L’identifiant externe peut être utilisé comme référence ou pour lier cette ressource à un système externe tel qu’un répertoire utilisateur." }, "nestCollectionUnder": { - "message": "Collection imbriquée dessous" + "message": "Collection imbriquée sous" }, "accessControl": { "message": "Contrôle d’accès" @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Vous avez déjà un compte ?" + }, + "customBillingStart": { + "message": "La facturation personnalisée n'apparaît pas. Visitez la page " + }, + "customBillingEnd": { + "message": " pour la dernière facturation." } } diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 7fe4fe66a9b..70f447848d9 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 9764f7d39da..b6463a2d7cc 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 1911a71a36e..dbf22380177 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Već imaš račun?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index 51ded2ab77c..faa4f61db77 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Van már saját fiók?" + }, + "customBillingStart": { + "message": "Az egyedi számlázás nem jelenik meg. Kerssük fel " + }, + "customBillingEnd": { + "message": " oldalt a legújabb számlázásért." } } diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 0932b38ef0a..13e5d53c17c 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 1b58ad965e3..c726f0e5182 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Hai già un account?" + }, + "customBillingStart": { + "message": "La fatturazione personalizzata non è riflessa. Visita la " + }, + "customBillingEnd": { + "message": " pagina per l'ultima fatturazione." } } diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index efc64056030..6ec8f42fdf3 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "既にアカウントをお持ちですか?" + }, + "customBillingStart": { + "message": "カスタム請求は反映されていません。" + }, + "customBillingEnd": { + "message": "のページで最新の請求書をご覧いただけます。" } } diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 47aa45f2fa1..9bfddfad59e 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 8f210948f70..c349b08791a 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index ddf2a0a702d..6e4a514c11a 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 5f41e5c7ede..fcfc4628e6b 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Jau ir konts?" + }, + "customBillingStart": { + "message": "Pielāgotie norēķini nav atspoguļoti. Jāapmeklē " + }, + "customBillingEnd": { + "message": " sadaļu, lai gūtu ieskatu par jaunākajiem rēķiniem." } } diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 8d6832cb9a8..c29e0f42fad 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index c24948cacaa..656d48456cc 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index da1681c73aa..15621984c0b 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index a0eb8b17d09..09196ea1c8a 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Aangepaste facturering is niet weergeven. Bezoek de " + }, + "customBillingEnd": { + "message": " pagina voor laatste facturering." } } diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 6de911d6782..da3d7e5a0c3 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index b21b83ffdb7..f6d8e35497a 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Masz już konto?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 5da497922a6..c5333d785f0 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Já tem uma conta?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 38627692658..32c5276b0a1 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Já tem uma conta?" + }, + "customBillingStart": { + "message": "A faturação personalizada não é refletida. Visite a " + }, + "customBillingEnd": { + "message": " página para a faturação mais recente." } } diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 8de54c1494b..1df9da3f6bf 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 3feac542568..705198ac753 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Уже зарегистрированы?" + }, + "customBillingStart": { + "message": "Пользовательские счета не отображаются. Посетите страницу " + }, + "customBillingEnd": { + "message": " для получения последней информации о выставлении счетов." } } diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index be9cbdaff31..efdf9a8c86e 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 56752c2ddb6..08276bda0bc 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Už máte účet?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 62dda84d524..0f5ff850696 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index f037202a975..a1844d86fc8 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -7170,12 +7170,18 @@ "message": "Бета" }, "baseUrl": { - "message": "Server URL" + "message": "УРЛ Сервера" }, "aliasDomain": { - "message": "Alias domain" + "message": "Домен алијаса" }, "alreadyHaveAccount": { "message": "Већ имате налог?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 95a8c7fd421..78ab8fa1c70 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index 253bee8631e..c5880efe924 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Har du redan ett konto?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index f620a91ec72..7d1a4bebebd 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index 593169a336c..b429ed92dae 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 25285f2c317..627eec657cb 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Zaten hesabınız var mı?" + }, + "customBillingStart": { + "message": "Özel faturalandırma yansıtılmıyor. Son fatura sayfasını " + }, + "customBillingEnd": { + "message": " ziyaret edin." } } diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index deb7f18773b..29111deeb91 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -7170,12 +7170,18 @@ "message": "Бета" }, "baseUrl": { - "message": "Server URL" + "message": "URL-адреса сервера" }, "aliasDomain": { - "message": "Alias domain" + "message": "Псевдонім домену" }, "alreadyHaveAccount": { "message": "Вже маєте обліковий запис?" + }, + "customBillingStart": { + "message": "Власний рахунок не відображений. Відвідайте " + }, + "customBillingEnd": { + "message": " для отримання останнього рахунку." } } diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 96eef230907..1483e23a2be 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "Already have an account?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index af2cb944862..7f3fc7f09fa 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -603,13 +603,13 @@ "message": "登录或者创建一个账户来访问您的安全密码库。" }, "loginWithDevice": { - "message": "设备登录" + "message": "使用设备登录" }, "loginWithDeviceEnabledNote": { "message": "设备登录必须在 Bitwarden 应用程序的设置中启用。需要其他登录选项吗?" }, "loginWithMasterPassword": { - "message": "主密码登录" + "message": "使用主密码登录" }, "createAccount": { "message": "创建账户" @@ -785,7 +785,7 @@ } }, "enterVerificationCodeApp": { - "message": "请输入验证器应用程序中的 6 位验证码。" + "message": "请输入您的验证器应用中的 6 位数验证码。" }, "enterVerificationCodeEmail": { "message": "请输入发送给电子邮件 $EMAIL$ 的 6 位数验证码。", @@ -1519,7 +1519,7 @@ "message": "密钥" }, "twoStepAuthenticatorEnterCode": { - "message": "输入应用程序中的 6 位验证码" + "message": "输入应用程序中的 6 位数验证码" }, "twoStepAuthenticatorReaddDesc": { "message": "如果您要把它添加到另一个设备,下面是您的验证器应用所需要的二维码(或密钥)。" @@ -1615,7 +1615,7 @@ "message": "输入您希望接收验证码的电子邮件" }, "twoFactorEmailEnterCode": { - "message": "输入电子邮件中的 6 位验证码" + "message": "输入电子邮件中的 6 位数验证码" }, "sendEmail": { "message": "发送电子邮件" @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "已经有一个账户?" + }, + "customBillingStart": { + "message": "未返回自定义费用记录。请访问 " + }, + "customBillingEnd": { + "message": " 页面获取最新的账单。" } } diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 192212eff19..eba26af5767 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -7177,5 +7177,11 @@ }, "alreadyHaveAccount": { "message": "已經有帳戶?" + }, + "customBillingStart": { + "message": "Custom billing is not reflected. Visit the " + }, + "customBillingEnd": { + "message": " page for latest invoicing." } } From e1203c2d815af4f77ae2d1d6724dabd46b05988f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:32:53 +0000 Subject: [PATCH 04/33] Autosync the updated translations (#6521) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/fa/messages.json | 88 ++++++++++---------- apps/desktop/src/locales/sr/messages.json | 2 +- apps/desktop/src/locales/uk/messages.json | 2 +- apps/desktop/src/locales/zh_CN/messages.json | 4 +- apps/desktop/src/locales/zh_TW/messages.json | 2 +- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index dad420ca1d1..363159ecbdd 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -476,7 +476,7 @@ "message": "بیشترین حجم پرونده ۵۰۰ مگابایت است." }, "encryptionKeyMigrationRequired": { - "message": "Encryption key migration required. Please login through the web vault to update your encryption key." + "message": "انتقال کلید رمزگذاری مورد نیاز است. لطفاً از طریق گاوصندوق وب وارد شوید تا کلید رمزگذاری خود را به روز کنید." }, "editedFolder": { "message": "پوشه ذخیره شد" @@ -1078,7 +1078,7 @@ "message": "۱ گیگابایت فضای ذخیره‌سازی رمزنگاری شده برای پرونده‌های پیوست." }, "premiumSignUpTwoStepOptions": { - "message": "Proprietary two-step login options such as YubiKey and Duo." + "message": "گزینه های ورود اضافی دو مرحله ای مانند YubiKey و Duo." }, "premiumSignUpReports": { "message": "گزارش‌های بهداشت رمز عبور، سلامت حساب و نقض داده‌ها برای ایمن نگهداشتن گاوصندوق شما." @@ -1493,7 +1493,7 @@ "message": "یک گاوصندوق خارج شده درخواست احراز هویت مجدد را برای دسترسی آن می‌دهد." }, "unlockMethodNeededToChangeTimeoutActionDesc": { - "message": "Set up an unlock method to change your vault timeout action." + "message": "یک روش بازگشایی برای پایان زمان مجاز تنظیم کنید." }, "lock": { "message": "قفل", @@ -1985,7 +1985,7 @@ "message": "برون ریزی گاو‌صندوق شخصی" }, "exportingIndividualVaultDescription": { - "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.", + "message": "فقط موارد شخصی گاوصندوق مرتبط با $EMAIL$ برون ریزی خواهند شد. موارد گاوصندوق سازمان شامل نخواهد شد. فقط اطلاعات مورد گاوصندوق برون ریزی خواهد شد و شامل تاریخچه کلمه عبور مرتبط یا پیوست نمی‌شود.", "placeholders": { "email": { "content": "$1", @@ -2110,7 +2110,7 @@ "message": "با دستگاه دیگری وارد شوید" }, "loginInitiated": { - "message": "Login initiated" + "message": "ورود به سیستم آغاز شد" }, "notificationSentDevice": { "message": "یک اعلان به دستگاه شما ارسال شده است." @@ -2250,35 +2250,35 @@ "message": "به‌روز رسانی تنظیمات توصیه شده" }, "deviceApprovalRequired": { - "message": "Device approval required. Select an approval option below:" + "message": "تأیید دستگاه لازم است. یک روش تأیید انتخاب کنید:" }, "rememberThisDevice": { - "message": "Remember this device" + "message": "این دستگاه را به خاطر بسپار" }, "uncheckIfPublicDevice": { - "message": "Uncheck if using a public device" + "message": "اگر از دستگاه عمومی استفاده می‌کنید علامت را بردارید" }, "approveFromYourOtherDevice": { - "message": "Approve from your other device" + "message": "تأیید با دستگاه دیگرتان" }, "requestAdminApproval": { - "message": "Request admin approval" + "message": "درخواست تأیید مدیر" }, "approveWithMasterPassword": { - "message": "Approve with master password" + "message": "تأیید با کلمه عبور اصلی" }, "region": { - "message": "Region" + "message": "منطقه" }, "ssoIdentifierRequired": { - "message": "Organization SSO identifier is required." + "message": "شناسه سازمان SSO مورد نیاز است." }, "eu": { - "message": "EU", + "message": "اروپا", "description": "European Union" }, "loggingInOn": { - "message": "Logging in on" + "message": "ورود با" }, "usDomain": { "message": "bitwarden.com" @@ -2287,46 +2287,46 @@ "message": "bitwarden.eu" }, "selfHostedServer": { - "message": "self-hosted" + "message": "خود میزبان" }, "accessDenied": { "message": "دسترسی رد شد. شما اجازه مشاهده این صفحه را ندارید." }, "accountSuccessfullyCreated": { - "message": "Account successfully created!" + "message": "حساب کاربری با موفقیت ایجاد شد!" }, "adminApprovalRequested": { - "message": "Admin approval requested" + "message": "تأیید مدیر درخواست شد" }, "adminApprovalRequestSentToAdmins": { - "message": "Your request has been sent to your admin." + "message": "درخواست شما به مدیرتان فرستاده شد." }, "youWillBeNotifiedOnceApproved": { - "message": "You will be notified once approved." + "message": "به محض تأیید مطلع خواهید شد." }, "troubleLoggingIn": { - "message": "Trouble logging in?" + "message": "در ورود مشکلی دارید؟" }, "loginApproved": { - "message": "Login approved" + "message": "ورود تأیید شد" }, "userEmailMissing": { - "message": "User email missing" + "message": "ایمیل کاربر وجود ندارد" }, "deviceTrusted": { - "message": "Device trusted" + "message": "دستگاه مورد اعتماد است" }, "inputRequired": { - "message": "Input is required." + "message": "ورودی ضروری است." }, "required": { - "message": "required" + "message": "ضروری" }, "search": { - "message": "Search" + "message": "جستجو" }, "inputMinLength": { - "message": "Input must be at least $COUNT$ characters long.", + "message": "ورودی باید حداقل $COUNT$ کاراکتر داشته باشد.", "placeholders": { "count": { "content": "$1", @@ -2335,7 +2335,7 @@ } }, "inputMaxLength": { - "message": "Input must not exceed $COUNT$ characters in length.", + "message": "طول ورودی نباید بیش از $COUNT$ کاراکتر باشد.", "placeholders": { "count": { "content": "$1", @@ -2344,7 +2344,7 @@ } }, "inputForbiddenCharacters": { - "message": "The following characters are not allowed: $CHARACTERS$", + "message": "کاراکترهای زیر مجاز نیستند: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -2353,7 +2353,7 @@ } }, "inputMinValue": { - "message": "Input value must be at least $MIN$.", + "message": "مقدار ورودی باید حداقل $MIN$ باشد.", "placeholders": { "min": { "content": "$1", @@ -2362,7 +2362,7 @@ } }, "inputMaxValue": { - "message": "Input value must not exceed $MAX$.", + "message": "مقدار ورودی نباید از $MAX$ تجاوز کند.", "placeholders": { "max": { "content": "$1", @@ -2371,17 +2371,17 @@ } }, "multipleInputEmails": { - "message": "1 or more emails are invalid" + "message": "یک یا چند ایمیل نامعتبر است" }, "inputTrimValidator": { - "message": "Input must not contain only whitespace.", + "message": "ورودی نباید فقط حاوی فضای خالی باشد.", "description": "Notification to inform the user that a form's input can't contain only whitespace." }, "inputEmail": { - "message": "Input is not an email address." + "message": "ورودی یک نشانی ایمیل نیست." }, "fieldsNeedAttention": { - "message": "$COUNT$ field(s) above need your attention.", + "message": "فیلد $COUNT$ در بالا به توجه شما نیاز دارد.", "placeholders": { "count": { "content": "$1", @@ -2390,22 +2390,22 @@ } }, "selectPlaceholder": { - "message": "-- Select --" + "message": "-- انتخاب --" }, "multiSelectPlaceholder": { - "message": "-- Type to filter --" + "message": "-- برای فیلتر تایپ کنید --" }, "multiSelectLoading": { - "message": "Retrieving options..." + "message": "در حال بازیابی گزینه‌ها..." }, "multiSelectNotFound": { - "message": "No items found" + "message": "موردی یافت نشد" }, "multiSelectClearAll": { - "message": "Clear all" + "message": "پاک‌کردن همه" }, "plusNMore": { - "message": "+ $QUANTITY$ more", + "message": "+ $QUANTITY$ بیشتر", "placeholders": { "quantity": { "content": "$1", @@ -2414,9 +2414,9 @@ } }, "submenu": { - "message": "Submenu" + "message": "زیرمنو" }, "aliasDomain": { - "message": "Alias domain" + "message": "دامنه مستعار" } } diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 7ce3fe92ab4..392dbe4a141 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -2417,6 +2417,6 @@ "message": "Под-мени" }, "aliasDomain": { - "message": "Alias domain" + "message": "Домен алијаса" } } diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index 61e50fb0e44..a3489dce44e 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -2417,6 +2417,6 @@ "message": "Підменю" }, "aliasDomain": { - "message": "Alias domain" + "message": "Псевдонім домену" } } diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 2e24b4d9080..f656607fe60 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -594,7 +594,7 @@ "message": "继续" }, "enterVerificationCodeApp": { - "message": "请输入您的身份验证器应用中的 6 位验证码。" + "message": "请输入您的验证器应用中的 6 位数验证码。" }, "enterVerificationCodeEmail": { "message": "请输入发送给电子邮件 $EMAIL$ 的 6 位数验证码。", @@ -2083,7 +2083,7 @@ "message": "密码库" }, "loginWithMasterPassword": { - "message": "主密码登录" + "message": "使用主密码登录" }, "loggingInAs": { "message": "正登录为" diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 819e81b91f5..3e8cf00867b 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -2119,7 +2119,7 @@ "message": "Please make sure your vault is unlocked and Fingerprint phrase matches the other device." }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "指紋短語" }, "needAnotherOption": { "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" From 437f39d4fbc24c8d61df0b425c768e1e828d101e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 07:37:02 +0000 Subject: [PATCH 05/33] Autosync the updated translations (#6522) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 24 +++++ apps/browser/src/_locales/az/messages.json | 44 +++++++-- apps/browser/src/_locales/be/messages.json | 24 +++++ apps/browser/src/_locales/bg/messages.json | 50 +++++++--- apps/browser/src/_locales/bn/messages.json | 24 +++++ apps/browser/src/_locales/bs/messages.json | 24 +++++ apps/browser/src/_locales/ca/messages.json | 24 +++++ apps/browser/src/_locales/cs/messages.json | 24 +++++ apps/browser/src/_locales/cy/messages.json | 24 +++++ apps/browser/src/_locales/da/messages.json | 24 +++++ apps/browser/src/_locales/de/messages.json | 24 +++++ apps/browser/src/_locales/el/messages.json | 24 +++++ apps/browser/src/_locales/en_GB/messages.json | 24 +++++ apps/browser/src/_locales/en_IN/messages.json | 24 +++++ apps/browser/src/_locales/es/messages.json | 24 +++++ apps/browser/src/_locales/et/messages.json | 24 +++++ apps/browser/src/_locales/eu/messages.json | 24 +++++ apps/browser/src/_locales/fa/messages.json | 94 ++++++++++++------- apps/browser/src/_locales/fi/messages.json | 24 +++++ apps/browser/src/_locales/fil/messages.json | 24 +++++ apps/browser/src/_locales/fr/messages.json | 26 ++++- apps/browser/src/_locales/gl/messages.json | 24 +++++ apps/browser/src/_locales/he/messages.json | 24 +++++ apps/browser/src/_locales/hi/messages.json | 24 +++++ apps/browser/src/_locales/hr/messages.json | 24 +++++ apps/browser/src/_locales/hu/messages.json | 42 +++++++-- apps/browser/src/_locales/id/messages.json | 24 +++++ apps/browser/src/_locales/it/messages.json | 24 +++++ apps/browser/src/_locales/ja/messages.json | 24 +++++ apps/browser/src/_locales/ka/messages.json | 24 +++++ apps/browser/src/_locales/km/messages.json | 24 +++++ apps/browser/src/_locales/kn/messages.json | 24 +++++ apps/browser/src/_locales/ko/messages.json | 24 +++++ apps/browser/src/_locales/lt/messages.json | 24 +++++ apps/browser/src/_locales/lv/messages.json | 24 +++++ apps/browser/src/_locales/ml/messages.json | 24 +++++ apps/browser/src/_locales/mr/messages.json | 24 +++++ apps/browser/src/_locales/my/messages.json | 24 +++++ apps/browser/src/_locales/nb/messages.json | 24 +++++ apps/browser/src/_locales/ne/messages.json | 24 +++++ apps/browser/src/_locales/nl/messages.json | 26 ++++- apps/browser/src/_locales/nn/messages.json | 24 +++++ apps/browser/src/_locales/or/messages.json | 24 +++++ apps/browser/src/_locales/pl/messages.json | 24 +++++ apps/browser/src/_locales/pt_BR/messages.json | 24 +++++ apps/browser/src/_locales/pt_PT/messages.json | 24 +++++ apps/browser/src/_locales/ro/messages.json | 24 +++++ apps/browser/src/_locales/ru/messages.json | 24 +++++ apps/browser/src/_locales/si/messages.json | 24 +++++ apps/browser/src/_locales/sk/messages.json | 24 +++++ apps/browser/src/_locales/sl/messages.json | 24 +++++ apps/browser/src/_locales/sr/messages.json | 26 ++++- apps/browser/src/_locales/sv/messages.json | 24 +++++ apps/browser/src/_locales/te/messages.json | 24 +++++ apps/browser/src/_locales/th/messages.json | 24 +++++ apps/browser/src/_locales/tr/messages.json | 26 ++++- apps/browser/src/_locales/uk/messages.json | 32 ++++++- apps/browser/src/_locales/vi/messages.json | 24 +++++ apps/browser/src/_locales/zh_CN/messages.json | 30 +++++- apps/browser/src/_locales/zh_TW/messages.json | 24 +++++ apps/browser/store/locales/az/copy.resx | 2 +- 61 files changed, 1519 insertions(+), 79 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index ba917a9e681..c3ba5c4a950 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "التعبئة التلقائية" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "إنشاء كلمة مرور (تم النسخ)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "لا توجد تسجيلات دخول مطابقة." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "افتح خزنتك" }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index b784592a3b0..483dc2c14f1 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Avto-doldurma" }, + "autoFillLogin": { + "message": "Giriş avto-doldurma" + }, + "autoFillCard": { + "message": "Kart avto-doldurma" + }, + "autoFillIdentity": { + "message": "Kimlik avto-doldurma" + }, "generatePasswordCopied": { "message": "Parol yarat (kopyalandı)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Uyğun gələn hesab yoxdur." }, + "noCards": { + "message": "Kart yoxdur" + }, + "noIdentities": { + "message": "Kimlik yoxdur" + }, + "addLoginMenu": { + "message": "Giriş əlavə et" + }, + "addCardMenu": { + "message": "Kart əlavə et" + }, + "addIdentityMenu": { + "message": "Kimlik əlavə et" + }, "unlockVaultMenu": { "message": "Anbarın kilidini açın" }, @@ -671,7 +695,7 @@ "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { - "message": "Anbarı ixrac et" + "message": "Anbarı xaricə köçür" }, "fileFormat": { "message": "Fayl formatı" @@ -681,19 +705,19 @@ "description": "WARNING (should stay in capitalized letters if the language permits)" }, "confirmVaultExport": { - "message": "Anbarın ixracını təsdiqləyin" + "message": "Anbarın xaricə köçürülməsini təsdiqləyin" }, "exportWarningDesc": { - "message": "Bu ixrac faylındakı anbar verilənləriniz şifrələnməmiş formatdadır. İxrac edilən faylı, güvənli olmayan kanallar üzərində saxlamamalı və ya göndərməməlisiniz (e-poçt kimi). Bu faylı işiniz bitdikdən sonra dərhal silin." + "message": "Xaricə köçürdüyünüz bu fayldakı datanız şifrələnməmiş formatdadır. Bu faylı güvənli olmayan kanallar (e-poçt kimi) üzərində saxlamamalı və ya göndərməməlisiniz. İşiniz bitdikdən sonra faylı dərhal silin." }, "encExportKeyWarningDesc": { - "message": "Bu ixrac faylı, hesabınızın şifrələmə açarını istifadə edərək verilənlərinizi şifrələyir. Hesabınızın şifrələmə açarını döndərsəniz, bu ixrac faylının şifrəsini aça bilməyəcəyiniz üçün yenidən ixrac etməli olacaqsınız." + "message": "Xaricə köçürdüyünüz bu fayldakı data, hesabınızın şifrələmə açarı istifadə edilərək şifrələnir. Hesabınızın şifrələmə açarını dəyişdirsəniz, bu faylın şifrəsini aça bilməyəcəksiniz və onu yenidən xaricə köçürməli olacaqsınız." }, "encExportAccountWarningDesc": { "message": "Hesab şifrələmə açarları, hər Bitwarden istifadəçi hesabı üçün unikaldır, buna görə də şifrələnmiş bir ixracı, fərqli bir hesaba idxal edə bilməzsiniz." }, "exportMasterPassword": { - "message": "Anbar verilənlərinizi ixrac etmək üçün ana parolunuzu daxil edin." + "message": "Anbar datanızı xaricə köçürmək üçün ana parolunuzu daxil edin." }, "shared": { "message": "Paylaşılan" @@ -799,7 +823,7 @@ "message": "YubiKey və Duo kimi mülkiyyətçi iki addımlı giriş seçimləri." }, "ppremiumSignUpReports": { - "message": "Anbarınızın təhlükəsiyini təmin etmək üçün parol gigiyenası, hesab sağlamlığı və verilənlərin pozulması hesabatları." + "message": "Anbarınızın təhlükəsizliyini təmin etmək üçün parol gigiyenası, hesab sağlamlığı və data pozuntusu hesabatları." }, "ppremiumSignUpTotp": { "message": "Anbarınızdakı hesablar üçün TOTP təsdiqləmə kodu (2FA) yaradıcısı." @@ -2408,18 +2432,18 @@ "description": "Toggling an expand/collapse state." }, "aliasDomain": { - "message": "Alias domain" + "message": "Domen ləqəbi" }, "passwordRepromptDisabledAutofillOnPageLoad": { - "message": "Items with master password re-prompt cannot be auto-filled on page load. Auto-fill on page load turned off.", + "message": "\"Ana parolu təkrar soruş\" özəlliyi olan elementlər səhifə yüklənəndə avto-doldurulmur. \"Səhifə yüklənəndə avto-doldurma\" özəlliyi söndürülüb.", "description": "Toast message for describing that master password re-prompt cannot be auto-filled on page load." }, "autofillOnPageLoadSetToDefault": { - "message": "Auto-fill on page load set to use default setting.", + "message": "\"Səhifə yüklənəndə avto-doldurma\" özəlliyi ilkin tənzimləməni istifadə etmək üzrə tənzimləndi.", "description": "Toast message for informing the user that auto-fill on page load has been set to the default setting." }, "turnOffMasterPasswordPromptToEditField": { - "message": "Turn off master password re-prompt to edit this field", + "message": "Bu sahəyə düzəliş etmək üçün \"Ana parolu təkrar soruş\"u söndürün", "description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item." } } diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index e941d525936..d0c1bac2bb7 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Аўтазапаўненне" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Генерыраваць пароль (з капіяваннем)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Няма адпаведных лагінаў." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Разблакіраваць сховішча" }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 08451607d2b..c96fadbd422 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -14,7 +14,7 @@ "message": "Впишете се или създайте нов абонамент, за да достъпите защитен трезор." }, "createAccount": { - "message": "Създаване на абонамент" + "message": "Създаване на акаунт" }, "login": { "message": "Вписване" @@ -91,6 +91,15 @@ "autoFill": { "message": "Автоматично дописване" }, + "autoFillLogin": { + "message": "Авт. попълване на данни за вход" + }, + "autoFillCard": { + "message": "Самопопълваща се карта" + }, + "autoFillIdentity": { + "message": "Самопопълваща се самоличност" + }, "generatePasswordCopied": { "message": "Генериране на парола (копирана)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Няма съвпадащи записи." }, + "noCards": { + "message": "Няма карти" + }, + "noIdentities": { + "message": "Няма самоличности" + }, + "addLoginMenu": { + "message": "Добавяне на запис за вход" + }, + "addCardMenu": { + "message": "Добавяне на карта" + }, + "addIdentityMenu": { + "message": "Добавяне на самоличност" + }, "unlockVaultMenu": { "message": "Отключете трезора си" }, @@ -467,7 +491,7 @@ "message": "Грешен код за потвърждаване" }, "valueCopied": { - "message": "$VALUE$ — копирано", + "message": "Копирано е $VALUE$", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -537,7 +561,7 @@ "message": "Копирана парола" }, "uri": { - "message": "Адрес" + "message": "Унифициран идентификатор на ресурс" }, "uriPosition": { "message": "Адрес $POSITION$", @@ -550,7 +574,7 @@ } }, "newUri": { - "message": "Нов адрес" + "message": "Нов унифициран идентификатор на ресурс" }, "addedItem": { "message": "Елементът е добавен" @@ -631,7 +655,7 @@ "message": "Да се обнови ли паролата в Bitwarden?" }, "notificationChangeSave": { - "message": "Да, нека се обнови сега" + "message": "Осъвременяване" }, "notificationUnlockDesc": { "message": "Отключете трезора си в Битуорден, за да завършите заявката за автоматично попълване." @@ -684,7 +708,7 @@ "message": "Потвърждаване на изнасянето на трезора" }, "exportWarningDesc": { - "message": "Данните от трезора ви ще се изнесат в незащитен формат. Не го пращайте по незащитени канали като е-поща. Изтрийте файла незабавно след като свършите работата си с него." + "message": "Този износ съдържа данни на трезора ви в некриптиран формат. Не трябва да съхранявате или изпращате износния файл през незащитени канали (като имейл). Изтрийте файла моментално след като свършите работата си с него." }, "encExportKeyWarningDesc": { "message": "При изнасяне данните се шифрират с ключа ви. Ако го смените, ще трябва наново да ги изнесете, защото няма да може да дешифрирате настоящия файл." @@ -699,10 +723,10 @@ "message": "Споделено" }, "learnOrg": { - "message": "Разберете повече за организациите" + "message": "Научете за организациите" }, "learnOrgConfirmation": { - "message": "Битуорден позволява да споделяте части от трезора си чрез използването на организация. Искате ли да научите повече от сайта bitwarden.com?" + "message": "Битуорден позволява да споделяте елементи от трезора си а други, използвайки организация. Бихте ли посетили сайта bitwarden.com, за да научите повече?" }, "moveToOrganization": { "message": "Преместване в организация" @@ -781,7 +805,7 @@ "message": "Управление на абонамента" }, "premiumManageAlert": { - "message": "Можете да управлявате абонамента си през сайта bitwarden.com. Искате ли да го посетите сега?" + "message": "Може да управлявате членството си в мрежата на трезора в bitwarden.com. Искате ли да посетите уебсайта сега?" }, "premiumRefresh": { "message": "Опресняване на абонамента" @@ -901,7 +925,7 @@ "message": "Регистрацията е защитена с двустепенно удостоверяване, но никой от настроените доставчици на удостоверяване не се поддържа от този браузър." }, "noTwoStepProviders2": { - "message": "Пробвайте с поддържан уеб браузър (като Chrome или Firefox) и други доставчици на удостоверяване, които се поддържат от браузърите (като специални програми за удостоверяване)." + "message": "Употребявайте поддържан браузър (като Chrome, Firefox) и/или добавете други доставчици на удостоверяване, които се поддържат по-добре от браузърите (като специални програми за удостоверяване)." }, "twoStepOptions": { "message": "Настройки на двустепенното удостоверяване" @@ -920,10 +944,10 @@ "description": "'Authy' and 'Google Authenticator' are product names and should not be translated." }, "yubiKeyTitle": { - "message": "Устройство YubiKey OTP" + "message": "Ключ за сигурност YubiKey OTP" }, "yubiKeyDesc": { - "message": "Използвайте устройство на YubiKey, за да влезете в абонамента си. Поддържат се моделите YubiKey 4, 4 Nano, 4C и NEO." + "message": "Използвайте ключа за сигурност YubiKey, за да влезете в акаунта си. Работи с устройствата YubiKey 4, 4 Nano, 4C и NEO." }, "duoDesc": { "message": "Удостоверяване чрез Duo Security, с ползване на приложението Duo Mobile, SMS, телефонен разговор или устройство U2F.", @@ -2096,7 +2120,7 @@ "message": "собствен хостинг" }, "thirdParty": { - "message": "Third-party" + "message": "Трета страна" }, "thirdPartyServerMessage": { "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index edee2852116..f8c5fb8c85b 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "স্বতঃপূরণ" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "পাসওয়ার্ড তৈরি করুন (অনুলিপিকৃত)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "কোনও মিলত লগইন নেই।" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index e984a88b7bc..d5d1bbb16a6 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 7839cceebcb..af85e586c80 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Emplenament automàtic" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Genera contrasenya (copiada)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No hi ha inicis de sessió coincidents." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "1. Desbloquegeu la caixa forta." }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 71446db9f2c..e9b3bf997cd 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automatické vyplňování" }, + "autoFillLogin": { + "message": "Automaticky vyplnit přihlášení" + }, + "autoFillCard": { + "message": "Automaticky vyplnit kartu" + }, + "autoFillIdentity": { + "message": "Automaticky vyplnit identitu" + }, "generatePasswordCopied": { "message": "Vygenerovat heslo a zkopírovat do schránky" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Žádné odpovídající přihlašovací údaje" }, + "noCards": { + "message": "Žádné karty" + }, + "noIdentities": { + "message": "Žádné identity" + }, + "addLoginMenu": { + "message": "Přidat přihlašovací údaje" + }, + "addCardMenu": { + "message": "Přidat kartu" + }, + "addIdentityMenu": { + "message": "Přidat identitu" + }, "unlockVaultMenu": { "message": "Odemknout Váš trezor" }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 7292370f533..ff3ccc684f7 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Llenwi'n awtomatig" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Cynhyrchu cyfrinair (wedi'i gopïo)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Datgloi'ch cell" }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 1bc0ed79e5a..5dd437827f3 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-udfyld" }, + "autoFillLogin": { + "message": "Autoudfyld login" + }, + "autoFillCard": { + "message": "Autoudfyld kort" + }, + "autoFillIdentity": { + "message": "Autoudfyld identitet" + }, "generatePasswordCopied": { "message": "Generér adgangskode (kopieret)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Ingen matchende logins" }, + "noCards": { + "message": "Ingen kort" + }, + "noIdentities": { + "message": "Ingen identiteter" + }, + "addLoginMenu": { + "message": "Tilføj login" + }, + "addCardMenu": { + "message": "Tilføj kort" + }, + "addIdentityMenu": { + "message": "Tilføj identitet" + }, "unlockVaultMenu": { "message": "Lås din boks op" }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 443d4294cd3..3edd462918f 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-Ausfüllen" }, + "autoFillLogin": { + "message": "Zugangsdaten automatisch ausfüllen" + }, + "autoFillCard": { + "message": "Karte automatisch ausfüllen" + }, + "autoFillIdentity": { + "message": "Identität automatisch ausfüllen" + }, "generatePasswordCopied": { "message": "Passwort generieren (kopiert)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Keine passenden Zugangsdaten" }, + "noCards": { + "message": "Keine Karten" + }, + "noIdentities": { + "message": "Keine Identitäten" + }, + "addLoginMenu": { + "message": "Zugangsdaten hinzufügen" + }, + "addCardMenu": { + "message": "Karte hinzufügen" + }, + "addIdentityMenu": { + "message": "Identität hinzufügen" + }, "unlockVaultMenu": { "message": "Entsperre deinen Tresor" }, diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index c0b349f8aff..2692a89b7db 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Αυτόματη συμπλήρωση" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Δημιουργία Κωδικού (αντιγράφηκε)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Δεν υπάρχουν αντιστοιχίσεις σύνδεσης." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Ξεκλειδώστε το vault σας" }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index fbe9e4fc31e..4e1057956fa 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 0ae234fbece..32dd196f2ae 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 15f8b4fbefa..b81a05c9a4b 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Autorellenar" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generar contraseña (copiada)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Sin entradas coincidentes." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Desbloquea la caja fuerte" }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index b799c3a63a3..4fe20767c0e 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automaatne täitmine" }, + "autoFillLogin": { + "message": "Täida konto andmed" + }, + "autoFillCard": { + "message": "Täida kaardi andmed" + }, + "autoFillIdentity": { + "message": "Täida identiteet" + }, "generatePasswordCopied": { "message": "Genereeri parool (kopeeritakse)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Sobivaid kontoandmeid ei leitud." }, + "noCards": { + "message": "Kaardid puuduvad" + }, + "noIdentities": { + "message": "Identiteedid puuduvad" + }, + "addLoginMenu": { + "message": "Lisa konto andmed" + }, + "addCardMenu": { + "message": "Lisa kaart" + }, + "addIdentityMenu": { + "message": "Lisa identiteet" + }, "unlockVaultMenu": { "message": "Lukusta hoidla lahti" }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 6290304cda6..291a687f8b4 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-betetzea" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Sortu pasahitza (kopiatuta)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Bat datozen saio-hasierarik gabe" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Desblokeatu kutxa gotorra" }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 250ca3631a5..bcfab0cdbc8 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "پر کردن خودکار" }, + "autoFillLogin": { + "message": "پر کردن خودکار ورود" + }, + "autoFillCard": { + "message": "پر کردن خودکار کارت" + }, + "autoFillIdentity": { + "message": "پر کردن خودکار هویت" + }, "generatePasswordCopied": { "message": "ساخت کلمه عبور (کپی شد)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "ورودی‌ها منتطبق نیست" }, + "noCards": { + "message": "کارتی وجود ندارد" + }, + "noIdentities": { + "message": "هویتی وجود ندارد" + }, + "addLoginMenu": { + "message": "افزودن ورود" + }, + "addCardMenu": { + "message": "افزودن کارت" + }, + "addIdentityMenu": { + "message": "افزودن هویت" + }, "unlockVaultMenu": { "message": "قفل گاوصندوق خود را باز کنید" }, @@ -637,7 +661,7 @@ "message": "برای پر کردن خودکار گاوصندوق Bitwarden خود را باز کنید." }, "notificationUnlock": { - "message": "بازگشایی" + "message": "باز کردن قفل" }, "enableContextMenuItem": { "message": "نمایش گزینه‌های منوی زمینه" @@ -772,7 +796,7 @@ "message": "ویژگی موجود نیست" }, "encryptionKeyMigrationRequired": { - "message": "Encryption key migration required. Please login through the web vault to update your encryption key." + "message": "انتقال کلید رمزگذاری مورد نیاز است. لطفاً از طریق گاوصندوق وب وارد شوید تا کلید رمزگذاری خود را به روز کنید." }, "premiumMembership": { "message": "عضویت پرمیوم" @@ -1606,10 +1630,10 @@ "message": "بیومتریک مرورگر در این دستگاه پشتیبانی نمی‌شود." }, "biometricsFailedTitle": { - "message": "زیست‌سنجی ناتمام ماند" + "message": "زیست‌سنجی ناموفق بود" }, "biometricsFailedDesc": { - "message": "زیست‌سنجی نمی تواند انجام شود، استفاده از کلمه عبور اصلی یا خروج را در نظر بگیرید. اگر این مشکل ادامه یافت لطفا با پشتیبانی Bitwarden تماس بگیرید." + "message": "زیست‌سنجی نمی‌تواند انجام شود، استفاده از کلمه عبور اصلی یا خروج را در نظر بگیرید. اگر این مشکل ادامه یافت لطفاً با پشتیبانی Bitwarden تماس بگیرید." }, "nativeMessaginPermissionErrorTitle": { "message": "مجوز ارائه نشده است" @@ -1992,7 +2016,7 @@ "message": "برون ریزی گاو‌صندوق شخصی" }, "exportingIndividualVaultDescription": { - "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.", + "message": "فقط موارد شخصی گاوصندوق مرتبط با $EMAIL$ برون ریزی خواهند شد. موارد گاوصندوق سازمان شامل نخواهد شد. فقط اطلاعات مورد گاوصندوق برون ریزی خواهد شد و شامل تاریخچه کلمه عبور مرتبط یا پیوست نمی‌شود.", "placeholders": { "email": { "content": "$1", @@ -2234,28 +2258,28 @@ } }, "loggingInOn": { - "message": "ورود به عنوان" + "message": "ورود با" }, "opensInANewWindow": { "message": "در پنجره جدید باز می‌شود" }, "deviceApprovalRequired": { - "message": "تایید دستگاه لازم است. یک روش تایید برگزینید:" + "message": "تأیید دستگاه لازم است. یک روش تأیید انتخاب کنید:" }, "rememberThisDevice": { "message": "این دستگاه را به خاطر بسپار" }, "uncheckIfPublicDevice": { - "message": "بردارید اگر از دستگاه عمومی استفاده میکنید" + "message": "اگر از دستگاه عمومی استفاده می‌کنید علامت را بردارید" }, "approveFromYourOtherDevice": { - "message": "تایید با دستگاه دیگرتان" + "message": "تأیید با دستگاه دیگرتان" }, "requestAdminApproval": { - "message": "درخواست تایید مدیر" + "message": "درخواست تأیید مدیر" }, "approveWithMasterPassword": { - "message": "تایید با کلمه عبور اصلی" + "message": "تأیید با کلمه عبور اصلی" }, "ssoIdentifierRequired": { "message": "شناسه سازمان SSO مورد نیاز است." @@ -2283,37 +2307,37 @@ "message": "حساب کاربری با موفقیت ایجاد شد!" }, "adminApprovalRequested": { - "message": "تایید مدیر در خواست شد" + "message": "تأیید مدیر درخواست شد" }, "adminApprovalRequestSentToAdmins": { "message": "درخواست شما به مدیرتان فرستاده شد." }, "youWillBeNotifiedOnceApproved": { - "message": "به محض تایید مطلع خواهید شد." + "message": "به محض تأیید مطلع خواهید شد." }, "troubleLoggingIn": { "message": "در ورود مشکلی دارید؟" }, "loginApproved": { - "message": "ورود تایید شد" + "message": "ورود تأیید شد" }, "userEmailMissing": { - "message": "رایانامه کاربر کم است" + "message": "ایمیل کاربر وجود ندارد" }, "deviceTrusted": { "message": "دستگاه مورد اعتماد است" }, "inputRequired": { - "message": "ورودی مورد نیاز است." + "message": "ورودی ضروری است." }, "required": { - "message": "الزامی" + "message": "ضروری" }, "search": { "message": "جستجو" }, "inputMinLength": { - "message": "ورودی باید حداقل $COUNT$ نشانه داشته باشد.", + "message": "ورودی باید حداقل $COUNT$ کاراکتر داشته باشد.", "placeholders": { "count": { "content": "$1", @@ -2322,7 +2346,7 @@ } }, "inputMaxLength": { - "message": "اندازه ورودی نباید بیش از $COUNT$ نشانه باشد.", + "message": "طول ورودی نباید بیش از $COUNT$ کاراکتر باشد.", "placeholders": { "count": { "content": "$1", @@ -2331,7 +2355,7 @@ } }, "inputForbiddenCharacters": { - "message": "نشانه های زیر مجاز نیستند: $CHARACTERS$", + "message": "کاراکترهای زیر مجاز نیستند: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -2340,7 +2364,7 @@ } }, "inputMinValue": { - "message": "مقدار ورودی باید دست کم $MIN$ باشد.", + "message": "مقدار ورودی باید حداقل $MIN$ باشد.", "placeholders": { "min": { "content": "$1", @@ -2349,7 +2373,7 @@ } }, "inputMaxValue": { - "message": "مقدار ورودی نباید بیش از $MAX$ باشد.", + "message": "مقدار ورودی نباید از $MAX$ تجاوز کند.", "placeholders": { "max": { "content": "$1", @@ -2358,17 +2382,17 @@ } }, "multipleInputEmails": { - "message": "یک یا چند رایانامه نامعتبر است" + "message": "یک یا چند ایمیل نامعتبر است" }, "inputTrimValidator": { - "message": "ورودی نباید فقط فاصله باشد.", + "message": "ورودی نباید فقط حاوی فضای خالی باشد.", "description": "Notification to inform the user that a form's input can't contain only whitespace." }, "inputEmail": { - "message": "ورودی یک نشانی رایانامه نیست." + "message": "ورودی یک نشانی ایمیل نیست." }, "fieldsNeedAttention": { - "message": "بخش (های) $COUNT$ در بالا نیازمند توجه شما است.", + "message": "فیلد $COUNT$ در بالا به توجه شما نیاز دارد.", "placeholders": { "count": { "content": "$1", @@ -2380,16 +2404,16 @@ "message": "-- انتخاب --" }, "multiSelectPlaceholder": { - "message": "-- برای گزینش چیزی بنویسید --" + "message": "-- برای فیلتر تایپ کنید --" }, "multiSelectLoading": { "message": "در حال بازیابی گزینه‌ها..." }, "multiSelectNotFound": { - "message": "موردی پیدا نشد" + "message": "موردی یافت نشد" }, "multiSelectClearAll": { - "message": "پاک کردن همه" + "message": "پاک‌کردن همه" }, "plusNMore": { "message": "+ $QUANTITY$ بیشتر", @@ -2401,25 +2425,25 @@ } }, "submenu": { - "message": "زیرفهرست" + "message": "زیرمنو" }, "toggleCollapse": { - "message": "باز و بسته کردن", + "message": "دکمه بستن", "description": "Toggling an expand/collapse state." }, "aliasDomain": { - "message": "Alias domain" + "message": "دامنه مستعار" }, "passwordRepromptDisabledAutofillOnPageLoad": { - "message": "Items with master password re-prompt cannot be auto-filled on page load. Auto-fill on page load turned off.", + "message": "موارد با درخواست مجدد کلمه عبور اصلی را نمی‌توان در بارگذاری صفحه به‌صورت خودکار پر کرد. پر کردن خودکار در بارگیری صفحه خاموش شد.", "description": "Toast message for describing that master password re-prompt cannot be auto-filled on page load." }, "autofillOnPageLoadSetToDefault": { - "message": "Auto-fill on page load set to use default setting.", + "message": "پر کردن خودکار در بارگیری صفحه برای استفاده از تنظیمات پیش‌فرض تنظیم شده است.", "description": "Toast message for informing the user that auto-fill on page load has been set to the default setting." }, "turnOffMasterPasswordPromptToEditField": { - "message": "Turn off master password re-prompt to edit this field", + "message": "برای ویرایش این فیلد، درخواست مجدد کلمه عبور اصلی را خاموش کنید", "description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item." } } diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 3a829d4783d..daaa9a89258 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automaattinen täyttö" }, + "autoFillLogin": { + "message": "Täytä kirjautumistieto automaattisesti" + }, + "autoFillCard": { + "message": "Täytä kortti automaattisesti" + }, + "autoFillIdentity": { + "message": "Täytä identiteetti automaattisesti" + }, "generatePasswordCopied": { "message": "Luo salasana (leikepöydälle)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Ei tunnistettuja kirjautumistietoja." }, + "noCards": { + "message": "Kortteja ei ole" + }, + "noIdentities": { + "message": "Identiteettejä ei ole" + }, + "addLoginMenu": { + "message": "Lisää kirjautumistieto" + }, + "addCardMenu": { + "message": "Lisää kortti" + }, + "addIdentityMenu": { + "message": "Lisää identiteetti" + }, "unlockVaultMenu": { "message": "Avaa holvisi" }, diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index a8673d001ae..464cf888899 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill sa Filipino ay Awtomatikong Pagpuno" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Maglagay ng Password" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Walang tumutugmang mga login" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Buksan ang iyong kahadeyero" }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index ba4d6a6dd86..b0827b39006 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Saisie automatique" }, + "autoFillLogin": { + "message": "Saisie automatique de l'identifiant" + }, + "autoFillCard": { + "message": "Saisie automatique de la carte" + }, + "autoFillIdentity": { + "message": "Saisie automatique de l'identité" + }, "generatePasswordCopied": { "message": "Générer un mot de passe (copié)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Aucun identifiant correspondant." }, + "noCards": { + "message": "Aucune carte" + }, + "noIdentities": { + "message": "Aucune identité" + }, + "addLoginMenu": { + "message": "Ajouter un identifiant" + }, + "addCardMenu": { + "message": "Ajouter une carte" + }, + "addIdentityMenu": { + "message": "Ajouter une identité" + }, "unlockVaultMenu": { "message": "Déverrouillez votre coffre" }, @@ -634,7 +658,7 @@ "message": "Mettre à jour" }, "notificationUnlockDesc": { - "message": "Unlock your Bitwarden vault to complete the auto-fill request." + "message": "Déverrouillez votre coffre Bitwarden pour terminer la demande de saisie automatique." }, "notificationUnlock": { "message": "Déverrouiller" diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 68f1ebc1218..19985cd5ec8 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "השלמה אוטומטית" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "צור סיסמה (העתק)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "לא נמצאו פרטי כניסה תואמים." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "שחרור הכספת שלך" }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 2b99c964209..4b686192902 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "स्वत:भरण" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate Password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "कोई मेल-मिला लॉगिन नहीं |" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "आपकी तिजोरी का ताला खोलें" }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index b88c097804f..b334d22332f 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-ispuna" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generiraj lozinku (i kopiraj)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Nema podudarajućih prijava" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Otključaj svoj trezor" }, diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index efe6d260355..abf5a12e5e5 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automatikus kitöltés" }, + "autoFillLogin": { + "message": "Automatikus kitöltés bejelentkezés" + }, + "autoFillCard": { + "message": "Automatikus kitöltés kártya" + }, + "autoFillIdentity": { + "message": "Automatikus kitöltés személyazonosság" + }, "generatePasswordCopied": { "message": "Jelszó generálás (másolt)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Nincsenek egyező bejelentkezések." }, + "noCards": { + "message": "Nincsenek kártyák" + }, + "noIdentities": { + "message": "Nincsenek személyazonosságok" + }, + "addLoginMenu": { + "message": "Bejelentkezés hozzáadása" + }, + "addCardMenu": { + "message": "Kártya hozzáadása" + }, + "addIdentityMenu": { + "message": "Személyazonossság hozzáadása" + }, "unlockVaultMenu": { "message": "Széf kinyitása" }, @@ -143,7 +167,7 @@ "message": "A folytatáshoz meg kell erősíteni a személyazonosságot." }, "account": { - "message": "Felhasználó" + "message": "Fiók" }, "changeMasterPassword": { "message": "Mesterjelszó módosítása" @@ -513,7 +537,7 @@ "message": "A kétlépcsős bejelentkezés biztonságosabbá teszi a fiókot azáltal, hogy ellenőrizni kell a bejelentkezést egy másik olyan eszközzel mint például biztonsági kulcs, hitelesítő alkalmazás, SMS, telefon hívás vagy email. A kétlépcsős bejelentkezést a bitwarden.com webes széfben lehet engedélyezni. Felkeressük a webhelyet most?" }, "editedFolder": { - "message": "A mappa módosításra került." + "message": "A mappa mentésre került." }, "deleteFolderConfirmation": { "message": "Biztos, hogy törölni akarod ezt a mappát?" @@ -562,7 +586,7 @@ "message": "Biztosan törlésre kerüljön ezt az elem?" }, "deletedItem": { - "message": "Az elem törlésre került." + "message": "Az elem a lomtárba került." }, "overwritePassword": { "message": "Jelszó felülírása" @@ -769,7 +793,7 @@ "message": "A naximális fájlméret 500 MB." }, "featureUnavailable": { - "message": "Ez a funkció nem érhető el." + "message": "A funkció nem érhető el." }, "encryptionKeyMigrationRequired": { "message": "Titkosítási kulcs migráció szükséges. Jelentkezzünk be a webes széfen keresztül a titkosítási kulcs frissítéséhez." @@ -787,7 +811,7 @@ "message": "Tagság frissítése" }, "premiumNotCurrentMember": { - "message": "Jelenleg nincs prémium tagság." + "message": "Jelenleg nem vagyunk prémium tag." }, "premiumSignUpAndGet": { "message": "Regisztráció a prémium tagságra az alábbi funkciókért:" @@ -796,7 +820,7 @@ "message": "1 GB titkosított tárhely a fájlmellékleteknek." }, "premiumSignUpTwoStepOptions": { - "message": "Proprietary two-step login options such as YubiKey and Duo." + "message": "Saját kétlépcsős bejelentkezési lehetőségek mint a YubiKey és a Duo." }, "ppremiumSignUpReports": { "message": "Jelszó higiénia, fiók biztonság és adatszivárgási jelentések a széf biztonsága érdekében." @@ -817,7 +841,7 @@ "message": "A prémium tagság megvásárolható a bitwarden.com webes széfben. Szeretnénk felkeresni a webhelyet most?" }, "premiumCurrentMember": { - "message": "Jelenleg a prémium tagság érvényben van." + "message": "Prémium tag vagyunk!" }, "premiumCurrentMemberThanks": { "message": "Köszönjük a Bitwarden támogatását." @@ -994,7 +1018,7 @@ "message": "Alapértelmezett beállítások bejelentkezési elemekhez" }, "defaultAutoFillOnPageLoadDesc": { - "message": "Az Automatikus kitöltés engedélyezése az oldalbetöltéskor engedélyezheti vagy letilthatja a funkciót az egyes bejelentkezési elemeknél. Ez az alapértelmezett beállítás a bejelentkezési elemeknéll, amelyek nincsenek külön konfigurálva." + "message": "Az egyes bejelentkezési elemeknél kikapcsolhatjuk oldalbetöltéskor az automatikus kitöltést az elem Szerkesztés nézetében." }, "itemAutoFillOnPageLoad": { "message": "Automatikus kitöltés oldal betöltésnél (Ha engedélyezett az opcióknál)" @@ -1905,7 +1929,7 @@ "message": "Perc" }, "vaultTimeoutPolicyInEffect": { - "message": "A szervezeti házirendek hatással vannak a széf időkorlátjára. A széf időkorlátja legfeljebb $HOURS$ óra és $MINUTES$ perc lehet.", + "message": "A szervezeti szabályzata $HOURS$ órára és $MINUTES$ percre állította be a maximálisan megengedett széf időtúllépést.", "placeholders": { "hours": { "content": "$1", diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index f3fdd1a7c27..7b19a6838c0 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Isi otomatis" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Membuat Kata Sandi (tersalin)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Tidak ada info masuk yang cocok." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Buka brankas Anda" }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 691e2484cba..9bca2da6062 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Riempimento automatico" }, + "autoFillLogin": { + "message": "Riempi automaticamente login" + }, + "autoFillCard": { + "message": "Riempi automaticamente carta" + }, + "autoFillIdentity": { + "message": "Riempi automaticamente identità" + }, "generatePasswordCopied": { "message": "Genera password e copiala" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Nessun login corrispondente" }, + "noCards": { + "message": "Nessuna carta" + }, + "noIdentities": { + "message": "Nessuna identità" + }, + "addLoginMenu": { + "message": "Aggiungi login" + }, + "addCardMenu": { + "message": "Aggiungi carta" + }, + "addIdentityMenu": { + "message": "Aggiungi identità" + }, "unlockVaultMenu": { "message": "Sblocca la tua cassaforte" }, diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index c3762ae4ef8..d2528a45489 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "自動入力" }, + "autoFillLogin": { + "message": "自動入力ログイン" + }, + "autoFillCard": { + "message": "自動入力カード" + }, + "autoFillIdentity": { + "message": "自動入力 ID" + }, "generatePasswordCopied": { "message": "パスワードを生成 (コピー)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "一致するログインがありません。" }, + "noCards": { + "message": "カードなし" + }, + "noIdentities": { + "message": "ID なし" + }, + "addLoginMenu": { + "message": "ログイン情報を追加" + }, + "addCardMenu": { + "message": "カードを追加" + }, + "addIdentityMenu": { + "message": "ID を追加" + }, "unlockVaultMenu": { "message": "保管庫のロックを解除" }, diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 50a25ad0dd9..2d2b5cb8a5e 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "თვითშევსება" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index 06f9461e5fd..95c9350aff8 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "ಸ್ವಯಂ ಭರ್ತಿ" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "ಪಾಸ್ವರ್ಡ್ ರಚಿಸಿ (ನಕಲಿಸಲಾಗಿದೆ)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "ಹೊಂದಾಣಿಕೆಯ ಲಾಗಿನ್‌ಗಳು ಇಲ್ಲ." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 5921e579e24..e7aba95f493 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "자동 완성" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "비밀번호 생성 및 클립보드에 복사" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "사용할 수 있는 로그인이 없습니다." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "보관함 잠금 해제" }, diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 425d0c98233..885b3cbec8f 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automatinis užpildymas" }, + "autoFillLogin": { + "message": "Automatinio užpildymo prisijungimas" + }, + "autoFillCard": { + "message": "Automatinio užpildymo kortelė" + }, + "autoFillIdentity": { + "message": "Automatinio užpildymo tapatybė" + }, "generatePasswordCopied": { "message": "Kurti slaptažodį (paruoštas įterpti)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Nėra atitinkančių prisijungimų." }, + "noCards": { + "message": "Nėra kortelių" + }, + "noIdentities": { + "message": "Nėra tapatybių" + }, + "addLoginMenu": { + "message": "Pridėti prisijungimą" + }, + "addCardMenu": { + "message": "Pridėti kortelę" + }, + "addIdentityMenu": { + "message": "Pridėti tapatybę" + }, "unlockVaultMenu": { "message": "Atrakinti saugyklą" }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 624904d7213..2abb0ac4de6 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automātiskā aizpildīšana" }, + "autoFillLogin": { + "message": "Automātiski aizpildīt pieteikšanos" + }, + "autoFillCard": { + "message": "Automātiski aizpildīt karti" + }, + "autoFillIdentity": { + "message": "Automātiski aizpildīt identitāti" + }, "generatePasswordCopied": { "message": "Izveidot paroli (tiks ievietota starpliktuvē)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Nav atbilstošu pieteikšanās vienumu" }, + "noCards": { + "message": "Nav karšu" + }, + "noIdentities": { + "message": "Nav identitāšu" + }, + "addLoginMenu": { + "message": "Pievienot pieteikšanās vienumu" + }, + "addCardMenu": { + "message": "Pievienot karti" + }, + "addIdentityMenu": { + "message": "Pievienot identitāti" + }, "unlockVaultMenu": { "message": "Atslēgt glabātavu" }, diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 58d5b04fc8b..258ad3fd966 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "ഓട്ടോഫിൽ" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "പാസ്‌വേഡ് സൃഷ്ടിക്കുക (പകർത്തുക )" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "പൊരുത്തപ്പെടുന്ന ലോഗിനുകളൊന്നുമില്ല." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index 8f8f58775f7..131c062d544 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "स्वयंभरण" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "तिजोरी उघडा" }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 4dadbbc8a7b..43a19478bb0 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-utfylling" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generer et passord (kopiert)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Ingen samsvarende innlogginger." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Lås opp hvelvet ditt" }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 5915dad872a..630510f6723 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-invullen" }, + "autoFillLogin": { + "message": "Login automatisch invullen" + }, + "autoFillCard": { + "message": "Kaart automatisch invullen" + }, + "autoFillIdentity": { + "message": "Identiteit automatisch invullen" + }, "generatePasswordCopied": { "message": "Wachtwoord genereren (op klembord)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Geen overeenkomstige logins." }, + "noCards": { + "message": "Geen kaarten" + }, + "noIdentities": { + "message": "Geen identiteiten" + }, + "addLoginMenu": { + "message": "Login toevoegen" + }, + "addCardMenu": { + "message": "Kaart toevoegen" + }, + "addIdentityMenu": { + "message": "Identiteit toevoegen" + }, "unlockVaultMenu": { "message": "Ontgrendel je kluis" }, @@ -772,7 +796,7 @@ "message": "Functionaliteit niet beschikbaar" }, "encryptionKeyMigrationRequired": { - "message": "Encryption key migration required. Please login through the web vault to update your encryption key." + "message": "Migratie van de encryptiesleutel vereist. Login via de website om je sleutel te bij te werken." }, "premiumMembership": { "message": "Premium-abonnement" diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 2f28c87d801..5b16c13ef14 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Autouzupełnianie" }, + "autoFillLogin": { + "message": "Autouzupełnianie logowania" + }, + "autoFillCard": { + "message": "Autouzupełnianie karty" + }, + "autoFillIdentity": { + "message": "Autouzupełnianie tożsamości" + }, "generatePasswordCopied": { "message": "Wygeneruj hasło (do schowka)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Brak pasujących danych logowania" }, + "noCards": { + "message": "Brak kart" + }, + "noIdentities": { + "message": "Brak tożsamości" + }, + "addLoginMenu": { + "message": "Dodaj dane logowania" + }, + "addCardMenu": { + "message": "Dodaj kartę" + }, + "addIdentityMenu": { + "message": "Dodaj tożsamość" + }, "unlockVaultMenu": { "message": "Odblokuj sejf" }, diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index ed62f893a19..7578ae170ca 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Autopreencher" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Gerar Senha (copiada)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Sem credenciais correspondentes." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Desbloqueie seu cofre" }, diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 735edf60afe..1495b64e453 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Preenchimento automático" }, + "autoFillLogin": { + "message": "Preenchimento automático da credencial" + }, + "autoFillCard": { + "message": "Preenchimento automático do cartão" + }, + "autoFillIdentity": { + "message": "Preenchimento automático da identidade" + }, "generatePasswordCopied": { "message": "Gerar palavra-passe (copiada)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Sem credenciais correspondentes" }, + "noCards": { + "message": "Sem cartões" + }, + "noIdentities": { + "message": "Sem identidades" + }, + "addLoginMenu": { + "message": "Adicionar credencial" + }, + "addCardMenu": { + "message": "Adicionar cartão" + }, + "addIdentityMenu": { + "message": "Adicionar identidade" + }, "unlockVaultMenu": { "message": "Desbloquear o cofre" }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index f525f87b6c2..085951a93f1 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-completare" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generare parolă (s-a copiat)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Nu există potrivire de autentificări" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Deblocați-vă seiful" }, diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 40452e56dce..40ecd382bd5 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Автозаполнение" }, + "autoFillLogin": { + "message": "Автозаполнение логина" + }, + "autoFillCard": { + "message": "Автозаполнение карты" + }, + "autoFillIdentity": { + "message": "Автозаполнение личности" + }, "generatePasswordCopied": { "message": "Сгенерировать пароль (с копированием)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Нет подходящих логинов." }, + "noCards": { + "message": "Нет карт" + }, + "noIdentities": { + "message": "Нет личностей" + }, + "addLoginMenu": { + "message": "Добавить логин" + }, + "addCardMenu": { + "message": "Добавить карту" + }, + "addIdentityMenu": { + "message": "Добавить личность" + }, "unlockVaultMenu": { "message": "Разблокировать хранилище" }, diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index 04f2a619a82..8ea364cb6d1 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "ස්වයං-පිරවීම" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "මුරපදය ජනනය (පිටපත්)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "ගැලපෙන පිවිසුම් නොමැත." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 684c677c45b..d04f2ccf05a 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Automatické vypĺňanie" }, + "autoFillLogin": { + "message": "Automatické vyplnenie prihlasovacích údajov" + }, + "autoFillCard": { + "message": "Automatické vyplnenie karty" + }, + "autoFillIdentity": { + "message": "Automatické vyplnenie identity" + }, "generatePasswordCopied": { "message": "Vygenerovať heslo (skopírované)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Žiadne zodpovedajúce prihlasovacie údaje." }, + "noCards": { + "message": "Žiadne karty" + }, + "noIdentities": { + "message": "Žiadne identity" + }, + "addLoginMenu": { + "message": "Pridať prihlasovacie údaje" + }, + "addCardMenu": { + "message": "Pridať kartu" + }, + "addIdentityMenu": { + "message": "Pridať identitu" + }, "unlockVaultMenu": { "message": "Odomknúť trezor" }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 8878c308045..5f859e9e5f3 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Samodejno izpolnjevanje" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generiraj geslo (kopirano)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Ni ustreznih prijav." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Odkleni svoj trezor" }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 46e96c7d8df..d55a5bfe197 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Аутоматско допуњавање" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Генериши Лозинку (копирано)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Нема одговарајућих пријављивања." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Откључај свој сеф" }, @@ -2408,7 +2432,7 @@ "description": "Toggling an expand/collapse state." }, "aliasDomain": { - "message": "Alias domain" + "message": "Домен алијаса" }, "passwordRepromptDisabledAutofillOnPageLoad": { "message": "Ставке са упитом за поновно постављање главне лозинке не могу се ауто-попунити при учитавању странице. Ауто-попуњавање при учитавању странице је искључено.", diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 680a3aac0bd..ca0b8de6580 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Fyll i automatiskt" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Skapa lösenord (kopierad)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Inga matchande inloggningar" }, + "noCards": { + "message": "Inga kort" + }, + "noIdentities": { + "message": "Inga identiteter" + }, + "addLoginMenu": { + "message": "Lägg till inloggning" + }, + "addCardMenu": { + "message": "Lägg till kort" + }, + "addIdentityMenu": { + "message": "Lägg till identitet" + }, "unlockVaultMenu": { "message": "Lås upp ditt valv" }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index f8ffeff747e..22330901579 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Auto-fill" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "No matching logins" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Unlock your vault" }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 0db240ea797..20702a1de4a 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "กรอกข้อมูลอัตโนมัติ" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Generate Password (copied)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "ไม่พบข้อมูลล็อกอินที่ตรงกัน" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "ปลดล็อกกตู้นิรภัยของคุณ" }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index e52a2f59f26..e9763386aa6 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Otomatik doldur" }, + "autoFillLogin": { + "message": "Hesabı otomatik doldur" + }, + "autoFillCard": { + "message": "Kartı otomatik doldur" + }, + "autoFillIdentity": { + "message": "Kimliği otomatik doldur" + }, "generatePasswordCopied": { "message": "Parola oluştur (ve kopyala)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Eşleşen hesap yok" }, + "noCards": { + "message": "Kart yok" + }, + "noIdentities": { + "message": "Kimlik yok" + }, + "addLoginMenu": { + "message": "Hesap ekle" + }, + "addCardMenu": { + "message": "Kart ekle" + }, + "addIdentityMenu": { + "message": "Kimlik ekle" + }, "unlockVaultMenu": { "message": "Kasanızın kilidini açın" }, @@ -1609,7 +1633,7 @@ "message": "Biyometri doğrulanamadı" }, "biometricsFailedDesc": { - "message": "Biometrics cannot be completed, consider using a master password or logging out. If this persists, please contact Bitwarden support." + "message": "Biyometri doğrulaması tamamlanamadı. Ana parolanızı kullanabilir veya çıkış yapabilirsiniz. Sorun devam ederse Bitwarden destek ekibiyle iletişime geçin." }, "nativeMessaginPermissionErrorTitle": { "message": "İzin verilmedi" diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 6cb70bd76bd..666870146d4 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Автозаповнення" }, + "autoFillLogin": { + "message": "Автозаповнення входу" + }, + "autoFillCard": { + "message": "Автозаповнення картки" + }, + "autoFillIdentity": { + "message": "Автозаповнення особистих даних" + }, "generatePasswordCopied": { "message": "Генерувати пароль (з копіюванням)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Немає відповідних записів" }, + "noCards": { + "message": "Немає карток" + }, + "noIdentities": { + "message": "Немає особистих даних" + }, + "addLoginMenu": { + "message": "Додати запис входу" + }, + "addCardMenu": { + "message": "Додати картку" + }, + "addIdentityMenu": { + "message": "Додати особисті дані" + }, "unlockVaultMenu": { "message": "Розблокуйте сховище" }, @@ -2408,18 +2432,18 @@ "description": "Toggling an expand/collapse state." }, "aliasDomain": { - "message": "Alias domain" + "message": "Псевдонім домену" }, "passwordRepromptDisabledAutofillOnPageLoad": { - "message": "Items with master password re-prompt cannot be auto-filled on page load. Auto-fill on page load turned off.", + "message": "Записи з повторним запитом головного пароля не можна автоматично заповнювати під час завантаження сторінки. Автозаповнення на сторінці вимкнено.", "description": "Toast message for describing that master password re-prompt cannot be auto-filled on page load." }, "autofillOnPageLoadSetToDefault": { - "message": "Auto-fill on page load set to use default setting.", + "message": "Автозаповнення на сторінці налаштовано з типовими параметрами.", "description": "Toast message for informing the user that auto-fill on page load has been set to the default setting." }, "turnOffMasterPasswordPromptToEditField": { - "message": "Turn off master password re-prompt to edit this field", + "message": "Вимкніть повторний запит головного пароля, щоб редагувати це поле", "description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item." } } diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index e562a0b5d5d..caedbb8b917 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "Tự động điền" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "Tạo mật khẩu (đã sao chép)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "Không có thông tin đăng nhập phù hợp." }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "Mở khoá kho lưu trữ của bạn" }, diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index b1d0aac7e4a..5331208af82 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "自动填充" }, + "autoFillLogin": { + "message": "自动填充登录" + }, + "autoFillCard": { + "message": "自动填充支付卡" + }, + "autoFillIdentity": { + "message": "自动填充身份" + }, "generatePasswordCopied": { "message": "生成密码(并复制)" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "无匹配的登录项目" }, + "noCards": { + "message": "无支付卡" + }, + "noIdentities": { + "message": "无身份" + }, + "addLoginMenu": { + "message": "添加登录项目" + }, + "addCardMenu": { + "message": "添加支付卡" + }, + "addIdentityMenu": { + "message": "添加身份" + }, "unlockVaultMenu": { "message": "解锁您的密码库" }, @@ -850,7 +874,7 @@ "message": "使用此功能需要高级会员资格。" }, "enterVerificationCodeApp": { - "message": "请输入您的验证器应用中的 6 位验证码。" + "message": "请输入您的验证器应用中的 6 位数验证码。" }, "enterVerificationCodeEmail": { "message": "请输入发送给电子邮件 $EMAIL$ 的 6 位数验证码。", @@ -2117,7 +2141,7 @@ } }, "loginWithMasterPassword": { - "message": "主密码登录" + "message": "使用主密码登录" }, "loggingInAs": { "message": "正登录为" @@ -2132,7 +2156,7 @@ "message": "记住电子邮件地址" }, "loginWithDevice": { - "message": "设备登录" + "message": "使用设备登录" }, "loginWithDeviceEnabledInfo": { "message": "设备登录必须在 Bitwarden 应用程序的设置中启用。需要其他登录选项吗?" diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 58ca526bc68..b3368beb188 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -91,6 +91,15 @@ "autoFill": { "message": "自動填入" }, + "autoFillLogin": { + "message": "Auto-fill login" + }, + "autoFillCard": { + "message": "Auto-fill card" + }, + "autoFillIdentity": { + "message": "Auto-fill identity" + }, "generatePasswordCopied": { "message": "產生及複製密碼" }, @@ -100,6 +109,21 @@ "noMatchingLogins": { "message": "無符合的登入資料" }, + "noCards": { + "message": "No cards" + }, + "noIdentities": { + "message": "No identities" + }, + "addLoginMenu": { + "message": "Add login" + }, + "addCardMenu": { + "message": "Add card" + }, + "addIdentityMenu": { + "message": "Add identity" + }, "unlockVaultMenu": { "message": "解鎖您的密碼庫" }, diff --git a/apps/browser/store/locales/az/copy.resx b/apps/browser/store/locales/az/copy.resx index 677ad41b6bc..cb05f8e5d9e 100644 --- a/apps/browser/store/locales/az/copy.resx +++ b/apps/browser/store/locales/az/copy.resx @@ -139,7 +139,7 @@ Bitwarden, parolları iş yoldaşlarınızla təhlükəsiz paylaşa bilməyiniz Nəyə görə Bitwarden-i seçməliyik: Yüksək səviyyə şifrələmə -Parollarınız qabaqcıl bir ucdan digərinə kimi şifrələmə (AES-256 bit, salted hashtag və PBKDF2 SHA-256) ilə qorunur, beləcə verilənlərinizin güvənli və gizli qalmasını təmin edir. +Parollarınız qabaqcıl ucdan-uca şifrələmə (AES-256 bit, salted hashtag və PBKDF2 SHA-256) ilə qorunur, beləcə datanızın güvənli və gizli qalmasını təmin edir. Daxili parol yaradıcı Çox istifadə etdiyiniz hər veb sayt üçün təhlükəsizlik tələblərinə görə güclü, unikal və təsadüfi şifrələr yaradın. From ceea6ef9853dfe8368167acb32b217653fff373d Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Fri, 6 Oct 2023 09:32:29 -0400 Subject: [PATCH 06/33] Update text for SM billing section checkbox (#6463) --- apps/web/src/app/billing/shared/sm-subscribe.component.html | 2 +- apps/web/src/locales/en/messages.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/billing/shared/sm-subscribe.component.html b/apps/web/src/app/billing/shared/sm-subscribe.component.html index c50d77be043..62a80c2a999 100644 --- a/apps/web/src/app/billing/shared/sm-subscribe.component.html +++ b/apps/web/src/app/billing/shared/sm-subscribe.component.html @@ -40,7 +40,7 @@

{{ "secretsManagerForPlan" | i18n : planName }}

- {{ "addSecretsManager" | i18n }} + {{ "subscribeToSecretsManager" | i18n }} {{ "addSecretsManagerUpgradeDesc" | i18n }} diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 34d0741ceba..651325bad6f 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -7096,8 +7096,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." From b05b3a29353c3814048815608dc2410480007b37 Mon Sep 17 00:00:00 2001 From: Will Martin Date: Fri, 6 Oct 2023 12:12:54 -0400 Subject: [PATCH 07/33] [PM-4230] bump Electron to v26.3.0 (#6511) --- apps/desktop/electron-builder.json | 2 +- package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 6f760ef2b1e..0830fabf13d 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -19,7 +19,7 @@ "**/node_modules/@bitwarden/desktop-native/index.js", "**/node_modules/@bitwarden/desktop-native/desktop_native.${platform}-${arch}*.node" ], - "electronVersion": "24.8.5", + "electronVersion": "26.3.0", "generateUpdatesFilesForAllChannels": true, "publish": { "provider": "generic", diff --git a/package-lock.json b/package-lock.json index c67336a74b8..2725952486d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -123,7 +123,7 @@ "cross-env": "7.0.3", "css-loader": "6.8.1", "del": "6.1.1", - "electron": "24.8.5", + "electron": "26.3.0", "electron-builder": "^23.6.0", "electron-log": "4.4.8", "electron-reload": "2.0.0-alpha.1", @@ -20179,9 +20179,9 @@ } }, "node_modules/electron": { - "version": "24.8.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-24.8.5.tgz", - "integrity": "sha512-CWSF0CrD1XhxyoXUcCcEoJB8orMTHuOrkj2s87XU11vjgVJHhzhCBh9TVqhMQt7U6TtcGYa5kDIiLRekxJRaRA==", + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-26.3.0.tgz", + "integrity": "sha512-7ZpvSHu+jmqialSvywTZnOQZZGLqlyj+yV5HGDrEzFnMiFaXBRpbByHgoUhaExJ/8t/0xKQjKlMRAY65w+zNZQ==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/package.json b/package.json index 4ca11450d04..9d824be17cf 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "cross-env": "7.0.3", "css-loader": "6.8.1", "del": "6.1.1", - "electron": "24.8.5", + "electron": "26.3.0", "electron-builder": "^23.6.0", "electron-log": "4.4.8", "electron-reload": "2.0.0-alpha.1", From 21fef9d38d7519abf3b10019c125e840c9d268f3 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:06:40 +1000 Subject: [PATCH 08/33] [AC-1453] Update TrialInitiationModule with new standalone component (#6448) * import new standalone components directly into TrialInitiationModule instead of importing and re-exporting through LooseComponentsModule --- .../auth/trial-initiation/trial-initiation.module.ts | 6 ++++-- apps/web/src/app/shared/loose-components.module.ts | 11 ----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/auth/trial-initiation/trial-initiation.module.ts b/apps/web/src/app/auth/trial-initiation/trial-initiation.module.ts index 222ad94923c..426ce3e2e7c 100644 --- a/apps/web/src/app/auth/trial-initiation/trial-initiation.module.ts +++ b/apps/web/src/app/auth/trial-initiation/trial-initiation.module.ts @@ -6,9 +6,10 @@ import { FormFieldModule } from "@bitwarden/components"; import { OrganizationCreateModule } from "../../admin-console/organizations/create/organization-create.module"; import { RegisterFormModule } from "../../auth/register-form/register-form.module"; +import { PaymentComponent, TaxInfoComponent } from "../../billing"; import { BillingComponent } from "../../billing/accounts/trial-initiation/billing.component"; import { EnvironmentSelectorModule } from "../../components/environment-selector/environment-selector.module"; -import { LooseComponentsModule, SharedModule } from "../../shared"; +import { SharedModule } from "../../shared"; import { ConfirmationDetailsComponent } from "./confirmation-details.component"; import { AbmEnterpriseContentComponent } from "./content/abm-enterprise-content.component"; @@ -37,8 +38,9 @@ import { VerticalStepperModule } from "./vertical-stepper/vertical-stepper.modul FormFieldModule, RegisterFormModule, OrganizationCreateModule, - LooseComponentsModule, EnvironmentSelectorModule, + PaymentComponent, + TaxInfoComponent, ], declarations: [ TrialInitiationComponent, diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index 86c0da0d908..6efaf3653da 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -51,7 +51,6 @@ import { UpdatePasswordComponent } from "../auth/update-password.component"; import { UpdateTempPasswordComponent } from "../auth/update-temp-password.component"; import { VerifyEmailTokenComponent } from "../auth/verify-email-token.component"; import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.component"; -import { BillingSharedModule } from "../billing/shared"; import { DynamicAvatarComponent } from "../components/dynamic-avatar.component"; import { SelectableAvatarComponent } from "../components/selectable-avatar.component"; import { FooterComponent } from "../layouts/footer.component"; @@ -107,11 +106,6 @@ import { SharedModule } from "./shared.module"; EnvironmentSelectorModule, AccountFingerprintComponent, PasswordCalloutComponent, - - // Temporary export to be removed in AC-1453 - // Import PaymentComponent and TaxInfoComponent directly into TrialIniationComponent - // and remove BillingSharedModule here - BillingSharedModule, ], declarations: [ AcceptEmergencyComponent, @@ -282,11 +276,6 @@ import { SharedModule } from "./shared.module"; VerifyEmailTokenComponent, VerifyRecoverDeleteComponent, LowKdfComponent, - - // Temporary export to be removed in AC-1453 - // Import PaymentComponent and TaxInfoComponent directly into TrialIniationComponent - // and remove BillingSharedModule here - BillingSharedModule, ], }) export class LooseComponentsModule {} From 320c1a59702fbf7a8cad10010505b8c51b9689c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:29:22 +0200 Subject: [PATCH 09/33] Update dependency postcss to v8.4.31 [SECURITY] (#6530) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2725952486d..9ab91abac71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -154,7 +154,7 @@ "mini-css-extract-plugin": "2.7.6", "node-ipc": "9.2.1", "pkg": "5.8.1", - "postcss": "8.4.27", + "postcss": "8.4.31", "postcss-loader": "7.3.3", "prettier": "2.8.8", "prettier-plugin-tailwindcss": "0.3.0", @@ -32902,9 +32902,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 9d824be17cf..2cd1718c1e5 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "mini-css-extract-plugin": "2.7.6", "node-ipc": "9.2.1", "pkg": "5.8.1", - "postcss": "8.4.27", + "postcss": "8.4.31", "postcss-loader": "7.3.3", "prettier": "2.8.8", "prettier-plugin-tailwindcss": "0.3.0", From 3b803f62c58d644ee973609915ef6a1099558cc5 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Mon, 9 Oct 2023 10:29:50 -0400 Subject: [PATCH 10/33] [PM-4083] Fix case of misused promise (#6443) * fix misused promise * await resolution of totpService.getCode --- .../browser/src/autofill/services/autofill.service.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index ee233c42524..aca72562287 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -148,7 +148,7 @@ export default class AutofillService implements AutofillServiceInterface { throw new Error("Nothing to auto-fill."); } - let totpPromise: Promise = null; + let totp: string | null = null; const canAccessPremium = await this.stateService.getCanAccessPremium(); const defaultUriMatch = (await this.stateService.getDefaultUriMatch()) ?? UriMatchType.Domain; @@ -205,15 +205,14 @@ export default class AutofillService implements AutofillServiceInterface { if ( options.cipher.type !== CipherType.Login || - // eslint-disable-next-line @typescript-eslint/no-misused-promises - totpPromise || + totp !== null || !options.cipher.login.totp || (!canAccessPremium && !options.cipher.organizationUseTotp) ) { return; } - totpPromise = this.stateService.getDisableAutoTotpCopy().then((disabled) => { + totp = await this.stateService.getDisableAutoTotpCopy().then((disabled) => { if (!disabled) { return this.totpService.getCode(options.cipher.login.totp); } @@ -224,8 +223,8 @@ export default class AutofillService implements AutofillServiceInterface { if (didAutofill) { this.eventCollectionService.collect(EventType.Cipher_ClientAutofilled, options.cipher.id); - if (totpPromise != null) { - return await totpPromise; + if (totp !== null) { + return totp; } else { return null; } From b2aa33f5a372c54d23da0bbae59261a937b7d4b3 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 9 Oct 2023 11:55:36 -0400 Subject: [PATCH 11/33] [PM-4194] refactor vault api implementation for federated users (#6519) * refactor vault api implementation * remove extra new line * user type context * refactor getK1 * simplify get k1 more --- .../lastpass/access/federated-user-context.ts | 6 + .../{user-type.ts => user-type-context.ts} | 33 ++-- .../src/importers/lastpass/access/vault.ts | 164 ++++++++++++++---- 3 files changed, 160 insertions(+), 43 deletions(-) create mode 100644 libs/importer/src/importers/lastpass/access/federated-user-context.ts rename libs/importer/src/importers/lastpass/access/{user-type.ts => user-type-context.ts} (59%) diff --git a/libs/importer/src/importers/lastpass/access/federated-user-context.ts b/libs/importer/src/importers/lastpass/access/federated-user-context.ts new file mode 100644 index 00000000000..7f56a695d95 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/federated-user-context.ts @@ -0,0 +1,6 @@ +export class FederatedUserContext { + username: string; + idpUserInfo: any; + accessToken: string; + idToken: string; +} diff --git a/libs/importer/src/importers/lastpass/access/user-type.ts b/libs/importer/src/importers/lastpass/access/user-type-context.ts similarity index 59% rename from libs/importer/src/importers/lastpass/access/user-type.ts rename to libs/importer/src/importers/lastpass/access/user-type-context.ts index 8321cfa7363..f2629d59516 100644 --- a/libs/importer/src/importers/lastpass/access/user-type.ts +++ b/libs/importer/src/importers/lastpass/access/user-type-context.ts @@ -1,27 +1,17 @@ -export class UserType { - /* - Type values - 0 = Master Password - 3 = Federated - */ - type: number; +export class UserTypeContext { + type: Type; IdentityProviderGUID: string; IdentityProviderURL: string; OpenIDConnectAuthority: string; OpenIDConnectClientId: string; CompanyId: number; - /* - Provider Values - 0 = LastPass - 2 = Okta - */ - Provider: number; + Provider: Provider; PkceEnabled: boolean; IsPasswordlessEnabled: boolean; isFederated(): boolean { return ( - this.type === 3 && + this.type === Type.Federated && this.hasValue(this.IdentityProviderURL) && this.hasValue(this.OpenIDConnectAuthority) && this.hasValue(this.OpenIDConnectClientId) @@ -32,3 +22,18 @@ export class UserType { return str != null && str.trim() !== ""; } } + +export enum Provider { + Azure = 0, + OktaAuthServer = 1, + OktaNoAuthServer = 2, + Google = 3, + PingOne = 4, + OneLogin = 5, +} + +export enum Type { + MasterPassword = 0, + // Not sure what Types 1 and 2 are? + Federated = 3, +} diff --git a/libs/importer/src/importers/lastpass/access/vault.ts b/libs/importer/src/importers/lastpass/access/vault.ts index 6cbee8028ca..157965804c2 100644 --- a/libs/importer/src/importers/lastpass/access/vault.ts +++ b/libs/importer/src/importers/lastpass/access/vault.ts @@ -1,3 +1,4 @@ +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { HttpStatusCode } from "@bitwarden/common/enums"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -6,19 +7,24 @@ import { Account } from "./account"; import { Client } from "./client"; import { ClientInfo } from "./client-info"; import { CryptoUtils } from "./crypto-utils"; +import { FederatedUserContext } from "./federated-user-context"; import { Parser } from "./parser"; import { ParserOptions } from "./parser-options"; import { RestClient } from "./rest-client"; import { Ui } from "./ui"; -import { UserType } from "./user-type"; +import { Provider, UserTypeContext } from "./user-type-context"; export class Vault { accounts: Account[]; + userType: UserTypeContext; private client: Client; private cryptoUtils: CryptoUtils; - constructor(private cryptoFunctionService: CryptoFunctionService) { + constructor( + private cryptoFunctionService: CryptoFunctionService, + private tokenService: TokenService + ) { this.cryptoUtils = new CryptoUtils(cryptoFunctionService); const parser = new Parser(cryptoFunctionService, this.cryptoUtils); this.client = new Client(parser, this.cryptoUtils); @@ -35,24 +41,25 @@ export class Vault { } async openFederated( - username: string, - k1: string, - k2: string, + federatedUser: FederatedUserContext, clientInfo: ClientInfo, ui: Ui, parserOptions: ParserOptions = ParserOptions.default ): Promise { - const k1Arr = Utils.fromByteStringToArray(k1); - const k2Arr = Utils.fromB64ToArray(k2); + if (federatedUser == null) { + throw "Federated user context is not set."; + } + const k1 = await this.getK1(federatedUser); + const k2 = await this.getK2(federatedUser); const hiddenPasswordArr = await this.cryptoFunctionService.hash( - this.cryptoUtils.ExclusiveOr(k1Arr, k2Arr), + this.cryptoUtils.ExclusiveOr(k1, k2), "sha256" ); const hiddenPassword = Utils.fromBufferToB64(hiddenPasswordArr); - await this.open(username, hiddenPassword, clientInfo, ui, parserOptions); + await this.open(federatedUser.username, hiddenPassword, clientInfo, ui, parserOptions); } - async getUserType(username: string): Promise { + async setUserTypeContext(username: string) { const lowercaseUsername = username.toLowerCase(); const rest = new RestClient(); rest.baseUrl = "https://lastpass.com"; @@ -60,35 +67,134 @@ export class Vault { const response = await rest.get(endpoint); if (response.status === HttpStatusCode.Ok) { const json = await response.json(); - const userType = new UserType(); - userType.CompanyId = json.CompanyId; - userType.IdentityProviderGUID = json.IdentityProviderGUID; - userType.IdentityProviderURL = json.IdentityProviderURL; - userType.IsPasswordlessEnabled = json.IsPasswordlessEnabled; - userType.OpenIDConnectAuthority = json.OpenIDConnectAuthority; - userType.OpenIDConnectClientId = json.OpenIDConnectClientId; - userType.PkceEnabled = json.PkceEnabled; - userType.Provider = json.Provider; - userType.type = json.type; - return userType; + this.userType = new UserTypeContext(); + this.userType.CompanyId = json.CompanyId; + this.userType.IdentityProviderGUID = json.IdentityProviderGUID; + this.userType.IdentityProviderURL = json.IdentityProviderURL; + this.userType.IsPasswordlessEnabled = json.IsPasswordlessEnabled; + this.userType.OpenIDConnectAuthority = json.OpenIDConnectAuthority; + this.userType.OpenIDConnectClientId = json.OpenIDConnectClientId; + this.userType.PkceEnabled = json.PkceEnabled; + this.userType.Provider = json.Provider; + this.userType.type = json.type; } throw "Cannot determine LastPass user type."; } - async getIdentityProviderKey(userType: UserType, idToken: string): Promise { - if (!userType.isFederated()) { - throw "Cannot get identity provider key for a LastPass user that is not federated."; + private async getK1(federatedUser: FederatedUserContext): Promise { + if (this.userType == null) { + throw "User type is not set."; + } + + if (!this.userType.isFederated()) { + throw "Cannot get k1 for LastPass user that is not federated."; + } + + if (federatedUser == null) { + throw "Federated user is not set."; + } + + let k1: Uint8Array = null; + if (federatedUser.idpUserInfo?.LastPassK1 !== null) { + return Utils.fromByteStringToArray(federatedUser.idpUserInfo.LastPassK1); + } else if (this.userType.Provider === Provider.Azure) { + k1 = await this.getK1Azure(federatedUser); + } else if (this.userType.Provider === Provider.Google) { + k1 = await this.getK1Google(federatedUser); + } else { + const b64Encoded = this.userType.Provider === Provider.PingOne; + k1 = this.getK1FromAccessToken(federatedUser, b64Encoded); + } + + if (k1 !== null) { + return k1; + } + + throw "Cannot get k1."; + } + + private async getK1Azure(federatedUser: FederatedUserContext) { + // Query the Graph API for the k1 field + const rest = new RestClient(); + rest.baseUrl = "https://graph.microsoft.com"; + const response = await rest.get( + "v1.0/me?$select=id,displayName,mail&$expand=extensions", + new Map([["Authorization", "Bearer " + federatedUser.accessToken]]) + ); + if (response.status === HttpStatusCode.Ok) { + const json = await response.json(); + const k1 = json?.extensions?.LastPassK1 as string; + if (k1 !== null) { + return Utils.fromB64ToArray(k1); + } + } + return null; + } + + private async getK1Google(federatedUser: FederatedUserContext) { + // Query Google Drive for the k1.lp file + const accessTokenAuthHeader = new Map([ + ["Authorization", "Bearer " + federatedUser.accessToken], + ]); + const rest = new RestClient(); + rest.baseUrl = "https://content.googleapis.com"; + const response = await rest.get( + "drive/v3/files?pageSize=1" + + "&q=name%20%3D%20%27k1.lp%27" + + "&spaces=appDataFolder" + + "&fields=nextPageToken%2C%20files(id%2C%20name)", + accessTokenAuthHeader + ); + if (response.status === HttpStatusCode.Ok) { + const json = await response.json(); + const files = json?.files as any[]; + if (files !== null && files.length > 0 && files[0].id != null && files[0].name === "k1.lp") { + // Open the k1.lp file + rest.baseUrl = "https://www.googleapis.com"; + const response = await rest.get( + "drive/v3/files/" + files[0].id + "?alt=media", + accessTokenAuthHeader + ); + if (response.status === HttpStatusCode.Ok) { + const k1 = await response.text(); + return Utils.fromB64ToArray(k1); + } + } } + return null; + } + + private getK1FromAccessToken(federatedUser: FederatedUserContext, b64: boolean) { + const decodedAccessToken = this.tokenService.decodeToken(federatedUser.accessToken); + const k1 = decodedAccessToken?.LastPassK1 as string; + if (k1 !== null) { + return b64 ? Utils.fromB64ToArray(k1) : Utils.fromByteStringToArray(k1); + } + return null; + } + + private async getK2(federatedUser: FederatedUserContext): Promise { + if (this.userType == null) { + throw "User type is not set."; + } + + if (!this.userType.isFederated()) { + throw "Cannot get k2 for LastPass user that is not federated."; + } + const rest = new RestClient(); - rest.baseUrl = userType.IdentityProviderURL; + rest.baseUrl = this.userType.IdentityProviderURL; const response = await rest.postJson("federatedlogin/api/v1/getkey", { - company_id: userType.CompanyId, - id_token: idToken, + company_id: this.userType.CompanyId, + id_token: federatedUser.idToken, }); if (response.status === HttpStatusCode.Ok) { const json = await response.json(); - return json["k2"] as string; + const k2 = json?.k2 as string; + if (k2 !== null) { + return Utils.fromB64ToArray(k2); + } } - throw "Cannot get identity provider key from LastPass."; + throw "Cannot get k2."; } } From 725ee08640eca13f9278ff49fc1dfcd0e8efc2c0 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 10 Oct 2023 15:10:26 +0200 Subject: [PATCH 12/33] [PM-2014] Passkey registration (#5396) * [PM-2014] feat: scaffold new fido2 login component and module * [PM-1024] feat: add content to login settings component * [PM-1024] feat: add badge and button aria label * [PM-2014] feat: create new dialog * feat: add ability to remove form field bottom margin (cherry picked from commit 05925ff77ed47f3865c2aecade8271390d9e2fa6) * [PM-2014] feat: disable dialog close button * [PM-2014] feat: implement mocked failing wizard flow * [PM-2014] feat: add icons and other content * [PM-2014] feat: change wording to "creating" password * [PM-2014] feat: add new auth and auth core modules * [PM-2014] chore: move fido2-login-settings to auth module * [PM-2014] chore: expose using barrel files * [PM-2014] feat: fetch webauthn challenge * [PM-2014] chore: refactor api logic into new api service and move ui logic into existing service * [PM-2014] feat: add tests for new credential options * [PM-2014] feat: return undefined when credential creation fails * [PM-2014] feat: implement credential creation * [PM-2014] feat: add passkey naming ui * [PM-2014] feat: add support for creation token * [PM-2014] feat: implement credential saving * [PM-2014] feat: Basic list of credentials * [PM-2014] feat: improve async data loading * [PM-2014] feat: finish up list UI * [PM-2014] fix: loading state not being set properly * [PM-2014] feat: improve aria labels * [PM-2014] feat: show toast on passkey saved * [PM-2014] feat: add delete dialog * [PM-2014] feat: implement deletion without user verification * [PM-2014] feat: add user verification to delete * [PM-2014] feat: change to danger button * [PM-2014] feat: show `save` if passkeys already exist * [PM-2014] feat: add passkey limit * [PM-2014] feat: improve error on delete * [PM-2014] feat: add support for feature flag * [PM-2014] feat: update copy * [PM-2014] feat: reduce remove button margin * [PM-2014] feat: refactor submit method * [PM-2014] feat: autofocus fields * [PM-2014] fix: move error handling to components After discussing it with Jake we decided that following convention was best. * [PM-2014] feat: change toast depending on existing passkeys * [PM-2014] chore: rename everything from `fido2` to `webauthn` * [PM-2014] fix: `CoreAuthModule` duplicate import * [PM-2014] feat: change to new figma design `Encryption not supported` * [PM-2014] fix: add missing href * [PM-2014] fix: misaligned badge * [PM-2014] chore: remove whitespace * [PM-2014] fix: dialog close bug * [PM-2014] fix: badge alignment not applying properly * [PM-2014] fix: remove redundant align class * [PM-2014] chore: move CoreAuthModule to AuthModule * [PM-2014] feat: create new settings module * [PM-2014] feat: move change password component to settings module * [PM-2014] chore: tweak loose components recommendation * [PM-2014] fix: remove deprecated pattern * [PM-2014] chore: rename everything to `WebauthnLogin` to follow new naming scheme * [PM-2014] chore: document requests and responses * [PM-2014] fix: remove `undefined` * [PM-2014] fix: clarify webauthn login service * [PM-2014] fix: use `getCredentials$()` * [PM-2014] fix: badge alignment using important statement * [PM-2014] fix: remove sm billing flag * [PM-2014] fix: `CoreAuthModule` double import * [PM-2014] fix: unimported component (issue due to conflict with master) * [PM-2014] fix: unawaited promise bug --- apps/web/src/app/auth/auth.module.ts | 12 ++ apps/web/src/app/auth/core/core.module.ts | 15 ++ apps/web/src/app/auth/core/index.ts | 2 + apps/web/src/app/auth/core/services/index.ts | 1 + .../core/services/webauthn-login/index.ts | 1 + .../request/save-credential.request.ts | 18 ++ ...uthn-login-attestation-response.request.ts | 27 +++ ...hn-login-authenticator-response.request.ts | 19 ++ ...ogin-credential-create-options.response.ts | 22 +++ .../webauthn-login-credential.response.ts | 17 ++ .../webauthn-login-api.service.ts | 40 ++++ .../webauthn-login.service.spec.ts | 63 +++++++ .../webauthn-login/webauthn-login.service.ts | 109 +++++++++++ .../views/credential-create-options.view.ts | 5 + .../core/views/webauth-credential.view.ts | 5 + apps/web/src/app/auth/index.ts | 2 + .../settings/change-password.component.html | 13 +- .../settings/change-password.component.ts | 15 +- .../src/app/auth/settings/settings.module.ts | 16 ++ .../create-credential-dialog.component.html | 70 +++++++ .../create-credential-dialog.component.ts | 178 ++++++++++++++++++ .../create-passkey-failed.icon.ts | 28 +++ .../create-passkey.icon.ts | 26 +++ .../delete-credential-dialog.component.html | 34 ++++ .../delete-credential-dialog.component.ts | 95 ++++++++++ .../settings/webauthn-login-settings/index.ts | 1 + .../webauthn-login-settings.component.html | 71 +++++++ .../webauthn-login-settings.component.ts | 72 +++++++ .../webauthn-login-settings.module.ts | 19 ++ apps/web/src/app/oss.module.ts | 2 + .../src/app/shared/loose-components.module.ts | 3 - apps/web/src/locales/en/messages.json | 82 ++++++++ libs/common/src/enums/feature-flag.enum.ts | 1 + .../directives/dialog-close.directive.ts | 14 +- 34 files changed, 1088 insertions(+), 10 deletions(-) create mode 100644 apps/web/src/app/auth/auth.module.ts create mode 100644 apps/web/src/app/auth/core/core.module.ts create mode 100644 apps/web/src/app/auth/core/index.ts create mode 100644 apps/web/src/app/auth/core/services/index.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/index.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts create mode 100644 apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts create mode 100644 apps/web/src/app/auth/core/views/credential-create-options.view.ts create mode 100644 apps/web/src/app/auth/core/views/webauth-credential.view.ts create mode 100644 apps/web/src/app/auth/index.ts create mode 100644 apps/web/src/app/auth/settings/settings.module.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/index.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.ts create mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.module.ts diff --git a/apps/web/src/app/auth/auth.module.ts b/apps/web/src/app/auth/auth.module.ts new file mode 100644 index 00000000000..49be17aa264 --- /dev/null +++ b/apps/web/src/app/auth/auth.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; + +import { CoreAuthModule } from "./core"; +import { SettingsModule } from "./settings/settings.module"; + +@NgModule({ + imports: [CoreAuthModule, SettingsModule], + declarations: [], + providers: [], + exports: [SettingsModule], +}) +export class AuthModule {} diff --git a/apps/web/src/app/auth/core/core.module.ts b/apps/web/src/app/auth/core/core.module.ts new file mode 100644 index 00000000000..e196b1c3d76 --- /dev/null +++ b/apps/web/src/app/auth/core/core.module.ts @@ -0,0 +1,15 @@ +import { NgModule, Optional, SkipSelf } from "@angular/core"; + +import { WebauthnLoginApiService } from "./services/webauthn-login/webauthn-login-api.service"; +import { WebauthnLoginService } from "./services/webauthn-login/webauthn-login.service"; + +@NgModule({ + providers: [WebauthnLoginService, WebauthnLoginApiService], +}) +export class CoreAuthModule { + constructor(@Optional() @SkipSelf() parentModule?: CoreAuthModule) { + if (parentModule) { + throw new Error("CoreAuthModule is already loaded. Import it in AuthModule only"); + } + } +} diff --git a/apps/web/src/app/auth/core/index.ts b/apps/web/src/app/auth/core/index.ts new file mode 100644 index 00000000000..3d2d739adf9 --- /dev/null +++ b/apps/web/src/app/auth/core/index.ts @@ -0,0 +1,2 @@ +export * from "./services"; +export * from "./core.module"; diff --git a/apps/web/src/app/auth/core/services/index.ts b/apps/web/src/app/auth/core/services/index.ts new file mode 100644 index 00000000000..4ef20f4b97d --- /dev/null +++ b/apps/web/src/app/auth/core/services/index.ts @@ -0,0 +1 @@ +export * from "./webauthn-login"; diff --git a/apps/web/src/app/auth/core/services/webauthn-login/index.ts b/apps/web/src/app/auth/core/services/webauthn-login/index.ts new file mode 100644 index 00000000000..10dea636b8d --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/index.ts @@ -0,0 +1 @@ +export * from "./webauthn-login.service"; diff --git a/apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts b/apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts new file mode 100644 index 00000000000..ffd0e6cf709 --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts @@ -0,0 +1,18 @@ +import { WebauthnLoginAttestationResponseRequest } from "./webauthn-login-attestation-response.request"; + +/** + * Request sent to the server to save a newly created webauthn login credential. + */ +export class SaveCredentialRequest { + /** The response recieved from the authenticator. This contains the public key */ + deviceResponse: WebauthnLoginAttestationResponseRequest; + + /** Nickname chosen by the user to identify this credential */ + name: string; + + /** + * Token required by the server to complete the creation. + * It contains encrypted information that the server needs to verify the credential. + */ + token: string; +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts new file mode 100644 index 00000000000..4b33896290c --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts @@ -0,0 +1,27 @@ +import { Utils } from "@bitwarden/common/platform/misc/utils"; + +import { WebauthnLoginAuthenticatorResponseRequest } from "./webauthn-login-authenticator-response.request"; + +/** + * The response recieved from an authentiator after a successful attestation. + * This request is used to save newly created webauthn login credentials to the server. + */ +export class WebauthnLoginAttestationResponseRequest extends WebauthnLoginAuthenticatorResponseRequest { + response: { + attestationObject: string; + clientDataJson: string; + }; + + constructor(credential: PublicKeyCredential) { + super(credential); + + if (!(credential.response instanceof AuthenticatorAttestationResponse)) { + throw new Error("Invalid authenticator response"); + } + + this.response = { + attestationObject: Utils.fromBufferToB64(credential.response.attestationObject), + clientDataJson: Utils.fromBufferToB64(credential.response.clientDataJSON), + }; + } +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts new file mode 100644 index 00000000000..9e332ad5381 --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts @@ -0,0 +1,19 @@ +import { Utils } from "@bitwarden/common/platform/misc/utils"; + +/** + * An abstract class that represents responses recieved from the webauthn authenticator. + * It contains data that is commonly returned during different types of authenticator interactions. + */ +export abstract class WebauthnLoginAuthenticatorResponseRequest { + id: string; + rawId: string; + type: string; + extensions: Record; + + constructor(credential: PublicKeyCredential) { + this.id = credential.id; + this.rawId = Utils.fromBufferToB64(credential.rawId); + this.type = credential.type; + this.extensions = {}; // Extensions are handled client-side + } +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts new file mode 100644 index 00000000000..ce588207727 --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts @@ -0,0 +1,22 @@ +import { ChallengeResponse } from "@bitwarden/common/auth/models/response/two-factor-web-authn.response"; +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +/** + * Options provided by the server to be used during attestation (i.e. creation of a new webauthn credential) + */ +export class WebauthnLoginCredentialCreateOptionsResponse extends BaseResponse { + /** Options to be provided to the webauthn authenticator */ + options: ChallengeResponse; + + /** + * Contains an encrypted version of the {@link options}. + * Used by the server to validate the attestation response of newly created credentials. + */ + token: string; + + constructor(response: unknown) { + super(response); + this.options = new ChallengeResponse(this.getResponseProperty("options")); + this.token = this.getResponseProperty("token"); + } +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts new file mode 100644 index 00000000000..7a7f5199e7c --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts @@ -0,0 +1,17 @@ +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +/** + * A webauthn login credential recieved from the server. + */ +export class WebauthnLoginCredentialResponse extends BaseResponse { + id: string; + name: string; + prfSupport: boolean; + + constructor(response: unknown) { + super(response); + this.id = this.getResponseProperty("id"); + this.name = this.getResponseProperty("name"); + this.prfSupport = this.getResponseProperty("prfSupport"); + } +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts new file mode 100644 index 00000000000..33e1aea369b --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from "@angular/core"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { ListResponse } from "@bitwarden/common/models/response/list.response"; +import { Verification } from "@bitwarden/common/types/verification"; + +import { SaveCredentialRequest } from "./request/save-credential.request"; +import { WebauthnLoginCredentialCreateOptionsResponse } from "./response/webauthn-login-credential-create-options.response"; +import { WebauthnLoginCredentialResponse } from "./response/webauthn-login-credential.response"; + +@Injectable() +export class WebauthnLoginApiService { + constructor( + private apiService: ApiService, + private userVerificationService: UserVerificationService + ) {} + + async getCredentialCreateOptions( + verification: Verification + ): Promise { + const request = await this.userVerificationService.buildRequest(verification); + const response = await this.apiService.send("POST", "/webauthn/options", request, true, true); + return new WebauthnLoginCredentialCreateOptionsResponse(response); + } + + async saveCredential(request: SaveCredentialRequest): Promise { + await this.apiService.send("POST", "/webauthn", request, true, true); + return true; + } + + getCredentials(): Promise> { + return this.apiService.send("GET", "/webauthn", null, true, true); + } + + async deleteCredential(credentialId: string, verification: Verification): Promise { + const request = await this.userVerificationService.buildRequest(verification); + await this.apiService.send("POST", `/webauthn/${credentialId}/delete`, request, true, true); + } +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts new file mode 100644 index 00000000000..070513f19e8 --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts @@ -0,0 +1,63 @@ +import { mock, MockProxy } from "jest-mock-extended"; + +import { CredentialCreateOptionsView } from "../../views/credential-create-options.view"; + +import { WebauthnLoginApiService } from "./webauthn-login-api.service"; +import { WebauthnLoginService } from "./webauthn-login.service"; + +describe("WebauthnService", () => { + let apiService!: MockProxy; + let credentials: MockProxy; + let webauthnService!: WebauthnLoginService; + + beforeAll(() => { + // Polyfill missing class + window.PublicKeyCredential = class {} as any; + window.AuthenticatorAttestationResponse = class {} as any; + apiService = mock(); + credentials = mock(); + webauthnService = new WebauthnLoginService(apiService, credentials); + }); + + describe("createCredential", () => { + it("should return undefined when navigator.credentials throws", async () => { + credentials.create.mockRejectedValue(new Error("Mocked error")); + const options = createCredentialCreateOptions(); + + const result = await webauthnService.createCredential(options); + + expect(result).toBeUndefined(); + }); + + it("should return credential when navigator.credentials does not throw", async () => { + const credential = createDeviceResponse(); + credentials.create.mockResolvedValue(credential as PublicKeyCredential); + const options = createCredentialCreateOptions(); + + const result = await webauthnService.createCredential(options); + + expect(result).toBe(credential); + }); + }); +}); + +function createCredentialCreateOptions(): CredentialCreateOptionsView { + return new CredentialCreateOptionsView(Symbol() as any, Symbol() as any); +} + +function createDeviceResponse(): PublicKeyCredential { + const credential = { + id: "dGVzdA==", + rawId: new Uint8Array([0x74, 0x65, 0x73, 0x74]), + type: "public-key", + response: { + attestationObject: new Uint8Array([0, 0, 0]), + clientDataJSON: "eyJ0ZXN0IjoidGVzdCJ9", + }, + } as any; + + Object.setPrototypeOf(credential, PublicKeyCredential.prototype); + Object.setPrototypeOf(credential.response, AuthenticatorAttestationResponse.prototype); + + return credential; +} diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts new file mode 100644 index 00000000000..760214961a7 --- /dev/null +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts @@ -0,0 +1,109 @@ +import { Injectable, Optional } from "@angular/core"; +import { BehaviorSubject, filter, from, map, Observable, shareReplay, switchMap, tap } from "rxjs"; + +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { Verification } from "@bitwarden/common/types/verification"; + +import { CredentialCreateOptionsView } from "../../views/credential-create-options.view"; +import { WebauthnCredentialView } from "../../views/webauth-credential.view"; + +import { SaveCredentialRequest } from "./request/save-credential.request"; +import { WebauthnLoginAttestationResponseRequest } from "./request/webauthn-login-attestation-response.request"; +import { WebauthnLoginApiService } from "./webauthn-login-api.service"; + +@Injectable() +export class WebauthnLoginService { + private navigatorCredentials: CredentialsContainer; + private _refresh$ = new BehaviorSubject(undefined); + private _loading$ = new BehaviorSubject(true); + private readonly credentials$ = this._refresh$.pipe( + tap(() => this._loading$.next(true)), + switchMap(() => this.fetchCredentials$()), + tap(() => this._loading$.next(false)), + shareReplay({ bufferSize: 1, refCount: true }) + ); + + readonly loading$ = this._loading$.asObservable(); + + constructor( + private apiService: WebauthnLoginApiService, + @Optional() navigatorCredentials?: CredentialsContainer, + @Optional() private logService?: LogService + ) { + // Default parameters don't work when used with Angular DI + this.navigatorCredentials = navigatorCredentials ?? navigator.credentials; + } + + async getCredentialCreateOptions( + verification: Verification + ): Promise { + const response = await this.apiService.getCredentialCreateOptions(verification); + return new CredentialCreateOptionsView(response.options, response.token); + } + + async createCredential( + credentialOptions: CredentialCreateOptionsView + ): Promise { + const nativeOptions: CredentialCreationOptions = { + publicKey: credentialOptions.options, + }; + + try { + const response = await this.navigatorCredentials.create(nativeOptions); + if (!(response instanceof PublicKeyCredential)) { + return undefined; + } + return response; + } catch (error) { + this.logService?.error(error); + return undefined; + } + } + + async saveCredential( + credentialOptions: CredentialCreateOptionsView, + deviceResponse: PublicKeyCredential, + name: string + ) { + const request = new SaveCredentialRequest(); + request.deviceResponse = new WebauthnLoginAttestationResponseRequest(deviceResponse); + request.token = credentialOptions.token; + request.name = name; + await this.apiService.saveCredential(request); + this.refresh(); + } + + /** + * List of webauthn credentials saved on the server. + * + * **Note:** + * - Subscribing might trigger a network request if the credentials haven't been fetched yet. + * - The observable is shared and will not create unnecessary duplicate requests. + * - The observable will automatically re-fetch if the user adds or removes a credential. + * - The observable is lazy and will only fetch credentials when subscribed to. + * - Don't subscribe to this in the constructor of a long-running service, as it will keep the observable alive. + */ + getCredentials$(): Observable { + return this.credentials$; + } + + getCredential$(credentialId: string): Observable { + return this.credentials$.pipe( + map((credentials) => credentials.find((c) => c.id === credentialId)), + filter((c) => c !== undefined) + ); + } + + async deleteCredential(credentialId: string, verification: Verification): Promise { + await this.apiService.deleteCredential(credentialId, verification); + this.refresh(); + } + + private fetchCredentials$(): Observable { + return from(this.apiService.getCredentials()).pipe(map((response) => response.data)); + } + + private refresh() { + this._refresh$.next(); + } +} diff --git a/apps/web/src/app/auth/core/views/credential-create-options.view.ts b/apps/web/src/app/auth/core/views/credential-create-options.view.ts new file mode 100644 index 00000000000..29efdef5ee6 --- /dev/null +++ b/apps/web/src/app/auth/core/views/credential-create-options.view.ts @@ -0,0 +1,5 @@ +import { ChallengeResponse } from "@bitwarden/common/auth/models/response/two-factor-web-authn.response"; + +export class CredentialCreateOptionsView { + constructor(readonly options: ChallengeResponse, readonly token: string) {} +} diff --git a/apps/web/src/app/auth/core/views/webauth-credential.view.ts b/apps/web/src/app/auth/core/views/webauth-credential.view.ts new file mode 100644 index 00000000000..ff5a9c692df --- /dev/null +++ b/apps/web/src/app/auth/core/views/webauth-credential.view.ts @@ -0,0 +1,5 @@ +export class WebauthnCredentialView { + id: string; + name: string; + prfSupport: boolean; +} diff --git a/apps/web/src/app/auth/index.ts b/apps/web/src/app/auth/index.ts new file mode 100644 index 00000000000..fb09223bd9e --- /dev/null +++ b/apps/web/src/app/auth/index.ts @@ -0,0 +1,2 @@ +export * from "./auth.module"; +export * from "./core"; diff --git a/apps/web/src/app/auth/settings/change-password.component.html b/apps/web/src/app/auth/settings/change-password.component.html index b3ad78168d9..37a4ad5b59a 100644 --- a/apps/web/src/app/auth/settings/change-password.component.html +++ b/apps/web/src/app/auth/settings/change-password.component.html @@ -6,7 +6,14 @@

{{ "changeMasterPassword" | i18n }}

-
+
@@ -118,3 +125,7 @@

{{ "changeMasterPassword" | i18n }}

{{ "changeMasterPassword" | i18n }} + + diff --git a/apps/web/src/app/auth/settings/change-password.component.ts b/apps/web/src/app/auth/settings/change-password.component.ts index 9ed8227316c..958582eb0a7 100644 --- a/apps/web/src/app/auth/settings/change-password.component.ts +++ b/apps/web/src/app/auth/settings/change-password.component.ts @@ -1,6 +1,6 @@ import { Component } from "@angular/core"; import { Router } from "@angular/router"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, Observable } from "rxjs"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -11,12 +11,13 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; -import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { EmergencyAccessStatusType } from "@bitwarden/common/auth/enums/emergency-access-status-type"; import { EmergencyAccessUpdateRequest } from "@bitwarden/common/auth/models/request/emergency-access-update.request"; import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { UpdateKeyRequest } from "@bitwarden/common/models/request/update-key.request"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -50,6 +51,8 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { checkForBreaches = true; characterMinimumMessage = ""; + protected showWebauthnLoginSettings$: Observable; + constructor( i18nService: I18nService, cryptoService: CryptoService, @@ -65,13 +68,13 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { private apiService: ApiService, private sendService: SendService, private organizationService: OrganizationService, - private keyConnectorService: KeyConnectorService, private router: Router, private organizationApiService: OrganizationApiServiceAbstraction, private organizationUserService: OrganizationUserService, dialogService: DialogService, private userVerificationService: UserVerificationService, - private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction + private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + private configService: ConfigServiceAbstraction ) { super( i18nService, @@ -86,6 +89,10 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { } async ngOnInit() { + this.showWebauthnLoginSettings$ = this.configService.getFeatureFlag$( + FeatureFlag.PasswordlessLogin + ); + if (!(await this.userVerificationService.hasMasterPassword())) { this.router.navigate(["/settings/security/two-factor"]); } diff --git a/apps/web/src/app/auth/settings/settings.module.ts b/apps/web/src/app/auth/settings/settings.module.ts new file mode 100644 index 00000000000..282524d07e4 --- /dev/null +++ b/apps/web/src/app/auth/settings/settings.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; + +import { PasswordCalloutComponent } from "@bitwarden/auth"; + +import { SharedModule } from "../../shared"; + +import { ChangePasswordComponent } from "./change-password.component"; +import { WebauthnLoginSettingsModule } from "./webauthn-login-settings"; + +@NgModule({ + imports: [SharedModule, WebauthnLoginSettingsModule, PasswordCalloutComponent], + declarations: [ChangePasswordComponent], + providers: [], + exports: [WebauthnLoginSettingsModule, ChangePasswordComponent], +}) +export class SettingsModule {} diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html new file mode 100644 index 00000000000..57a2c545ca1 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html @@ -0,0 +1,70 @@ +
+ + {{ "loginWithPasskey" | i18n }} + {{ "newPasskey" | i18n }} + + + +

+ {{ "passkeyEnterMasterPassword" | i18n }} +

+ + {{ "masterPassword" | i18n }} + + + {{ "confirmIdentity" | i18n }} + +
+ +
+ +

{{ "creatingPasskeyLoading" | i18n }}

+

{{ "creatingPasskeyLoadingInfo" | i18n }}

+
+ +
+ +

{{ "errorCreatingPasskey" | i18n }}

+

{{ "errorCreatingPasskeyInfo" | i18n }}

+
+ +
+

{{ "passkeySuccessfullyCreated" | i18n }}

+

+ {{ "customPasskeyNameInfo" | i18n }} +

+ + {{ "customName" | i18n }} + + {{ + "charactersCurrentAndMaximum" + | i18n : formGroup.value.credentialNaming.name.length : NameMaxCharacters + }} + +
+
+ + + + +
+
diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts new file mode 100644 index 00000000000..5c93d6f25e2 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts @@ -0,0 +1,178 @@ +import { DialogConfig, DialogRef } from "@angular/cdk/dialog"; +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, Validators } from "@angular/forms"; +import { firstValueFrom, map, Observable } from "rxjs"; + +import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; +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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DialogService } from "@bitwarden/components"; + +import { WebauthnLoginService } from "../../../core"; +import { CredentialCreateOptionsView } from "../../../core/views/credential-create-options.view"; + +import { CreatePasskeyFailedIcon } from "./create-passkey-failed.icon"; +import { CreatePasskeyIcon } from "./create-passkey.icon"; + +export enum CreateCredentialDialogResult { + Success, +} + +type Step = + | "userVerification" + | "credentialCreation" + | "credentialCreationFailed" + | "credentialNaming"; + +@Component({ + templateUrl: "create-credential-dialog.component.html", +}) +export class CreateCredentialDialogComponent implements OnInit { + protected readonly NameMaxCharacters = 50; + protected readonly CreateCredentialDialogResult = CreateCredentialDialogResult; + protected readonly Icons = { CreatePasskeyIcon, CreatePasskeyFailedIcon }; + + protected currentStep: Step = "userVerification"; + protected formGroup = this.formBuilder.group({ + userVerification: this.formBuilder.group({ + masterPassword: ["", [Validators.required]], + }), + credentialNaming: this.formBuilder.group({ + name: ["", Validators.maxLength(50)], + }), + }); + protected credentialOptions?: CredentialCreateOptionsView; + protected deviceResponse?: PublicKeyCredential; + protected hasPasskeys$?: Observable; + + constructor( + private formBuilder: FormBuilder, + private dialogRef: DialogRef, + private webauthnService: WebauthnLoginService, + private platformUtilsService: PlatformUtilsService, + private i18nService: I18nService, + private logService: LogService + ) {} + + ngOnInit(): void { + this.hasPasskeys$ = this.webauthnService + .getCredentials$() + .pipe(map((credentials) => credentials.length > 0)); + } + + protected submit = async () => { + this.dialogRef.disableClose = true; + + try { + switch (this.currentStep) { + case "userVerification": + return await this.submitUserVerification(); + case "credentialCreationFailed": + return await this.submitCredentialCreationFailed(); + case "credentialCreation": + return await this.submitCredentialCreation(); + case "credentialNaming": + return await this.submitCredentialNaming(); + } + } finally { + this.dialogRef.disableClose = false; + } + }; + + protected async submitUserVerification() { + this.formGroup.controls.userVerification.markAllAsTouched(); + if (this.formGroup.controls.userVerification.invalid) { + return; + } + + try { + this.credentialOptions = await this.webauthnService.getCredentialCreateOptions({ + type: VerificationType.MasterPassword, + secret: this.formGroup.value.userVerification.masterPassword, + }); + } catch (error) { + if (error instanceof ErrorResponse && error.statusCode === 400) { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("error"), + this.i18nService.t("invalidMasterPassword") + ); + } else { + this.logService?.error(error); + this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError")); + } + return; + } + + this.currentStep = "credentialCreation"; + await this.submitCredentialCreation(); + } + + protected async submitCredentialCreation() { + this.deviceResponse = await this.webauthnService.createCredential(this.credentialOptions); + if (this.deviceResponse === undefined) { + this.currentStep = "credentialCreationFailed"; + return; + } + + this.currentStep = "credentialNaming"; + } + + protected async submitCredentialCreationFailed() { + this.currentStep = "credentialCreation"; + await this.submitCredentialCreation(); + } + + protected async submitCredentialNaming() { + this.formGroup.controls.credentialNaming.markAllAsTouched(); + if (this.formGroup.controls.credentialNaming.invalid) { + return; + } + + const name = this.formGroup.value.credentialNaming.name; + try { + await this.webauthnService.saveCredential( + this.credentialOptions, + this.deviceResponse, + this.formGroup.value.credentialNaming.name + ); + } catch (error) { + this.logService?.error(error); + this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError")); + return; + } + + if (await firstValueFrom(this.hasPasskeys$)) { + this.platformUtilsService.showToast( + "success", + null, + this.i18nService.t("passkeySaved", name) + ); + } else { + this.platformUtilsService.showToast( + "success", + null, + this.i18nService.t("loginWithPasskeyEnabled") + ); + } + + this.dialogRef.close(CreateCredentialDialogResult.Success); + } +} + +/** + * Strongly typed helper to open a CreateCredentialDialog + * @param dialogService Instance of the dialog service that will be used to open the dialog + * @param config Configuration for the dialog + */ +export const openCreateCredentialDialog = ( + dialogService: DialogService, + config: DialogConfig +) => { + return dialogService.open( + CreateCredentialDialogComponent, + config + ); +}; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts new file mode 100644 index 00000000000..39a2389c5a9 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts @@ -0,0 +1,28 @@ +import { svgIcon } from "@bitwarden/components"; + +export const CreatePasskeyFailedIcon = svgIcon` + + + + + + + + + + + +`; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts new file mode 100644 index 00000000000..c0e984bbee2 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts @@ -0,0 +1,26 @@ +import { svgIcon } from "@bitwarden/components"; + +export const CreatePasskeyIcon = svgIcon` + + + + + + + + + + +`; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html new file mode 100644 index 00000000000..4cfdbbcf7fe --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html @@ -0,0 +1,34 @@ +
+ + {{ "removePasskey" | i18n }} + {{ + credential.name + }} + + + + + + + +

{{ "removePasskeyInfo" | i18n }}

+ + + {{ "masterPassword" | i18n }} + + + {{ "confirmIdentity" | i18n }} + +
+
+ + + + +
+
diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts new file mode 100644 index 00000000000..7cb03238392 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts @@ -0,0 +1,95 @@ +import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog"; +import { Component, Inject, OnDestroy, OnInit } from "@angular/core"; +import { FormBuilder, Validators } from "@angular/forms"; +import { Subject, takeUntil } from "rxjs"; + +import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; +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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DialogService } from "@bitwarden/components"; + +import { WebauthnLoginService } from "../../../core"; +import { WebauthnCredentialView } from "../../../core/views/webauth-credential.view"; + +export interface DeleteCredentialDialogParams { + credentialId: string; +} + +@Component({ + templateUrl: "delete-credential-dialog.component.html", +}) +export class DeleteCredentialDialogComponent implements OnInit, OnDestroy { + private destroy$ = new Subject(); + + protected formGroup = this.formBuilder.group({ + masterPassword: ["", [Validators.required]], + }); + protected credential?: WebauthnCredentialView; + + constructor( + @Inject(DIALOG_DATA) private params: DeleteCredentialDialogParams, + private formBuilder: FormBuilder, + private dialogRef: DialogRef, + private webauthnService: WebauthnLoginService, + private platformUtilsService: PlatformUtilsService, + private i18nService: I18nService, + private logService: LogService + ) {} + + ngOnInit(): void { + this.webauthnService + .getCredential$(this.params.credentialId) + .pipe(takeUntil(this.destroy$)) + .subscribe((credential) => (this.credential = credential)); + } + + submit = async () => { + if (this.credential === undefined) { + return; + } + + this.dialogRef.disableClose = true; + try { + await this.webauthnService.deleteCredential(this.credential.id, { + type: VerificationType.MasterPassword, + secret: this.formGroup.value.masterPassword, + }); + this.platformUtilsService.showToast("success", null, this.i18nService.t("passkeyRemoved")); + } catch (error) { + if (error instanceof ErrorResponse && error.statusCode === 400) { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("error"), + this.i18nService.t("invalidMasterPassword") + ); + } else { + this.logService.error(error); + this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError")); + } + return false; + } finally { + this.dialogRef.disableClose = false; + } + + this.dialogRef.close(); + }; + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} + +/** + * Strongly typed helper to open a DeleteCredentialDialogComponent + * @param dialogService Instance of the dialog service that will be used to open the dialog + * @param config Configuration for the dialog + */ +export const openDeleteCredentialDialogComponent = ( + dialogService: DialogService, + config: DialogConfig +) => { + return dialogService.open(DeleteCredentialDialogComponent, config); +}; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/index.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/index.ts new file mode 100644 index 00000000000..87356770952 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/index.ts @@ -0,0 +1 @@ +export * from "./webauthn-login-settings.module"; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html new file mode 100644 index 00000000000..23abe02665c --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html @@ -0,0 +1,71 @@ +

+ {{ "loginWithPasskey" | i18n }} + + {{ + "on" | i18n + }} + {{ + "off" | i18n + }} + + + + +

+

+ {{ "loginWithPasskeyInfo" | i18n }} + {{ + "learnMoreAboutPasswordless" | i18n + }} +

+ + + + + + + +
{{ credential.name }} + + + {{ "supportsEncryption" | i18n }} + + + {{ "encryptionNotSupported" | i18n }} + + + +
+ +

{{ "passkeyLimitReachedInfo" | i18n }}

+ + + + + + diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.ts new file mode 100644 index 00000000000..98aa517b98e --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.ts @@ -0,0 +1,72 @@ +import { Component, HostBinding, OnDestroy, OnInit } from "@angular/core"; +import { Subject, takeUntil } from "rxjs"; + +import { DialogService } from "@bitwarden/components"; + +import { WebauthnLoginService } from "../../core"; +import { WebauthnCredentialView } from "../../core/views/webauth-credential.view"; + +import { openCreateCredentialDialog } from "./create-credential-dialog/create-credential-dialog.component"; +import { openDeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component"; + +@Component({ + selector: "app-webauthn-login-settings", + templateUrl: "webauthn-login-settings.component.html", + host: { + "aria-live": "polite", + }, +}) +export class WebauthnLoginSettingsComponent implements OnInit, OnDestroy { + private destroy$ = new Subject(); + + protected readonly MaxCredentialCount = 5; + + protected credentials?: WebauthnCredentialView[]; + protected loading = true; + + constructor( + private webauthnService: WebauthnLoginService, + private dialogService: DialogService + ) {} + + @HostBinding("attr.aria-busy") + get ariaBusy() { + return this.loading ? "true" : "false"; + } + + get hasCredentials() { + return this.credentials && this.credentials.length > 0; + } + + get hasData() { + return this.credentials !== undefined; + } + + get limitReached() { + return this.credentials?.length >= this.MaxCredentialCount; + } + + ngOnInit(): void { + this.webauthnService + .getCredentials$() + .pipe(takeUntil(this.destroy$)) + .subscribe((credentials) => (this.credentials = credentials)); + + this.webauthnService.loading$ + .pipe(takeUntil(this.destroy$)) + .subscribe((loading) => (this.loading = loading)); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + protected createCredential() { + openCreateCredentialDialog(this.dialogService, {}); + } + + protected deleteCredential(credentialId: string) { + openDeleteCredentialDialogComponent(this.dialogService, { data: { credentialId } }); + } +} diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.module.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.module.ts new file mode 100644 index 00000000000..73e21387ec6 --- /dev/null +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from "@angular/core"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; + +import { SharedModule } from "../../../shared/shared.module"; + +import { CreateCredentialDialogComponent } from "./create-credential-dialog/create-credential-dialog.component"; +import { DeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component"; +import { WebauthnLoginSettingsComponent } from "./webauthn-login-settings.component"; + +@NgModule({ + imports: [SharedModule, FormsModule, ReactiveFormsModule], + declarations: [ + WebauthnLoginSettingsComponent, + CreateCredentialDialogComponent, + DeleteCredentialDialogComponent, + ], + exports: [WebauthnLoginSettingsComponent], +}) +export class WebauthnLoginSettingsModule {} diff --git a/apps/web/src/app/oss.module.ts b/apps/web/src/app/oss.module.ts index e1e57302f4b..a68b681dca3 100644 --- a/apps/web/src/app/oss.module.ts +++ b/apps/web/src/app/oss.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { OrganizationUserModule } from "./admin-console/organizations/users/organization-user.module"; +import { AuthModule } from "./auth"; import { LoginModule } from "./auth/login/login.module"; import { TrialInitiationModule } from "./auth/trial-initiation/trial-initiation.module"; import { LooseComponentsModule, SharedModule } from "./shared"; @@ -16,6 +17,7 @@ import { VaultFilterModule } from "./vault/individual-vault/vault-filter/vault-f OrganizationBadgeModule, OrganizationUserModule, LoginModule, + AuthModule, ], exports: [ SharedModule, diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index 6efaf3653da..f55cf72551c 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -25,7 +25,6 @@ import { RecoverTwoFactorComponent } from "../auth/recover-two-factor.component" import { RegisterFormModule } from "../auth/register-form/register-form.module"; import { RemovePasswordComponent } from "../auth/remove-password.component"; import { SetPasswordComponent } from "../auth/set-password.component"; -import { ChangePasswordComponent } from "../auth/settings/change-password.component"; import { DeauthorizeSessionsComponent } from "../auth/settings/deauthorize-sessions.component"; import { EmergencyAccessAddEditComponent } from "../auth/settings/emergency-access/emergency-access-add-edit.component"; import { EmergencyAccessAttachmentsComponent } from "../auth/settings/emergency-access/emergency-access-attachments.component"; @@ -119,7 +118,6 @@ import { SharedModule } from "./shared.module"; ApiKeyComponent, AttachmentsComponent, ChangeEmailComponent, - ChangePasswordComponent, CollectionsComponent, DeauthorizeSessionsComponent, DeleteAccountComponent, @@ -204,7 +202,6 @@ import { SharedModule } from "./shared.module"; ApiKeyComponent, AttachmentsComponent, ChangeEmailComponent, - ChangePasswordComponent, CollectionsComponent, DeauthorizeSessionsComponent, DeleteAccountComponent, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 651325bad6f..b9d613877f2 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 9ca25ab2879..cc0873351b8 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -2,6 +2,7 @@ export enum FeatureFlag { DisplayEuEnvironmentFlag = "display-eu-environment", DisplayLowKdfIterationWarningFlag = "display-kdf-iteration-warning", TrustedDeviceEncryption = "trusted-device-encryption", + PasswordlessLogin = "passwordless-login", AutofillV2 = "autofill-v2", BrowserFilelessImport = "browser-fileless-import", } diff --git a/libs/components/src/dialog/directives/dialog-close.directive.ts b/libs/components/src/dialog/directives/dialog-close.directive.ts index 543c37715dd..5e44ced7c21 100644 --- a/libs/components/src/dialog/directives/dialog-close.directive.ts +++ b/libs/components/src/dialog/directives/dialog-close.directive.ts @@ -1,5 +1,5 @@ import { DialogRef } from "@angular/cdk/dialog"; -import { Directive, HostListener, Input, Optional } from "@angular/core"; +import { Directive, HostBinding, HostListener, Input, Optional } from "@angular/core"; @Directive({ selector: "[bitDialogClose]", @@ -9,7 +9,17 @@ export class DialogCloseDirective { constructor(@Optional() public dialogRef: DialogRef) {} - @HostListener("click") close(): void { + @HostBinding("attr.disabled") + get disableClose() { + return this.dialogRef?.disableClose ? true : null; + } + + @HostListener("click") + close(): void { + if (this.disableClose) { + return; + } + this.dialogRef.close(this.dialogResult); } } From ad867150a09d2de81f78f77bb748421b8233ace9 Mon Sep 17 00:00:00 2001 From: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Date: Tue, 10 Oct 2023 12:35:18 -0400 Subject: [PATCH 13/33] {SM-847] Updated Delete service account modal to be default size, not small (#6405) * Updated Delete service account modal to be default size, not small * updating project-delte-dialog and service-account-dialog to use default size dialog * updating to default size --- .../projects/dialog/project-delete-dialog.component.html | 2 +- .../projects/dialog/project-dialog.component.html | 2 +- .../dialog/service-account-delete-dialog.component.html | 2 +- .../dialog/service-account-dialog.component.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-delete-dialog.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-delete-dialog.component.html index 0a9239a10a0..a8b3866dc17 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-delete-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-delete-dialog.component.html @@ -1,5 +1,5 @@
- + {{ title | i18n }} diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.html index b56f7d45121..912fa8802b1 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.html @@ -1,5 +1,5 @@ - + {{ title | i18n }}
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-delete-dialog.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-delete-dialog.component.html index 048248531d1..9af34837037 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-delete-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-delete-dialog.component.html @@ -1,5 +1,5 @@ - + {{ title }} diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.html index 5f7260025cf..55f6ff4da14 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.html @@ -1,5 +1,5 @@ - + {{ title | i18n }}
From 3e720c05f21a68e78fab196c9fec08d1374c1fdc Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:12:13 +0200 Subject: [PATCH 14/33] [PM-4198][TechDebt] Split up import and export modules (#6483) * Split up import/export into separate modules * Fix routing and apply PR feedback * Renamed OrganizationExport exports to OrganizationVaultExport * Renamed filenames according to export rename --------- Co-authored-by: Daniel James Smith --- .../organization-settings-routing.module.ts | 18 ++++++++++--- .../org-import-routing.module.ts} | 16 +++--------- .../org-import.component.ts | 4 +-- .../org-import.module.ts} | 9 +++---- .../org-vault-export-routing.module.ts | 25 +++++++++++++++++++ .../org-vault-export.component.ts} | 6 ++--- .../vault-export/org-vault-export.module.ts | 12 +++++++++ apps/web/src/app/oss-routing.module.ts | 10 +++++--- .../file-password-prompt.component.html | 0 .../dialog/file-password-prompt.component.ts | 0 .../dialog/import-error-dialog.component.html | 0 .../dialog/import-error-dialog.component.ts | 0 .../import-success-dialog.component.html | 0 .../dialog/import-success-dialog.component.ts | 0 .../{import-export => import}/dialog/index.ts | 0 .../app/tools/import/import-routing.module.ts | 17 +++++++++++++ .../import.component.html | 0 .../import.component.ts | 0 .../import.module.ts} | 8 +++--- .../export-routing.module.ts} | 10 ++------ .../export.component.html | 0 .../export.component.ts | 0 .../app/tools/vault-export/export.module.ts | 12 +++++++++ 23 files changed, 103 insertions(+), 44 deletions(-) rename apps/web/src/app/admin-console/organizations/tools/{import-export/org-import-export-routing.module.ts => import/org-import-routing.module.ts} (53%) rename apps/web/src/app/admin-console/organizations/tools/{import-export => import}/org-import.component.ts (95%) rename apps/web/src/app/admin-console/organizations/tools/{import-export/org-import-export.module.ts => import/org-import.module.ts} (81%) create mode 100644 apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts rename apps/web/src/app/admin-console/organizations/tools/{import-export/org-export.component.ts => vault-export/org-vault-export.component.ts} (92%) create mode 100644 apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts rename apps/web/src/app/tools/{import-export => import}/dialog/file-password-prompt.component.html (100%) rename apps/web/src/app/tools/{import-export => import}/dialog/file-password-prompt.component.ts (100%) rename apps/web/src/app/tools/{import-export => import}/dialog/import-error-dialog.component.html (100%) rename apps/web/src/app/tools/{import-export => import}/dialog/import-error-dialog.component.ts (100%) rename apps/web/src/app/tools/{import-export => import}/dialog/import-success-dialog.component.html (100%) rename apps/web/src/app/tools/{import-export => import}/dialog/import-success-dialog.component.ts (100%) rename apps/web/src/app/tools/{import-export => import}/dialog/index.ts (100%) create mode 100644 apps/web/src/app/tools/import/import-routing.module.ts rename apps/web/src/app/tools/{import-export => import}/import.component.html (100%) rename apps/web/src/app/tools/{import-export => import}/import.component.ts (100%) rename apps/web/src/app/tools/{import-export/import-export.module.ts => import/import.module.ts} (85%) rename apps/web/src/app/tools/{import-export/import-export-routing.module.ts => vault-export/export-routing.module.ts} (60%) rename apps/web/src/app/tools/{import-export => vault-export}/export.component.html (100%) rename apps/web/src/app/tools/{import-export => vault-export}/export.component.ts (100%) create mode 100644 apps/web/src/app/tools/vault-export/export.module.ts diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts index 7feda23f5cf..1606d86497c 100644 --- a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts @@ -45,10 +45,20 @@ const routes: Routes = [ }, { path: "tools", - loadChildren: () => - import("../tools/import-export/org-import-export.module").then( - (m) => m.OrganizationImportExportModule - ), + children: [ + { + path: "import", + loadChildren: () => + import("../tools/import/org-import.module").then((m) => m.OrganizationImportModule), + }, + { + path: "export", + loadChildren: () => + import("../tools/vault-export/org-vault-export.module").then( + (m) => m.OrganizationVaultExportModule + ), + }, + ], }, ], }, diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export-routing.module.ts b/apps/web/src/app/admin-console/organizations/tools/import/org-import-routing.module.ts similarity index 53% rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export-routing.module.ts rename to apps/web/src/app/admin-console/organizations/tools/import/org-import-routing.module.ts index c0430ab2e07..9b4b4b5c787 100644 --- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/tools/import/org-import-routing.module.ts @@ -3,14 +3,13 @@ import { RouterModule, Routes } from "@angular/router"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { OrganizationPermissionsGuard } from "../../../../admin-console/organizations/guards/org-permissions.guard"; +import { OrganizationPermissionsGuard } from "../../guards/org-permissions.guard"; -import { OrganizationExportComponent } from "./org-export.component"; import { OrganizationImportComponent } from "./org-import.component"; const routes: Routes = [ { - path: "import", + path: "", component: OrganizationImportComponent, canActivate: [OrganizationPermissionsGuard], data: { @@ -18,18 +17,9 @@ const routes: Routes = [ organizationPermissions: (org: Organization) => org.canAccessImportExport, }, }, - { - path: "export", - component: OrganizationExportComponent, - canActivate: [OrganizationPermissionsGuard], - data: { - titleId: "exportVault", - organizationPermissions: (org: Organization) => org.canAccessImportExport, - }, - }, ]; @NgModule({ imports: [RouterModule.forChild(routes)], }) -export class OrganizationImportExportRoutingModule {} +export class OrganizationImportRoutingModule {} diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import.component.ts b/apps/web/src/app/admin-console/organizations/tools/import/org-import.component.ts similarity index 95% rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-import.component.ts rename to apps/web/src/app/admin-console/organizations/tools/import/org-import.component.ts index e8dad8baf41..b514f2bcf38 100644 --- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/import/org-import.component.ts @@ -18,11 +18,11 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv import { DialogService } from "@bitwarden/components"; import { ImportServiceAbstraction } from "@bitwarden/importer"; -import { ImportComponent } from "../../../../tools/import-export/import.component"; +import { ImportComponent } from "../../../../tools/import/import.component"; @Component({ selector: "app-org-import", - templateUrl: "../../../../tools/import-export/import.component.html", + templateUrl: "../../../../tools/import/import.component.html", }) // eslint-disable-next-line rxjs-angular/prefer-takeuntil export class OrganizationImportComponent extends ImportComponent { diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export.module.ts b/apps/web/src/app/admin-console/organizations/tools/import/org-import.module.ts similarity index 81% rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export.module.ts rename to apps/web/src/app/admin-console/organizations/tools/import/org-import.module.ts index e40e961ac98..66a22158e20 100644 --- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export.module.ts +++ b/apps/web/src/app/admin-console/organizations/tools/import/org-import.module.ts @@ -15,13 +15,12 @@ import { import { LooseComponentsModule, SharedModule } from "../../../../shared"; -import { OrganizationExportComponent } from "./org-export.component"; -import { OrganizationImportExportRoutingModule } from "./org-import-export-routing.module"; +import { OrganizationImportRoutingModule } from "./org-import-routing.module"; import { OrganizationImportComponent } from "./org-import.component"; @NgModule({ - imports: [SharedModule, LooseComponentsModule, OrganizationImportExportRoutingModule], - declarations: [OrganizationImportComponent, OrganizationExportComponent], + imports: [SharedModule, LooseComponentsModule, OrganizationImportRoutingModule], + declarations: [OrganizationImportComponent], providers: [ { provide: ImportApiServiceAbstraction, @@ -42,4 +41,4 @@ import { OrganizationImportComponent } from "./org-import.component"; }, ], }) -export class OrganizationImportExportModule {} +export class OrganizationImportModule {} diff --git a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts new file mode 100644 index 00000000000..e3e809a550d --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; + +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; + +import { OrganizationPermissionsGuard } from "../../guards/org-permissions.guard"; + +import { OrganizationVaultExportComponent } from "./org-vault-export.component"; + +const routes: Routes = [ + { + path: "", + component: OrganizationVaultExportComponent, + canActivate: [OrganizationPermissionsGuard], + data: { + titleId: "exportVault", + organizationPermissions: (org: Organization) => org.canAccessImportExport, + }, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], +}) +export class OrganizationVaultExportRoutingModule {} diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts similarity index 92% rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts rename to apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts index 9ea1442fd13..ae91150f608 100644 --- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts @@ -14,14 +14,14 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { DialogService } from "@bitwarden/components"; import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export"; -import { ExportComponent } from "../../../../tools/import-export/export.component"; +import { ExportComponent } from "../../../../tools/vault-export/export.component"; @Component({ selector: "app-org-export", - templateUrl: "../../../../tools/import-export/export.component.html", + templateUrl: "../../../../tools/vault-export/export.component.html", }) // eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class OrganizationExportComponent extends ExportComponent { +export class OrganizationVaultExportComponent extends ExportComponent { constructor( cryptoService: CryptoService, i18nService: I18nService, diff --git a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts new file mode 100644 index 00000000000..34b4fa4adba --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; + +import { LooseComponentsModule, SharedModule } from "../../../../shared"; + +import { OrganizationVaultExportRoutingModule } from "./org-vault-export-routing.module"; +import { OrganizationVaultExportComponent } from "./org-vault-export.component"; + +@NgModule({ + imports: [SharedModule, LooseComponentsModule, OrganizationVaultExportRoutingModule], + declarations: [OrganizationVaultExportComponent], +}) +export class OrganizationVaultExportModule {} diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 58d3f60134e..d8a57cd3fb3 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -254,11 +254,13 @@ const routes: Routes = [ children: [ { path: "", pathMatch: "full", redirectTo: "generator" }, { - path: "", + path: "import", + loadChildren: () => import("./tools/import/import.module").then((m) => m.ImportModule), + }, + { + path: "export", loadChildren: () => - import("./tools/import-export/import-export.module").then( - (m) => m.ImportExportModule - ), + import("./tools/vault-export/export.module").then((m) => m.ExportModule), }, { path: "generator", diff --git a/apps/web/src/app/tools/import-export/dialog/file-password-prompt.component.html b/apps/web/src/app/tools/import/dialog/file-password-prompt.component.html similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/file-password-prompt.component.html rename to apps/web/src/app/tools/import/dialog/file-password-prompt.component.html diff --git a/apps/web/src/app/tools/import-export/dialog/file-password-prompt.component.ts b/apps/web/src/app/tools/import/dialog/file-password-prompt.component.ts similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/file-password-prompt.component.ts rename to apps/web/src/app/tools/import/dialog/file-password-prompt.component.ts diff --git a/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html b/apps/web/src/app/tools/import/dialog/import-error-dialog.component.html similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.html rename to apps/web/src/app/tools/import/dialog/import-error-dialog.component.html diff --git a/apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts b/apps/web/src/app/tools/import/dialog/import-error-dialog.component.ts similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/import-error-dialog.component.ts rename to apps/web/src/app/tools/import/dialog/import-error-dialog.component.ts diff --git a/apps/web/src/app/tools/import-export/dialog/import-success-dialog.component.html b/apps/web/src/app/tools/import/dialog/import-success-dialog.component.html similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/import-success-dialog.component.html rename to apps/web/src/app/tools/import/dialog/import-success-dialog.component.html diff --git a/apps/web/src/app/tools/import-export/dialog/import-success-dialog.component.ts b/apps/web/src/app/tools/import/dialog/import-success-dialog.component.ts similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/import-success-dialog.component.ts rename to apps/web/src/app/tools/import/dialog/import-success-dialog.component.ts diff --git a/apps/web/src/app/tools/import-export/dialog/index.ts b/apps/web/src/app/tools/import/dialog/index.ts similarity index 100% rename from apps/web/src/app/tools/import-export/dialog/index.ts rename to apps/web/src/app/tools/import/dialog/index.ts diff --git a/apps/web/src/app/tools/import/import-routing.module.ts b/apps/web/src/app/tools/import/import-routing.module.ts new file mode 100644 index 00000000000..82d0a733846 --- /dev/null +++ b/apps/web/src/app/tools/import/import-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; + +import { ImportComponent } from "./import.component"; + +const routes: Routes = [ + { + path: "", + component: ImportComponent, + data: { titleId: "importData" }, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], +}) +export class ImportRoutingModule {} diff --git a/apps/web/src/app/tools/import-export/import.component.html b/apps/web/src/app/tools/import/import.component.html similarity index 100% rename from apps/web/src/app/tools/import-export/import.component.html rename to apps/web/src/app/tools/import/import.component.html diff --git a/apps/web/src/app/tools/import-export/import.component.ts b/apps/web/src/app/tools/import/import.component.ts similarity index 100% rename from apps/web/src/app/tools/import-export/import.component.ts rename to apps/web/src/app/tools/import/import.component.ts diff --git a/apps/web/src/app/tools/import-export/import-export.module.ts b/apps/web/src/app/tools/import/import.module.ts similarity index 85% rename from apps/web/src/app/tools/import-export/import-export.module.ts rename to apps/web/src/app/tools/import/import.module.ts index d180417cdcc..34f71cfab7f 100644 --- a/apps/web/src/app/tools/import-export/import-export.module.ts +++ b/apps/web/src/app/tools/import/import.module.ts @@ -20,15 +20,13 @@ import { ImportSuccessDialogComponent, FilePasswordPromptComponent, } from "./dialog"; -import { ExportComponent } from "./export.component"; -import { ImportExportRoutingModule } from "./import-export-routing.module"; +import { ImportRoutingModule } from "./import-routing.module"; import { ImportComponent } from "./import.component"; @NgModule({ - imports: [SharedModule, LooseComponentsModule, ImportExportRoutingModule], + imports: [SharedModule, LooseComponentsModule, ImportRoutingModule], declarations: [ ImportComponent, - ExportComponent, FilePasswordPromptComponent, ImportErrorDialogComponent, ImportSuccessDialogComponent, @@ -53,4 +51,4 @@ import { ImportComponent } from "./import.component"; }, ], }) -export class ImportExportModule {} +export class ImportModule {} diff --git a/apps/web/src/app/tools/import-export/import-export-routing.module.ts b/apps/web/src/app/tools/vault-export/export-routing.module.ts similarity index 60% rename from apps/web/src/app/tools/import-export/import-export-routing.module.ts rename to apps/web/src/app/tools/vault-export/export-routing.module.ts index 101e149d7f8..3afda4a06f2 100644 --- a/apps/web/src/app/tools/import-export/import-export-routing.module.ts +++ b/apps/web/src/app/tools/vault-export/export-routing.module.ts @@ -2,16 +2,10 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { ExportComponent } from "./export.component"; -import { ImportComponent } from "./import.component"; const routes: Routes = [ { - path: "import", - component: ImportComponent, - data: { titleId: "importData" }, - }, - { - path: "export", + path: "", component: ExportComponent, data: { titleId: "exportVault" }, }, @@ -20,4 +14,4 @@ const routes: Routes = [ @NgModule({ imports: [RouterModule.forChild(routes)], }) -export class ImportExportRoutingModule {} +export class ExportRoutingModule {} diff --git a/apps/web/src/app/tools/import-export/export.component.html b/apps/web/src/app/tools/vault-export/export.component.html similarity index 100% rename from apps/web/src/app/tools/import-export/export.component.html rename to apps/web/src/app/tools/vault-export/export.component.html diff --git a/apps/web/src/app/tools/import-export/export.component.ts b/apps/web/src/app/tools/vault-export/export.component.ts similarity index 100% rename from apps/web/src/app/tools/import-export/export.component.ts rename to apps/web/src/app/tools/vault-export/export.component.ts diff --git a/apps/web/src/app/tools/vault-export/export.module.ts b/apps/web/src/app/tools/vault-export/export.module.ts new file mode 100644 index 00000000000..aca8bdbd4ec --- /dev/null +++ b/apps/web/src/app/tools/vault-export/export.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; + +import { LooseComponentsModule, SharedModule } from "../../shared"; + +import { ExportRoutingModule } from "./export-routing.module"; +import { ExportComponent } from "./export.component"; + +@NgModule({ + imports: [SharedModule, LooseComponentsModule, ExportRoutingModule], + declarations: [ExportComponent], +}) +export class ExportModule {} From 524123ac01346936445935c78f72253836d4e59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Tue, 10 Oct 2023 19:13:50 +0200 Subject: [PATCH 15/33] Add lint to try to limit reappearance of Safari memory leaks (#6382) --- .eslintrc.json | 17 +++++++++++++++++ .../browser/src/platform/browser/browser-api.ts | 2 ++ 2 files changed, 19 insertions(+) diff --git a/.eslintrc.json b/.eslintrc.json index d6c329a94dc..44b4e09adf2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -179,6 +179,23 @@ "rules": { "no-restricted-imports": ["error", { "patterns": ["@bitwarden/vault/*", "src/**/*"] }] } + }, + { + "files": ["apps/browser/src/**/*.ts", "libs/**/*.ts"], + "excludedFiles": "apps/browser/src/autofill/{content,notification}/**/*.ts", + "rules": { + "no-restricted-syntax": [ + "error", + { + "message": "Using addListener in the browser popup produces a memory leak in Safari, use `BrowserApi.messageListener` instead", + "selector": "CallExpression > [object.object.object.name='chrome'][object.object.property.name='runtime'][object.property.name='onMessage'][property.name='addListener']" + }, + { + "message": "Using addListener in the browser popup produces a memory leak in Safari, use `BrowserApi.storageChangeListener` instead", + "selector": "CallExpression > [object.object.object.name='chrome'][object.object.property.name='storage'][object.property.name='onChanged'][property.name='addListener']" + } + ] + } } ] } diff --git a/apps/browser/src/platform/browser/browser-api.ts b/apps/browser/src/platform/browser/browser-api.ts index b71b8b80b6c..5d0c2f1a519 100644 --- a/apps/browser/src/platform/browser/browser-api.ts +++ b/apps/browser/src/platform/browser/browser-api.ts @@ -208,6 +208,7 @@ export class BrowserApi { name: string, callback: (message: any, sender: chrome.runtime.MessageSender, response: any) => void ) { + // eslint-disable-next-line no-restricted-syntax chrome.runtime.onMessage.addListener(callback); if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) { @@ -219,6 +220,7 @@ export class BrowserApi { static storageChangeListener( callback: Parameters[0] ) { + // eslint-disable-next-line no-restricted-syntax chrome.storage.onChanged.addListener(callback); if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) { From 56a122980351e2baf49b55002fd020b98c163a32 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Wed, 11 Oct 2023 16:09:01 +0200 Subject: [PATCH 16/33] [PM-4016] Address feedback on [PM-2014] (#6532) * [PM-4016] feat: use dialog `loading` attribute * [PM-4016] chore: move constant to service * [PM-4016] chore: simplify paddings * [PM-4016] chore: rename to `AuthSettingsModule` * [PM-4016] fix: move request creation to service * [PM-4016] feat: simplify module structure Remove core.module and use `@Injectable({ providedIn: "root" })` instead. --- apps/web/src/app/auth/auth.module.ts | 7 +++---- apps/web/src/app/auth/core/core.module.ts | 15 --------------- apps/web/src/app/auth/core/index.ts | 1 - .../webauthn-login/webauthn-login-api.service.ts | 16 +++++----------- .../webauthn-login.service.spec.ts | 6 +++++- .../webauthn-login/webauthn-login.service.ts | 12 +++++++++--- .../web/src/app/auth/settings/settings.module.ts | 4 ++-- .../create-credential-dialog.component.html | 2 +- .../create-credential-dialog.component.ts | 1 + .../delete-credential-dialog.component.html | 2 +- .../delete-credential-dialog.component.ts | 1 + .../webauthn-login-settings.component.html | 4 ++-- .../webauthn-login-settings.component.ts | 2 +- 13 files changed, 31 insertions(+), 42 deletions(-) delete mode 100644 apps/web/src/app/auth/core/core.module.ts diff --git a/apps/web/src/app/auth/auth.module.ts b/apps/web/src/app/auth/auth.module.ts index 49be17aa264..056b9f161f9 100644 --- a/apps/web/src/app/auth/auth.module.ts +++ b/apps/web/src/app/auth/auth.module.ts @@ -1,12 +1,11 @@ import { NgModule } from "@angular/core"; -import { CoreAuthModule } from "./core"; -import { SettingsModule } from "./settings/settings.module"; +import { AuthSettingsModule } from "./settings/settings.module"; @NgModule({ - imports: [CoreAuthModule, SettingsModule], + imports: [AuthSettingsModule], declarations: [], providers: [], - exports: [SettingsModule], + exports: [AuthSettingsModule], }) export class AuthModule {} diff --git a/apps/web/src/app/auth/core/core.module.ts b/apps/web/src/app/auth/core/core.module.ts deleted file mode 100644 index e196b1c3d76..00000000000 --- a/apps/web/src/app/auth/core/core.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NgModule, Optional, SkipSelf } from "@angular/core"; - -import { WebauthnLoginApiService } from "./services/webauthn-login/webauthn-login-api.service"; -import { WebauthnLoginService } from "./services/webauthn-login/webauthn-login.service"; - -@NgModule({ - providers: [WebauthnLoginService, WebauthnLoginApiService], -}) -export class CoreAuthModule { - constructor(@Optional() @SkipSelf() parentModule?: CoreAuthModule) { - if (parentModule) { - throw new Error("CoreAuthModule is already loaded. Import it in AuthModule only"); - } - } -} diff --git a/apps/web/src/app/auth/core/index.ts b/apps/web/src/app/auth/core/index.ts index 3d2d739adf9..b2221a94a89 100644 --- a/apps/web/src/app/auth/core/index.ts +++ b/apps/web/src/app/auth/core/index.ts @@ -1,2 +1 @@ export * from "./services"; -export * from "./core.module"; diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts index 33e1aea369b..6dc61563491 100644 --- a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts @@ -1,25 +1,20 @@ import { Injectable } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; -import { Verification } from "@bitwarden/common/types/verification"; import { SaveCredentialRequest } from "./request/save-credential.request"; import { WebauthnLoginCredentialCreateOptionsResponse } from "./response/webauthn-login-credential-create-options.response"; import { WebauthnLoginCredentialResponse } from "./response/webauthn-login-credential.response"; -@Injectable() +@Injectable({ providedIn: "root" }) export class WebauthnLoginApiService { - constructor( - private apiService: ApiService, - private userVerificationService: UserVerificationService - ) {} + constructor(private apiService: ApiService) {} async getCredentialCreateOptions( - verification: Verification + request: SecretVerificationRequest ): Promise { - const request = await this.userVerificationService.buildRequest(verification); const response = await this.apiService.send("POST", "/webauthn/options", request, true, true); return new WebauthnLoginCredentialCreateOptionsResponse(response); } @@ -33,8 +28,7 @@ export class WebauthnLoginApiService { return this.apiService.send("GET", "/webauthn", null, true, true); } - async deleteCredential(credentialId: string, verification: Verification): Promise { - const request = await this.userVerificationService.buildRequest(verification); + async deleteCredential(credentialId: string, request: SecretVerificationRequest): Promise { await this.apiService.send("POST", `/webauthn/${credentialId}/delete`, request, true, true); } } diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts index 070513f19e8..1e4f1fa7717 100644 --- a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts @@ -1,5 +1,7 @@ import { mock, MockProxy } from "jest-mock-extended"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; + import { CredentialCreateOptionsView } from "../../views/credential-create-options.view"; import { WebauthnLoginApiService } from "./webauthn-login-api.service"; @@ -7,6 +9,7 @@ import { WebauthnLoginService } from "./webauthn-login.service"; describe("WebauthnService", () => { let apiService!: MockProxy; + let userVerificationService!: MockProxy; let credentials: MockProxy; let webauthnService!: WebauthnLoginService; @@ -15,8 +18,9 @@ describe("WebauthnService", () => { window.PublicKeyCredential = class {} as any; window.AuthenticatorAttestationResponse = class {} as any; apiService = mock(); + userVerificationService = mock(); credentials = mock(); - webauthnService = new WebauthnLoginService(apiService, credentials); + webauthnService = new WebauthnLoginService(apiService, userVerificationService, credentials); }); describe("createCredential", () => { diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts index 760214961a7..c5979f08c61 100644 --- a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts @@ -1,6 +1,7 @@ import { Injectable, Optional } from "@angular/core"; import { BehaviorSubject, filter, from, map, Observable, shareReplay, switchMap, tap } from "rxjs"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Verification } from "@bitwarden/common/types/verification"; @@ -11,8 +12,10 @@ import { SaveCredentialRequest } from "./request/save-credential.request"; import { WebauthnLoginAttestationResponseRequest } from "./request/webauthn-login-attestation-response.request"; import { WebauthnLoginApiService } from "./webauthn-login-api.service"; -@Injectable() +@Injectable({ providedIn: "root" }) export class WebauthnLoginService { + static readonly MaxCredentialCount = 5; + private navigatorCredentials: CredentialsContainer; private _refresh$ = new BehaviorSubject(undefined); private _loading$ = new BehaviorSubject(true); @@ -27,6 +30,7 @@ export class WebauthnLoginService { constructor( private apiService: WebauthnLoginApiService, + private userVerificationService: UserVerificationService, @Optional() navigatorCredentials?: CredentialsContainer, @Optional() private logService?: LogService ) { @@ -37,7 +41,8 @@ export class WebauthnLoginService { async getCredentialCreateOptions( verification: Verification ): Promise { - const response = await this.apiService.getCredentialCreateOptions(verification); + const request = await this.userVerificationService.buildRequest(verification); + const response = await this.apiService.getCredentialCreateOptions(request); return new CredentialCreateOptionsView(response.options, response.token); } @@ -95,7 +100,8 @@ export class WebauthnLoginService { } async deleteCredential(credentialId: string, verification: Verification): Promise { - await this.apiService.deleteCredential(credentialId, verification); + const request = await this.userVerificationService.buildRequest(verification); + await this.apiService.deleteCredential(credentialId, request); this.refresh(); } diff --git a/apps/web/src/app/auth/settings/settings.module.ts b/apps/web/src/app/auth/settings/settings.module.ts index 282524d07e4..12ae6bcbf5e 100644 --- a/apps/web/src/app/auth/settings/settings.module.ts +++ b/apps/web/src/app/auth/settings/settings.module.ts @@ -11,6 +11,6 @@ import { WebauthnLoginSettingsModule } from "./webauthn-login-settings"; imports: [SharedModule, WebauthnLoginSettingsModule, PasswordCalloutComponent], declarations: [ChangePasswordComponent], providers: [], - exports: [WebauthnLoginSettingsModule, ChangePasswordComponent], + exports: [ChangePasswordComponent], }) -export class SettingsModule {} +export class AuthSettingsModule {} diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html index 57a2c545ca1..aadcf5e5960 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.html @@ -1,5 +1,5 @@ - + {{ "loginWithPasskey" | i18n }} {{ "newPasskey" | i18n }} diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts index 5c93d6f25e2..12af83cac5c 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts @@ -46,6 +46,7 @@ export class CreateCredentialDialogComponent implements OnInit { protected credentialOptions?: CredentialCreateOptionsView; protected deviceResponse?: PublicKeyCredential; protected hasPasskeys$?: Observable; + protected loading$ = this.webauthnService.loading$; constructor( private formBuilder: FormBuilder, diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html index 4cfdbbcf7fe..5e87f6d4adf 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.html @@ -1,5 +1,5 @@ - + {{ "removePasskey" | i18n }} {{ diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts index 7cb03238392..9ee1337ffb2 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/delete-credential-dialog/delete-credential-dialog.component.ts @@ -27,6 +27,7 @@ export class DeleteCredentialDialogComponent implements OnInit, OnDestroy { masterPassword: ["", [Validators.required]], }); protected credential?: WebauthnCredentialView; + protected loading$ = this.webauthnService.loading$; constructor( @Inject(DIALOG_DATA) private params: DeleteCredentialDialogParams, diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html index 23abe02665c..5896d461bfb 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/webauthn-login-settings.component.html @@ -22,7 +22,7 @@

- - - + Date: Fri, 13 Oct 2023 00:56:42 +1000 Subject: [PATCH 20/33] [AC-1638] Disallow Secrets Manager for MSP-managed organizations (#6392) * Hide Add SM component on sub page for MSPs * Hide Add SM component on create org page for MSPs * Use hasProvider instead of providerType --- .../organizations/organization-plans.component.html | 2 +- .../organizations/organization-plans.component.ts | 10 +++++++--- .../organization-subscription-cloud.component.ts | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.html b/apps/web/src/app/billing/organizations/organization-plans.component.html index 06d04dc4e41..87a8ad61627 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.html +++ b/apps/web/src/app/billing/organizations/organization-plans.component.html @@ -276,7 +276,7 @@

{{ "summary" | i18n }}

Date: Thu, 12 Oct 2023 18:32:46 -0400 Subject: [PATCH 21/33] [PM-795] Fix send name missing ellipsis (#6538) * fix send name missing ellipsis * fix wrapping text on send items --- apps/desktop/src/scss/list.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/desktop/src/scss/list.scss b/apps/desktop/src/scss/list.scss index ec56eaa6c88..39e520f7d89 100644 --- a/apps/desktop/src/scss/list.scss +++ b/apps/desktop/src/scss/list.scss @@ -120,8 +120,12 @@ .item-content { display: block; + overflow-x: hidden; .item-title { display: block; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; .title-badges { @include themify($themes) { color: themed("mutedColor"); From 725acf5f7f1a620ffcf5a6094ffb8987f916e4ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 08:17:36 +0000 Subject: [PATCH 22/33] Autosync the updated translations (#6571) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/bg/messages.json | 4 ++-- apps/browser/src/_locales/fa/messages.json | 2 +- apps/browser/src/_locales/sr/messages.json | 16 ++++++++-------- apps/browser/src/_locales/sv/messages.json | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index c96fadbd422..75d86dd2b41 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -83,7 +83,7 @@ "message": "Копиране на потребителското име" }, "copyNumber": { - "message": "Копиране на номера" + "message": "Копиране на но̀мера" }, "copySecurityCode": { "message": "Копиране на кода за сигурност" @@ -257,7 +257,7 @@ "message": "Избор" }, "generatePassword": { - "message": "Генериране на парола" + "message": "Нова парола" }, "regeneratePassword": { "message": "Регенериране на паролата" diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index bcfab0cdbc8..c366c3a00b6 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -726,7 +726,7 @@ "message": "درباره سازمان‌ها اطلاعات کسب کنید" }, "learnOrgConfirmation": { - "message": "Bitwarden به شما اجازه می‌دهد با استفاده از سازماندهی، موارد گاوصندوق خود را با دیگران به اشتراک بگذارید. آیا مایل به بازدید از وب سایت bitwarden.com برای کسب اطلاعات بیشتر هستید؟" + "message": "Bitwarden به شما اجازه می‌دهد با استفاده از سازمان، موارد گاوصندوق خود را با دیگران به اشتراک بگذارید. آیا مایل به بازدید از وب سایت bitwarden.com برای کسب اطلاعات بیشتر هستید؟" }, "moveToOrganization": { "message": "انتقال به سازمان" diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index d55a5bfe197..c496e7628d9 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -92,13 +92,13 @@ "message": "Аутоматско допуњавање" }, "autoFillLogin": { - "message": "Auto-fill login" + "message": "Ауто-пуњење пријаве" }, "autoFillCard": { - "message": "Auto-fill card" + "message": "Ауто-пуњење картице" }, "autoFillIdentity": { - "message": "Auto-fill identity" + "message": "Ауто-пуњење идентитета" }, "generatePasswordCopied": { "message": "Генериши Лозинку (копирано)" @@ -110,19 +110,19 @@ "message": "Нема одговарајућих пријављивања." }, "noCards": { - "message": "No cards" + "message": "Нема карте" }, "noIdentities": { - "message": "No identities" + "message": "Нема идентитета" }, "addLoginMenu": { - "message": "Add login" + "message": "Нема пријаве" }, "addCardMenu": { - "message": "Add card" + "message": "Додати картицу" }, "addIdentityMenu": { - "message": "Add identity" + "message": "Додати идентитет" }, "unlockVaultMenu": { "message": "Откључај свој сеф" diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index ca0b8de6580..283665f4977 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -92,10 +92,10 @@ "message": "Fyll i automatiskt" }, "autoFillLogin": { - "message": "Auto-fill login" + "message": "Autofyll inloggning" }, "autoFillCard": { - "message": "Auto-fill card" + "message": "Autofyll kort" }, "autoFillIdentity": { "message": "Auto-fill identity" From b592b71df197b40935ddf343788f8386176f27a6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 08:24:02 +0000 Subject: [PATCH 23/33] Autosync the updated translations (#6570) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ar/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/az/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/be/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/bg/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/bn/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/bs/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ca/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/cs/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/cy/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/da/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/de/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/el/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/en_GB/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/en_IN/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/eo/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/es/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/et/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/eu/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/fa/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/fi/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/fil/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/fr/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/gl/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/he/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/hi/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/hr/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/hu/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/id/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/it/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ja/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ka/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/km/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/kn/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ko/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/lv/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ml/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/mr/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/my/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/nb/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ne/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/nl/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/nn/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/or/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/pl/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/pt_BR/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/pt_PT/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ro/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/ru/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/si/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/sk/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/sl/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/sr/messages.json | 90 ++++++++++++++++++++++-- apps/web/src/locales/sr_CS/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/sv/messages.json | 88 ++++++++++++++++++++++- apps/web/src/locales/te/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/th/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/tr/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/uk/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/vi/messages.json | 86 +++++++++++++++++++++- apps/web/src/locales/zh_CN/messages.json | 88 ++++++++++++++++++++++- apps/web/src/locales/zh_TW/messages.json | 86 +++++++++++++++++++++- 62 files changed, 5212 insertions(+), 128 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 8eaf6e1f011..017e170ecd3 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Teken aan met hoofwagwoord" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Skep rekening" }, @@ -5406,6 +5472,19 @@ "required": { "message": "vereis" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Maksimum $MAX$ karakters", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Aan" }, + "off": { + "message": "Off" + }, "members": { "message": "Lede" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index cd5c185c172..19971c613b7 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "تسجيل الدخول باستخدام كلمة المرور الرئيسية" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "إنشاء حساب" }, @@ -5406,6 +5472,19 @@ "required": { "message": "مطلوب" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "الأعضاء" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 1822746405e..e115c210540 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Ana parolla giriş et" }, + "loginWithPasskey": { + "message": "Parolla giriş et" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "Yeni parol" + }, + "learnMoreAboutPasswordless": { + "message": "Parolsuz haqqında daha ətraflı" + }, + "passkeyEnterMasterPassword": { + "message": "Parol ayarlarına sahib girişi dəyişdirmək üçün ana parolunuzu daxil edin." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Özəl ad" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Şifrələmə dəstəklənmir" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saxlanıldı", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Parol silindi" + }, + "removePasskey": { + "message": "Parolu sil" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Yenidən sına" + }, "createAccount": { "message": "Hesab yarat" }, @@ -5406,6 +5472,19 @@ "required": { "message": "tələb olunur" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ simvol", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "maksimum $MAX$ simvol", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Açıqdır" }, + "off": { + "message": "Bağlı" + }, "members": { "message": "Üzvlər" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "\"Secrets Manager\"ə abunə ol" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index fbefebf78a1..cbebeeacf1f 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Увайсці з асноўным паролем" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Стварыць уліковы запіс" }, @@ -5406,6 +5472,19 @@ "required": { "message": "патрабуецца" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Максімум $MAX$ сімвалаў", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Уключана" }, + "off": { + "message": "Off" + }, "members": { "message": "Удзельнікі" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Дадаць менеджар сакрэтаў" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Дадаць менеджар сакрэтаў у ваш абноўлены тарыфны план, каб падтрымліваць доступ да любых сакрэтаў, якія былі створаны з дапамогай вашых папярэдніх тарыфных планаў." diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index f6036998998..5074795c58a 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Вписване с главната парола" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Нов опит" + }, "createAccount": { "message": "Създаване на абонамент" }, @@ -5406,6 +5472,19 @@ "required": { "message": "задължително" }, + "charactersCurrentAndMaximum": { + "message": "Максимален брой знаци: $CURRENT$/$MAX$", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Максимален брой знаци: $MAX$", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Включено" }, + "off": { + "message": "Изключено" + }, "members": { "message": "Членове" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Добавяне на Управление на тайни" + "subscribeToSecretsManager": { + "message": "Абониране за Управлението на тайни" }, "addSecretsManagerUpgradeDesc": { "message": "Добавете Управление на тайни към своя надграден план, за да продължите да имате достъп до тайните създадени при предишния Ви план." diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index 25f2a837f52..c111b48b444 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "অ্যাকাউন্ট তৈরি" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 7fa48aeaa5e..c78a2207f5e 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 30ee2f589f3..96f1b5596d4 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Inici de sessió amb contrasenya mestra" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Crea un compte" }, @@ -5406,6 +5472,19 @@ "required": { "message": "requerit" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ caràcters màxim", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Activat" }, + "off": { + "message": "Off" + }, "members": { "message": "Membres" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Afig administrador de secrets" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Afegiu administrador de secrets al vostre pla actualitzat per mantindre l'accés a tots els secrets creats amb el vostre pla anterior." diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index 24e3817f615..843c805089c 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Přihlásit se pomocí hlavního hesla" }, + "loginWithPasskey": { + "message": "Přihlásit se pomocí přístupového klíče" + }, + "loginWithPasskeyInfo": { + "message": "Použijte vygenerovaný přístupový klíč, který Vás automaticky přihlásí bez hesla. Biometriky, jako je rozpoznávání obličeje, otisky prstů nebo jiná bezpečnostní metoda FIDO2 ověří Vaši totožnost." + }, + "newPasskey": { + "message": "Nové přístupový klíč" + }, + "learnMoreAboutPasswordless": { + "message": "Další informace o přihlášení bez hesla" + }, + "passkeyEnterMasterPassword": { + "message": "Zadejte Vaše hlavní heslo pro úpravu dvoufázového přihlášení." + }, + "creatingPasskeyLoading": { + "message": "Vytváření přístupového klíče..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Ponechte toto okno otevřené a postupujte podle dotazů z Vašeho prohlížeče." + }, + "errorCreatingPasskey": { + "message": "Chyba při vytváření přístupového klíče" + }, + "errorCreatingPasskeyInfo": { + "message": "Vyskytl se problém při vytváření přístupového klíče." + }, + "passkeySuccessfullyCreated": { + "message": "Přístupový klíč byl úspěšně vytvořen!" + }, + "customName": { + "message": "Vlastní název" + }, + "customPasskeyNameInfo": { + "message": "Pojmenujte Váš přístupový klíč, abyste jej mohli snáze identifikovat." + }, + "encryptionNotSupported": { + "message": "Šifrování není podporováno" + }, + "loginWithPasskeyEnabled": { + "message": "Přihlásit se se zapnutým přístupovým klíčem" + }, + "passkeySaved": { + "message": "$NAME$ uloženo", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Přístupový klíč byl odebrán" + }, + "removePasskey": { + "message": "Odebrat přístupový klíč" + }, + "removePasskeyInfo": { + "message": "Pokud budou odebrány všechny přístupové klíče, nebudete se moci přihlásit do nových zařízení bez hlavního hesla." + }, + "passkeyLimitReachedInfo": { + "message": "Byl dosažen limit přístupového klíče. Chcete-li přidat další, odeberte nějaký." + }, + "tryAgain": { + "message": "Zkusit znovu" + }, "createAccount": { "message": "Vytvořit účet" }, @@ -5406,6 +5472,19 @@ "required": { "message": "vyžadováno" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ znaků maximálně", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Maximálně $MAX$ znaků", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Zapnuto" }, + "off": { + "message": "VYP." + }, "members": { "message": "Členové" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Přidat správce tajných klíčů" + "subscribeToSecretsManager": { + "message": "Přihlásit se ke správci klíčů" }, "addSecretsManagerUpgradeDesc": { "message": "Přidáním správce klíčů k aktualizovanému plánu si zachováte přístup ke všem klíčům vytvořeným v předchozím plánu." diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 8de532e7e26..d5db4ca110e 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log ind med hovedadgangskode" }, + "loginWithPasskey": { + "message": "Log ind med adgangsnøgle" + }, + "loginWithPasskeyInfo": { + "message": "Brug en genereret adgangsnøgle, der automatisk logger dig ind uden en adgangskode. Biometri, såsom ansigtsgenkendelse eller fingeraftryk, eller en anden FIDO2-sikkerhedsmetode, vil bekræfte din identitet." + }, + "newPasskey": { + "message": "Ny adgangsnøgle" + }, + "learnMoreAboutPasswordless": { + "message": "Læs mere om adgangskodefrihed" + }, + "passkeyEnterMasterPassword": { + "message": "Angiv hovedadgangskoden for at ændre loginindstillinger for adgangsnøgle." + }, + "creatingPasskeyLoading": { + "message": "Opretter adgangsnøgle..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Hold dette vindue åbent, og følg prompterne fra webbrowseren." + }, + "errorCreatingPasskey": { + "message": "Fejl ved oprettelse af adgangsnøgle" + }, + "errorCreatingPasskeyInfo": { + "message": "Der opstod et problem med at oprette adgangsnøglen." + }, + "passkeySuccessfullyCreated": { + "message": "Adgangsnøgle hermed oprettet!" + }, + "customName": { + "message": "Tilpasset navn" + }, + "customPasskeyNameInfo": { + "message": "Navngiv adgangsnøglen for at hjælpe dig med at identificere den." + }, + "encryptionNotSupported": { + "message": "Kryptering ikke understøttet" + }, + "loginWithPasskeyEnabled": { + "message": "Log ind med adgangsnøgle slået til" + }, + "passkeySaved": { + "message": "$NAME$ gemt", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Adgangsnøgle fjernet" + }, + "removePasskey": { + "message": "Fjern adgangsnøgle" + }, + "removePasskeyInfo": { + "message": "Fjernes alle adgangsnøgler, vil du ikke kunne logge ind på nye enheder uden hovedadgangskoden." + }, + "passkeyLimitReachedInfo": { + "message": "Adgangsnøglekvote nået. Fjern en adgangsnøgle for at tilføje en anden." + }, + "tryAgain": { + "message": "Forsøg igen" + }, "createAccount": { "message": "Opret konto" }, @@ -5406,6 +5472,19 @@ "required": { "message": "obligatorisk" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ tegn maksimalt", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Maksimalt $MAX$ tegn", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Til" }, + "off": { + "message": "Fra" + }, "members": { "message": "Medlemmer" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Tilføj Secrets Manager" + "subscribeToSecretsManager": { + "message": "Abonnér på Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Føj Secrets Manager til den opgraderede abonnementstype for at bibeholde adgang til alle hemmeligheder oprettet med det tidligere abonnement." diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 09c18f83434..f988a6b988f 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Mit Master-Passwort anmelden" }, + "loginWithPasskey": { + "message": "Mit Passkey anmelden" + }, + "loginWithPasskeyInfo": { + "message": "Verwende einen generierten Passkey, der dich automatisch ohne Passwort anmeldet. Biometrische Merkmale wie Gesichtserkennung oder Fingerabdruck oder eine andere FIDO2-Sicherheitsmethode verifizieren deine Identität." + }, + "newPasskey": { + "message": "Neuer Passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Gib dein Master-Passwort ein, um die Einstellungen für die Anmeldung mit Passkeys zu ändern." + }, + "creatingPasskeyLoading": { + "message": "Passkey wird erstellt..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Behalte dieses Fenster offen und folge den Anweisungen deines Browsers." + }, + "errorCreatingPasskey": { + "message": "Fehler beim Erstellen des Passkeys." + }, + "errorCreatingPasskeyInfo": { + "message": "Es gab ein Problem beim Erstellen deines Passkeys." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey erfolgreich erstellt!" + }, + "customName": { + "message": "Benutzerdefinierter Name" + }, + "customPasskeyNameInfo": { + "message": "Benenne deinen Passkey, um ihn zu identifizieren." + }, + "encryptionNotSupported": { + "message": "Verschlüsselung nicht unterstützt" + }, + "loginWithPasskeyEnabled": { + "message": "Anmeldung mit Passkey aktiviert" + }, + "passkeySaved": { + "message": "$NAME$ gespeichert", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey gelöscht" + }, + "removePasskey": { + "message": "Passkey löschen" + }, + "removePasskeyInfo": { + "message": "Wenn alle Passkeys entfernt werden, kannst du dich ohne dein Master-Passwort nicht auf neuen Geräten anmelden." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey-Limit erreicht. Entferne einen Passkey, um ein weiteren hinzuzufügen." + }, + "tryAgain": { + "message": "Erneut versuchen" + }, "createAccount": { "message": "Konto erstellen" }, @@ -5406,6 +5472,19 @@ "required": { "message": "erforderlich" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ erlaubten Zeichen", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Maximal $MAX$ Zeichen", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Ein" }, + "off": { + "message": "Aus" + }, "members": { "message": "Mitglieder" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Secrets Manager hinzufügen" + "subscribeToSecretsManager": { + "message": "Secrets Manager abonnieren" }, "addSecretsManagerUpgradeDesc": { "message": "Füge den Secrets Manager zu deinem aktualisierten Abonnement hinzu, um den Zugriff auf alle Geheimnisse zu erhalten, die mit deinem vorherigen Abonnement erstellt wurden." diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 5004408eafa..55ebf648905 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Συνδεθείτε με τον κύριο κωδικό πρόσβασης" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Δημιουργία Λογαριασμού" }, @@ -5406,6 +5472,19 @@ "required": { "message": "απαιτείται" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index be316df1621..b91dfccd05f 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 277641ca9a0..da2447e4df4 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 77407c53c8f..d44056e11f6 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Saluti kun la ĉefpasvorto" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Krei konton" }, @@ -5406,6 +5472,19 @@ "required": { "message": "deviga" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Ŝaltita" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index 18d85d28661..0b6740ffe3c 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Iniciar sesión con contraseña maestra" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Crear cuenta" }, @@ -5406,6 +5472,19 @@ "required": { "message": "requerido" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ caracteres como máximo", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Activado" }, + "off": { + "message": "Off" + }, "members": { "message": "Miembros" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 97f5c17bf81..bcb56734b17 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Logi sisse ülemparooliga" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Konto loomine" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index 92d3823cd1e..569edfc4751 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Hasi saioa pasahitz nagusiarekin" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Sortu kontua" }, @@ -5406,6 +5472,19 @@ "required": { "message": "beharrezkoa" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Piztuta" }, + "off": { + "message": "Off" + }, "members": { "message": "Kideak" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index e564086f871..2c9af8a8dbd 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "با کلمه عبور اصلی وارد شوید" }, + "loginWithPasskey": { + "message": "با کلید عبور وارد شوید" + }, + "loginWithPasskeyInfo": { + "message": "از یک کلمه عبور ایجاد شده استفاده کنید که به طور خودکار بدون کلمه عبور شما را وارد می‌کند. بیومتریک‌ها، مانند تشخیص چهره یا اثر انگشت، یا سایر روش‌های امنیتی FIDO2 هویت شما را تأیید می‌کنند." + }, + "newPasskey": { + "message": "کلمه عبور جدید" + }, + "learnMoreAboutPasswordless": { + "message": "درباره بدون کلمه عبور بیشتر بدانید" + }, + "passkeyEnterMasterPassword": { + "message": "کلمه عبور اصلی خود را برای تغییر ورود با تنظیمات کلید عبور وارد کنید." + }, + "creatingPasskeyLoading": { + "message": "ایجاد کلید عبور..." + }, + "creatingPasskeyLoadingInfo": { + "message": "این پنجره را باز نگه دارید و دستورهای مرورگر خود را دنبال کنید." + }, + "errorCreatingPasskey": { + "message": "خطا در ایجاد کلید عبور" + }, + "errorCreatingPasskeyInfo": { + "message": "مشکلی در ایجاد کلید عبور شما وجود داشت." + }, + "passkeySuccessfullyCreated": { + "message": "کلید عبور با موفقیت ایجاد شد!" + }, + "customName": { + "message": "نام سفارشی" + }, + "customPasskeyNameInfo": { + "message": "کلید عبور خود را برای کمک به شناسایی آن نام ببرید." + }, + "encryptionNotSupported": { + "message": "رمزگذاری پشتیبانی نمی‌شود" + }, + "loginWithPasskeyEnabled": { + "message": "با فعال بودن کلید ورود وارد شوید" + }, + "passkeySaved": { + "message": "$NAME$ ذخیره شد", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "کلید عبور حذف شد" + }, + "removePasskey": { + "message": "حذف کلید عبور" + }, + "removePasskeyInfo": { + "message": "اگر همه کلیدهای عبور حذف شوند، نمی‌توانید بدون کلمه عبور اصلی خود وارد دستگاه‌های جدید شوید." + }, + "passkeyLimitReachedInfo": { + "message": "به حد مجاز کلید عبور رسیده است. برای افزودن کلید عبور دیگر، کلید عبور را حذف کنید." + }, + "tryAgain": { + "message": "دوباره امتحان کن" + }, "createAccount": { "message": "ایجاد حساب کاربری" }, @@ -5406,6 +5472,19 @@ "required": { "message": "الزامی است" }, + "charactersCurrentAndMaximum": { + "message": "حداکثر کاراکتر $CURRENT$/$MAX$", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "حداکثر کاراکتر $MAX$", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "روشن" }, + "off": { + "message": "خاموش" + }, "members": { "message": "اعضا" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "افزودن مدیر رازها" + "subscribeToSecretsManager": { + "message": "دنبال کردن مدیر اسرار" }, "addSecretsManagerUpgradeDesc": { "message": "مدیر رازها را به برنامه ارتقا یافته خود اضافه کنید تا دسترسی به رازهای ایجاد شده با برنامه قبلی خود را حفظ کنید." diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index bb2d7ae1995..01368eada3e 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Kirjaudu pääsalasanalla" }, + "loginWithPasskey": { + "message": "Kirjaudu suojausavaimella" + }, + "loginWithPasskeyInfo": { + "message": "Käytä generoitua suojausavainta, joka kirjaa sinut automaattisesti sisään ilman salasanaa. Henkilöllisyytesi vahvistetaan kasvojen tunnistuksen tai sormenjäljen kataisille biometrisillä tiedoilla, tai jollakin muulla FIDO2-suojausratkaisulla." + }, + "newPasskey": { + "message": "Uusi suojausavain" + }, + "learnMoreAboutPasswordless": { + "message": "Luo lisää salasanattomasta kirjautumisesta" + }, + "passkeyEnterMasterPassword": { + "message": "Syötä pääsalasanasi muokataksesi suojausavaimella kirjautumisen asetuksia." + }, + "creatingPasskeyLoading": { + "message": "Suojausavainta luodaan..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Pidä tämä ikkuna avoinna ja seuraa selaimesi opasteita." + }, + "errorCreatingPasskey": { + "message": "Virhe suojausavaimen luonnissa" + }, + "errorCreatingPasskeyInfo": { + "message": "Suojausavaimesi luonnissa kohdattiin ongelma." + }, + "passkeySuccessfullyCreated": { + "message": "Suojausavain on luotu!" + }, + "customName": { + "message": "Mukautettu nimi" + }, + "customPasskeyNameInfo": { + "message": "Anna suojausavaimellesi nimi, josta tunnistat sen." + }, + "encryptionNotSupported": { + "message": "Salausta ei tueta" + }, + "loginWithPasskeyEnabled": { + "message": "Suojausavaimella kirjautuminen on käytössä" + }, + "passkeySaved": { + "message": "$NAME$ tallennettiin", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Suojausavain poistettiin" + }, + "removePasskey": { + "message": "POista suojausavain" + }, + "removePasskeyInfo": { + "message": "Jos kaikki suojausavaimet poistetaan, et voi kirjautua uusille laitteille ilman pääsalasanaasi." + }, + "passkeyLimitReachedInfo": { + "message": "Suojausavianten enimmäismäärä on saavutettu. Lisää suojausavain poistamalla jokin nykyisistä avaimista." + }, + "tryAgain": { + "message": "Yritä uudelleen" + }, "createAccount": { "message": "Luo uusi tili" }, @@ -5406,6 +5472,19 @@ "required": { "message": "pakollinen" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$ merkkiä (enimmäismäärä on $MAX$)", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Enintään $MAX$ merkkiä", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Käytössä" }, + "off": { + "message": "Ei käytössä" + }, "members": { "message": "Jäsenet" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Lisää Salaisuushallinta" + "subscribeToSecretsManager": { + "message": "Tilaa Salaisuushallinta" }, "addSecretsManagerUpgradeDesc": { "message": "Lisää Salaisuushallinta myös päivitettyyn tilaukseesi, jottet menetä pääsyä aiemmalla tilauksellasi luotuihin salaisuuksiin." diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index b68a81ca3e7..4a238724903 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Mag-log in gamit ang master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Gumawa ng account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "kailangan" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "I-on" }, + "off": { + "message": "Off" + }, "members": { "message": "Mga Miyembro" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index d02cfef1541..4c08e598cac 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Se connecter avec le mot de passe principal" }, + "loginWithPasskey": { + "message": "Se connecter avec la clé d'accès" + }, + "loginWithPasskeyInfo": { + "message": "Utilisez une clé d'accès générée qui vous connectera automatiquement sans mot de passe. Les fonctions biométriques, comme la reconnaissance faciale, l'empreinte digitale, ou une autre méthode de sécurité FIDO2 vérifiera votre identité." + }, + "newPasskey": { + "message": "Nouvelle clé d'accès" + }, + "learnMoreAboutPasswordless": { + "message": "En savoir plus sur l'identification sans mots de passe" + }, + "passkeyEnterMasterPassword": { + "message": "Entrez votre mot de passe maître pour modifier la connexion avec les paramètres de clé d'accès." + }, + "creatingPasskeyLoading": { + "message": "Création de la clé d'accès..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Gardez cette fenêtre ouverte et suivez les instructions de votre navigateur." + }, + "errorCreatingPasskey": { + "message": "Erreur de création de la clé d'accès" + }, + "errorCreatingPasskeyInfo": { + "message": "Il y a eu un problème lors de la crétion de votre clé d'accès." + }, + "passkeySuccessfullyCreated": { + "message": "Clé d'accès créée avec succès!" + }, + "customName": { + "message": "Nom personnalisé" + }, + "customPasskeyNameInfo": { + "message": "Nommez votre clé d'accès pour vous aider à l'identifier." + }, + "encryptionNotSupported": { + "message": "Chiffrement non pris en charge" + }, + "loginWithPasskeyEnabled": { + "message": "Se connecter avec la clé d'accès activée" + }, + "passkeySaved": { + "message": "$NAME$ a été enregistrée", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Clé d'accès supprimée" + }, + "removePasskey": { + "message": "Supprimer la clé d'accès" + }, + "removePasskeyInfo": { + "message": "Si toutes les clés d'accès sont supprimées, vous ne pourrez pas vous connecter à de nouveaux appareils sans votre mot de passe principal." + }, + "passkeyLimitReachedInfo": { + "message": "Limite de clé d'accès atteinte. Supprimez une clé d'accès pour en ajouter une autre." + }, + "tryAgain": { + "message": "Essayez de nouveau" + }, "createAccount": { "message": "Créez un compte" }, @@ -5406,6 +5472,19 @@ "required": { "message": "requis" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ caractères maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ caractères maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Activé" }, + "off": { + "message": "Désactivée" + }, "members": { "message": "Membres" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Ajouter Secrets Manager" + "subscribeToSecretsManager": { + "message": "S'abonner au Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Ajoutez Secrets Manager à votre plan mis à niveau pour conserver l'accès à tous les secrets créés avec votre plan précédent." diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 70f447848d9..9125060f521 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "צור חשבון" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index b6463a2d7cc..078fba139f2 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "खाता बनाएँ" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index dbf22380177..0684cdb4a5a 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Prijava glavnom lozinkom" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Stvori račun" }, @@ -5406,6 +5472,19 @@ "required": { "message": "obavezno" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "najviše $MAX$ znakova", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Uključeno" }, + "off": { + "message": "Off" + }, "members": { "message": "Članovi" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index faa4f61db77..d24afc3cce0 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Bejelentkezés mesterjelszóval" }, + "loginWithPasskey": { + "message": "Bejelentkezés jelszóval" + }, + "loginWithPasskeyInfo": { + "message": "Használjunk generált jelszót, amely automatikusan, jelszó nélkül bejelentkeztet. A biometrikus adatok, például az arcfelismerés vagy az ujjlenyomat, vagy más FIDO2 biztonsági módszer igazolja személyazonosságot." + }, + "newPasskey": { + "message": "Új jelszó" + }, + "learnMoreAboutPasswordless": { + "message": "További információ a jelszó nélküli használatról" + }, + "passkeyEnterMasterPassword": { + "message": "Adjuk meg a mesterjelszót a belépési jelszó beállításainak módosításához." + }, + "creatingPasskeyLoading": { + "message": "Jelszó létrehozása..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Tartsuk nyitva ezt az ablakot és kövessük a böngésző utasításait." + }, + "errorCreatingPasskey": { + "message": "Hiba történt a jelszó létrehozásakor." + }, + "errorCreatingPasskeyInfo": { + "message": "Probléma merült fel a jelszó létrehozásakor." + }, + "passkeySuccessfullyCreated": { + "message": "A jelszó sikeresen létrehozásra került!" + }, + "customName": { + "message": "Egyedi név" + }, + "customPasskeyNameInfo": { + "message": "Nevezzük el a jelszót a könnyebb azonosítshoz." + }, + "encryptionNotSupported": { + "message": "A titkosítás nem támogatott." + }, + "loginWithPasskeyEnabled": { + "message": "Jelentkezzünk be bekapcsolt jelszóval" + }, + "passkeySaved": { + "message": "$NAME$ mentésre került.", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "A jelszó eltávolításra került." + }, + "removePasskey": { + "message": "Jelszó eltávolítása" + }, + "removePasskeyInfo": { + "message": "Ha az összes jelszót eltávolítjuk, nem tudunk bejelentkezni az új eszközökre a mesterjelszó nélkül." + }, + "passkeyLimitReachedInfo": { + "message": "Elértük a jelszó korlátot. Távolítsunk el egy jelszót egy másik hozzáadásához." + }, + "tryAgain": { + "message": "Próbáluk újra" + }, "createAccount": { "message": "Fiók létrehozása" }, @@ -5406,6 +5472,19 @@ "required": { "message": "kötelező" }, + "charactersCurrentAndMaximum": { + "message": "Maximálisan $CURRENT$/$MAX$ karakter", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "maximálisan $MAX$ karakter", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Be" }, + "off": { + "message": "Ki" + }, "members": { "message": "Tagok" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Titkos kódkezelő hozzáadása" + "subscribeToSecretsManager": { + "message": "Feliratkozás a Titkos kód kezelés szolgáltatásra" }, "addSecretsManagerUpgradeDesc": { "message": "Titkkos kód kezelő hozzáadása a felminősített csomaghoz, hogy az előző csomaggal létrehozott titkos kódok megtartásához." diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 13e5d53c17c..f5f4c05d888 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Masuk dengan kata sandi utama" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Buat Akun" }, @@ -5406,6 +5472,19 @@ "required": { "message": "diperlukan" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Anggota" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index c726f0e5182..2e2c49876c2 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Accedi con password principale" }, + "loginWithPasskey": { + "message": "Accedi con passkey" + }, + "loginWithPasskeyInfo": { + "message": "Usa una passkey che ti farà accedere automaticamente senza una password. L'autenticazione biometrica, come il riconoscimento facciale o l'impronta digitale, o un altro metodo di sicurezza FIDO2 verificherà la tua identità." + }, + "newPasskey": { + "message": "Nuova passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Ulteriori informazioni sull'autenticazione senza password" + }, + "passkeyEnterMasterPassword": { + "message": "Inserisci la tua password principale per modificare le impostazioni di accesso con le passkey." + }, + "creatingPasskeyLoading": { + "message": "Creando la passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Mantieni questa finestra aperta e segui le istruzioni del tuo browser." + }, + "errorCreatingPasskey": { + "message": "Errore durante la creazione della passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "Si è verificato un problema durante la creazione della tua passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey creata!" + }, + "customName": { + "message": "Nome personalizzato" + }, + "customPasskeyNameInfo": { + "message": "Dai un nome alla tua passkey per aiutarti a riconoscerla." + }, + "encryptionNotSupported": { + "message": "Criptografia non supportata" + }, + "loginWithPasskeyEnabled": { + "message": "Accesso con passkey attivato" + }, + "passkeySaved": { + "message": "$NAME$ salvato", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey rimossa" + }, + "removePasskey": { + "message": "Rimuovi passkey" + }, + "removePasskeyInfo": { + "message": "Se tutte le passkey sono rimosse, non potrai accedere a nuovi dispositivi senza la tua password principale." + }, + "passkeyLimitReachedInfo": { + "message": "Limite di passkey raggiunto. Rimuovi una passkey per aggiungerne un'altra." + }, + "tryAgain": { + "message": "Riprova" + }, "createAccount": { "message": "Crea account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "obbligatorio" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$ caratteri su $MAX$", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Massimo $MAX$ caratteri", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Attivo" }, + "off": { + "message": "No" + }, "members": { "message": "Membri" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Aggiungi Gestore dei Segreti" + "subscribeToSecretsManager": { + "message": "Iscriviti al Gestore dei Segreti" }, "addSecretsManagerUpgradeDesc": { "message": "Aggiungi il Gestore dei Segreti al tuo piano aggiornato per mantenere l'accesso a tutti i secret creati con il tuo piano precedente." diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 6ec8f42fdf3..c943906d601 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "マスターパスワードでログイン" }, + "loginWithPasskey": { + "message": "パスキー でログイン" + }, + "loginWithPasskeyInfo": { + "message": "パスワードなしで自動的にログインできる、生成されたパスキーを使用します。顔や指紋などの生体認証、または他の FIDO2 認証方式で本人確認を行います。" + }, + "newPasskey": { + "message": "新しいパスキー" + }, + "learnMoreAboutPasswordless": { + "message": "パスワードレスの詳細" + }, + "passkeyEnterMasterPassword": { + "message": "パスキー設定でのログインを変更するには、マスターパスワードを入力してください。" + }, + "creatingPasskeyLoading": { + "message": "パスキーを作成中..." + }, + "creatingPasskeyLoadingInfo": { + "message": "このウィンドウを開いたままにして、ブラウザの指示に従ってください。" + }, + "errorCreatingPasskey": { + "message": "パスキーの作成に失敗しました" + }, + "errorCreatingPasskeyInfo": { + "message": "パスキー作成中に問題が発生しました。" + }, + "passkeySuccessfullyCreated": { + "message": "パスキーを作成しました!" + }, + "customName": { + "message": "カスタム名" + }, + "customPasskeyNameInfo": { + "message": "パスキーに名前を付けて、識別しやすいようにしましょう。" + }, + "encryptionNotSupported": { + "message": "暗号化はサポートされていません" + }, + "loginWithPasskeyEnabled": { + "message": "パスキーをオンにしてログイン" + }, + "passkeySaved": { + "message": "$NAME$ を保存しました", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "パスキーを削除しました" + }, + "removePasskey": { + "message": "パスキーを削除" + }, + "removePasskeyInfo": { + "message": "すべてのパスキーを削除すると、マスターパスワードなしで新しいデバイスにログインすることはできません。" + }, + "passkeyLimitReachedInfo": { + "message": "パスキーの上限に達しました。追加するにはまず既存のパスキーを削除してください。" + }, + "tryAgain": { + "message": "再試行" + }, "createAccount": { "message": "アカウントの作成" }, @@ -5406,6 +5472,19 @@ "required": { "message": "必須" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ 文字", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "最大 $MAX$ 文字", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "オン" }, + "off": { + "message": "オフ" + }, "members": { "message": "メンバー" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "シークレットマネージャーを追加" + "subscribeToSecretsManager": { + "message": "シークレットマネージャーに登録" }, "addSecretsManagerUpgradeDesc": { "message": "アップグレードしたプランにシークレットマネージャーを追加して、以前のプランで作成されたシークレットへのアクセスを維持します。" diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 9bfddfad59e..665c28b3b9c 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "ავტორიზაცია მთავარი პაროლით" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "ანგარიშის შექმნა" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index c349b08791a..d81d2a49b24 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "ಖಾತೆ ತೆರೆ" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 6e4a514c11a..66201c33c60 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "마스터 비밀번호로 로그인" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "계정 만들기" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "구성원" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index fcfc4628e6b..30ea169447a 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Pieteikties ar galveno paroli" }, + "loginWithPasskey": { + "message": "Pieteikties ar piekļuves atslēgu" + }, + "loginWithPasskeyInfo": { + "message": "Piekļuves atslēga ir izmantojama, lai automātiski pieteiktos bez paroles. Biometrija, piemēram, sejas atpazīšana vai pirkstu nospiedums, vai cits FIDO2 drošības veids apstiprinās identitāti." + }, + "newPasskey": { + "message": "Jauna piekļuves atslēga" + }, + "learnMoreAboutPasswordless": { + "message": "Uzzināt vairāk par bezparoles pieteikšanos" + }, + "passkeyEnterMasterPassword": { + "message": "Jāievada galvenā parole, lai mainītu pieteikšanās ar piekļuves atslēgu iestatījumus." + }, + "creatingPasskeyLoading": { + "message": "Izveido piekļuves atslēgu..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Šis logs ir jāpatur atvērts un jāseko uzvednēm pārlūkā." + }, + "errorCreatingPasskey": { + "message": "Kļūda piekļuves atslēgas izveidošanā" + }, + "errorCreatingPasskeyInfo": { + "message": "Atgadījās kļūda piekļuves atslēgas izveidošanas laikā." + }, + "passkeySuccessfullyCreated": { + "message": "Piekļuves atslēga veiksmīģi izveidota." + }, + "customName": { + "message": "Pielāgots nosaukums" + }, + "customPasskeyNameInfo": { + "message": "Nosaukuma piešķiršana piekļuves atslēgai palīdz to atpazīt." + }, + "encryptionNotSupported": { + "message": "Šifrēšana nav atbalstīta" + }, + "loginWithPasskeyEnabled": { + "message": "Pieteikšanās ar piekūves atslēgu ieslēgta" + }, + "passkeySaved": { + "message": "$NAME$ saglabāta", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Piekļuves atslēga noņemta" + }, + "removePasskey": { + "message": "Noņemt piekļuves atslēgu" + }, + "removePasskeyInfo": { + "message": "Ja visas piekļuves atslēgas ir noņemtas, nebūs iespējams pieteikties jaunās ierīcēs bez galvenās paroles." + }, + "passkeyLimitReachedInfo": { + "message": "Sasniegts piekļuves atslēgu ierobežojums. Jānoņem kāda piekļuves atslēga, lai pievienotu citu." + }, + "tryAgain": { + "message": "Jāmēģina vēlreiz" + }, "createAccount": { "message": "Izveidot kontu" }, @@ -5406,6 +5472,19 @@ "required": { "message": "nepieciešams" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ rakstzīmes", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Ne vairāk kā $MAX$ rakstzīmju", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Ieslēgts" }, + "off": { + "message": "Izslēgts" + }, "members": { "message": "Dalībnieki" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Pievienot Noslēpumu pārvaldnieku" + "subscribeToSecretsManager": { + "message": "Abonēt Noslēpumu pārvaldnieku" }, "addSecretsManagerUpgradeDesc": { "message": "Noslēpumu pārvaldnieks jāpievieno uzlabotajam plānam, lai saglabātu piekļuvi visiem noslēpumiem, kas tika izveidoti iepriekšējā plānā." diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index c29e0f42fad..e39f2f762d9 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "അക്കൗണ്ട് സൃഷ്ടിക്കുക" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 656d48456cc..9e0b6004513 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Logg på med hovedpassord" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Opprett en konto" }, @@ -5406,6 +5472,19 @@ "required": { "message": "obligatorisk" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Maksimalt $MAX$ tegn", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "På" }, + "off": { + "message": "Off" + }, "members": { "message": "Medlemmer" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 15621984c0b..4efbf528cf0 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 09196ea1c8a..66bf305406c 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Inloggen met je hoofdwachtwoord" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Account aanmaken" }, @@ -5406,6 +5472,19 @@ "required": { "message": "vereist" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Maximaal $MAX$ tekens", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Aan" }, + "off": { + "message": "Off" + }, "members": { "message": "Leden" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Secrets Manager toevoegen" + "subscribeToSecretsManager": { + "message": "Abonneren op Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Secrets Manager toevoegen aan je geüpgraded abonnement zodat je toegang houdt tot geheimen die met je vorige abonnement zijn aangemaakt." diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index da3d7e5a0c3..fa222d061d9 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index f6d8e35497a..ee8c1307e09 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Logowanie hasłem głównym" }, + "loginWithPasskey": { + "message": "Zaloguj się za pomocą passkey" + }, + "loginWithPasskeyInfo": { + "message": "Użyj wygenerowanego passkey'a, który automatycznie zaloguje Cię bez hasła. Biometrie, takie jak rozpoznawanie twarzy lub odcisk palca, lub inna metoda zabezpieczeń FIDO2, zweryfikują Twoją tożsamość." + }, + "newPasskey": { + "message": "Nowy passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Dowiedz się więcej o rozwiązaniach bezhasłowych" + }, + "passkeyEnterMasterPassword": { + "message": "Wprowadź hasło główne, aby zmodyfikować ustawienia logowania za pomocą passkey." + }, + "creatingPasskeyLoading": { + "message": "Tworzenie passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Pozostaw to okno otwarte i postępuj zgodnie z instrukcjami z przeglądarki." + }, + "errorCreatingPasskey": { + "message": "Błąd podczas tworzenia passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "Podczas tworzenia passkey'a pojawił się problem." + }, + "passkeySuccessfullyCreated": { + "message": "Pomyślnie utworzono passkey!" + }, + "customName": { + "message": "Niestandardowa nazwa" + }, + "customPasskeyNameInfo": { + "message": "Nazwij swój passkey, aby pomóc Ci go zidentyfikować." + }, + "encryptionNotSupported": { + "message": "Szyfrowanie nie jest obsługiwane" + }, + "loginWithPasskeyEnabled": { + "message": "Logowanie za pomocą passkey zostało włączone" + }, + "passkeySaved": { + "message": "$NAME$ zapisany", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey został usunięty" + }, + "removePasskey": { + "message": "Usuń passkey" + }, + "removePasskeyInfo": { + "message": "Jeśli wszystkie passkey'e zostaną usunięte, nie będziesz mógł zalogować się na nowe urządzenia bez hasła głównego." + }, + "passkeyLimitReachedInfo": { + "message": "Osiągnięto limit passkey'ów. Usuń passkey, aby dodać inny." + }, + "tryAgain": { + "message": "Spróbuj ponownie" + }, "createAccount": { "message": "Utwórz konto" }, @@ -5406,6 +5472,19 @@ "required": { "message": "wymagane" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ znaków", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ znaków maksymalnie", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Wł." }, + "off": { + "message": "Wyłączone" + }, "members": { "message": "Użytkownicy" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Dodaj menedżera sekretów" + "subscribeToSecretsManager": { + "message": "Zasubskrybuj się do menedżera sekretów" }, "addSecretsManagerUpgradeDesc": { "message": "Dodaj menedżera sekretów do zaktualizowanego planu, aby zachować dostęp do wszelkich sekretów utworzonych w poprzednim planie." diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index c5333d785f0..b35f957ab61 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Entrar com senha mestra" }, + "loginWithPasskey": { + "message": "Iniciar sessão com a chave de acesso" + }, + "loginWithPasskeyInfo": { + "message": "Use uma senha gerada que fará o login automaticamente sem uma senha. Biometrias como reconhecimento facial ou impressão digital, ou outro método de segurança FIDO2 verificarão sua identidade." + }, + "newPasskey": { + "message": "Nova chave de acesso" + }, + "learnMoreAboutPasswordless": { + "message": "Saiba mais sobre acesso sem senha" + }, + "passkeyEnterMasterPassword": { + "message": "Digite sua senha mestra para modificar as configurações de login com chave de acesso." + }, + "creatingPasskeyLoading": { + "message": "Criando chave de acesso..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Mantenha esta janela aberta e siga as instruções do seu navegador." + }, + "errorCreatingPasskey": { + "message": "Erro ao criar chave de acesso" + }, + "errorCreatingPasskeyInfo": { + "message": "Houve um problema ao criar sua chave de acesso." + }, + "passkeySuccessfullyCreated": { + "message": "Chave de acesso criada com sucesso!" + }, + "customName": { + "message": "Nome personalizado" + }, + "customPasskeyNameInfo": { + "message": "Nomeie sua chave de acesso para ajudá-lo a identificá-la." + }, + "encryptionNotSupported": { + "message": "Criptografia não suportada" + }, + "loginWithPasskeyEnabled": { + "message": "Iniciar sessão com a chave de acesso ativada" + }, + "passkeySaved": { + "message": "$NAME$ salvo", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Chave de acesso removida" + }, + "removePasskey": { + "message": "Remover chave de acesso" + }, + "removePasskeyInfo": { + "message": "Se todas as chaves de acesso forem removidas, não será mais possível fazer login em novos dispositivos sem sua senha mestra." + }, + "passkeyLimitReachedInfo": { + "message": "Limite de chaves de acesso atingido. Remova uma chave de acesso para adicionar outra." + }, + "tryAgain": { + "message": "Tente Novamente" + }, "createAccount": { "message": "Criar conta" }, @@ -5406,6 +5472,19 @@ "required": { "message": "obrigatório" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ caracteres no máximo", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "máximo de $MAX$ caracteres", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Ligado" }, + "off": { + "message": "Desligado" + }, "members": { "message": "Membros" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Assine o Gerenciador de Segredos" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 32c5276b0a1..52db80b2a0c 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Iniciar sessão com a palavra-passe mestra" }, + "loginWithPasskey": { + "message": "Iniciar sessão com a chave de acesso" + }, + "loginWithPasskeyInfo": { + "message": "Utilize uma chave de acesso gerada que lhe permitirá iniciar sessão automaticamente sem uma palavra-passe. A biometria, como o reconhecimento facial ou a impressão digital ou outro método de segurança FIDO2, verificará a sua identidade." + }, + "newPasskey": { + "message": "Nova chave de acesso" + }, + "learnMoreAboutPasswordless": { + "message": "Saiba mais sobre a ausência de palavra-passe" + }, + "passkeyEnterMasterPassword": { + "message": "Introduza a sua palavra-passe mestra para modificar as definições de início de sessão com chave de acesso." + }, + "creatingPasskeyLoading": { + "message": "A criar chave de acesso..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Mantenha esta janela aberta e siga as indicações do seu navegador." + }, + "errorCreatingPasskey": { + "message": "Erro ao criar chave de acesso" + }, + "errorCreatingPasskeyInfo": { + "message": "Houve um problema ao criar a sua chave de acesso." + }, + "passkeySuccessfullyCreated": { + "message": "Chave de acesso criada com sucesso!" + }, + "customName": { + "message": "Nome personalizado" + }, + "customPasskeyNameInfo": { + "message": "Dê um nome à sua chave de acesso para o ajudar a identificá-la." + }, + "encryptionNotSupported": { + "message": "Encriptação não suportada" + }, + "loginWithPasskeyEnabled": { + "message": "Iniciar sessão com a chave de acesso ativada" + }, + "passkeySaved": { + "message": "$NAME$ guardada", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Chave de acesso removida" + }, + "removePasskey": { + "message": "Remover chave de acesso" + }, + "removePasskeyInfo": { + "message": "Se todas as chaves de acesso forem removidas, não será possível iniciar sessão em novos dispositivos sem a sua palavra-passe mestra." + }, + "passkeyLimitReachedInfo": { + "message": "O limite de chaves de acesso foi atingido. Remova uma chave de acesso para adicionar outra." + }, + "tryAgain": { + "message": "Tentar novamente" + }, "createAccount": { "message": "Criar conta" }, @@ -5406,6 +5472,19 @@ "required": { "message": "necessário" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ máximo de caracteres", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Máximo de $MAX$ caracteres", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Ligado" }, + "off": { + "message": "Desligado" + }, "members": { "message": "Membros" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Adicionar Gestor de Segredos" + "subscribeToSecretsManager": { + "message": "Subscrever o Gestor de Segredos" }, "addSecretsManagerUpgradeDesc": { "message": "Adicione o Gestor de Segredos ao seu plano atualizado para manter o acesso a quaisquer segredos criados com o seu plano anterior." diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 1df9da3f6bf..9ca18d07767 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Autentificați-vă cu parola principală" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Creare cont" }, @@ -5406,6 +5472,19 @@ "required": { "message": "necesar" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Pornit" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 705198ac753..b209a6c4d11 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Войти с мастер-паролем" }, + "loginWithPasskey": { + "message": "Войти с ключом доступа" + }, + "loginWithPasskeyInfo": { + "message": "Используйте сгенерированный ключ доступа для автоматической авторизации без пароля. Ваша личность будет подтверждена биометрическими данными (распознаванием лица, отпечатком пальца или другим методом безопасности FIDO2)." + }, + "newPasskey": { + "message": "Новый ключ доступа" + }, + "learnMoreAboutPasswordless": { + "message": "Подробнее о беспарольном режиме" + }, + "passkeyEnterMasterPassword": { + "message": "Для изменения параметров авторизации ключом доступа введите мастер-пароль." + }, + "creatingPasskeyLoading": { + "message": "Создание ключа доступа..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Не закрывайте это окно и следуйте запросам браузера." + }, + "errorCreatingPasskey": { + "message": "Ошибка создания ключа доступа" + }, + "errorCreatingPasskeyInfo": { + "message": "При создании ключа доступа возникла проблема." + }, + "passkeySuccessfullyCreated": { + "message": "Ключ доступа успешно создан!" + }, + "customName": { + "message": "Имя" + }, + "customPasskeyNameInfo": { + "message": "Назовите ключ доступа так, чтобы вы могли его идентифицировать." + }, + "encryptionNotSupported": { + "message": "Шифрование не поддерживается" + }, + "loginWithPasskeyEnabled": { + "message": "Авторизоваться с помощью ключа доступа" + }, + "passkeySaved": { + "message": "$NAME$ сохранен", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Ключ доступа удален" + }, + "removePasskey": { + "message": "Удалить ключ доступа" + }, + "removePasskeyInfo": { + "message": "Если будут удалены все ключи доступа, вы не сможете авторизоваться на новых устройствах без мастер-пароля." + }, + "passkeyLimitReachedInfo": { + "message": "Достигнут предел ключей доступа. Удалите какой-нибудь ключ, чтобы добавить другой." + }, + "tryAgain": { + "message": "Попробуйте снова" + }, "createAccount": { "message": "Создать аккаунт" }, @@ -5406,6 +5472,19 @@ "required": { "message": "обязательно" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ симв. максимум", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Максимум символов $MAX$", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Вкл" }, + "off": { + "message": "Выкл" + }, "members": { "message": "Участники" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Добавить Менеджер секретов" + "subscribeToSecretsManager": { + "message": "Подписаться на Менеджер секретов" }, "addSecretsManagerUpgradeDesc": { "message": "Добавить Менеджер секретов к этому тарифному плану, чтобы сохранить доступ к секретам, созданным ранее." diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index efdf9a8c86e..1d8367d6114 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "ගිණුමක් සාදන්න" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 08276bda0bc..89d5995a995 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Prihlásenie pomocou hlavného hesla" }, + "loginWithPasskey": { + "message": "Prihlásiť sa s prístupovým kľúčom" + }, + "loginWithPasskeyInfo": { + "message": "Použite vygenerovaný prístupový kľúč, ktorý vás automaticky prihlási bez zadávania hesla. Vaša identita bude overená pomocou biometrie, ako napríklad rozpoznanie tváre alebo odtlačok prsta, alebo pomocou ďalšej FIDO2 bezpečnostnej metódy." + }, + "newPasskey": { + "message": "Nový prístupový kľúč" + }, + "learnMoreAboutPasswordless": { + "message": "Dozvedieť sa viac o automatickom prihlasovaní" + }, + "passkeyEnterMasterPassword": { + "message": "Zadajte vaše hlavné heslo ak chcete zmeniť nastavenia prihlásenia s prístupovým kľúčom." + }, + "creatingPasskeyLoading": { + "message": "Vytvára sa prístupový kľúč..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Ponechajte toto okno otvorené a nasledujte pokyny vášho prehliadača." + }, + "errorCreatingPasskey": { + "message": "Chyba pri vytváraní prístupového kľúča" + }, + "errorCreatingPasskeyInfo": { + "message": "Nastal problém pri vytváraní vášho prístupového kľúča." + }, + "passkeySuccessfullyCreated": { + "message": "Prístupový kľúč bol úspešne vytvorený!" + }, + "customName": { + "message": "Vlastný názov" + }, + "customPasskeyNameInfo": { + "message": "Dajte prístupovému kľúču názov aby ste ho mohli ľahšie identifikovať." + }, + "encryptionNotSupported": { + "message": "Šifrovanie nie je podporované" + }, + "loginWithPasskeyEnabled": { + "message": "Prihlásenie s prístupovým kľúčom zapnuté" + }, + "passkeySaved": { + "message": "$NAME$ uložený", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Prístupový kľúč bol odstránený" + }, + "removePasskey": { + "message": "Odstrániť prístupový kľúč" + }, + "removePasskeyInfo": { + "message": "Ak odstránite všetky prístupové kľúče, bez hlavného hesla sa nebudete môcť prihlásiť na nových zariadeniach." + }, + "passkeyLimitReachedInfo": { + "message": "Dosiahnutý limit počtu prístupových kľúčov. Odstráňte prístupový kľuč, ak chcete pridať ďalší." + }, + "tryAgain": { + "message": "Skúsiť znova" + }, "createAccount": { "message": "Vytvoriť účet" }, @@ -5406,6 +5472,19 @@ "required": { "message": "povinné" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ maximálneho počtu znakov", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "maximálne $MAX$ znakov", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Zapnuté" }, + "off": { + "message": "Vypnuté" + }, "members": { "message": "Členovia" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Pridať Secrets Manager" + "subscribeToSecretsManager": { + "message": "Predplatiť Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Do aktualizovaného plánu pridajte Secret Manager, aby ste si zachovali prístup k všetkým tajomstvám vytvoreným v predchádzajúcom pláne." diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 0f5ff850696..d082c126e7e 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Prijava z glavnim geslom" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Ustvarite si račun" }, @@ -5406,6 +5472,19 @@ "required": { "message": "obvezno" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index a1844d86fc8..2fad2224356 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Пријавите се са главном лозинком" }, + "loginWithPasskey": { + "message": "Пријави се са passkey" + }, + "loginWithPasskeyInfo": { + "message": "Користите генерисан passkey који ће вас аутоматски пријавити без лозинке. Биометрија, као што је препознавање лица или отисак прста, или неки други FIDO2 метод за проверу идентитета." + }, + "newPasskey": { + "message": "Нов passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Сазнајте више о пријављивању без лозинке" + }, + "passkeyEnterMasterPassword": { + "message": "Унесите главну лозинку да бисте изменили подешавања пријављивања са passkey." + }, + "creatingPasskeyLoading": { + "message": "Креација passkey-а..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Држите овај прозор отворен и пратите упутства из прегледача." + }, + "errorCreatingPasskey": { + "message": "Грешки у креацији passkey-а" + }, + "errorCreatingPasskeyInfo": { + "message": "Дошло је до проблема приликом креирања вашег passkey-а." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey успешно креиран!" + }, + "customName": { + "message": "Прилагоди име" + }, + "customPasskeyNameInfo": { + "message": "Именујте Ваш passkey за лакшу идентификацију." + }, + "encryptionNotSupported": { + "message": "Шифровање није подржано" + }, + "loginWithPasskeyEnabled": { + "message": "Пријављивање са passkey је упаљено" + }, + "passkeySaved": { + "message": "„$NAME$“ сачувано", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey уклоњен" + }, + "removePasskey": { + "message": "Уклонити passkey" + }, + "removePasskeyInfo": { + "message": "Ако су сви passkey уклоњени, нећете моћи да се пријавите на нове уређаје без ваше главне лозинке." + }, + "passkeyLimitReachedInfo": { + "message": "Достугнут лимит Passkey-а. Уклонити један да би додали други." + }, + "tryAgain": { + "message": "Покушај поново" + }, "createAccount": { "message": "Креирај налог" }, @@ -5406,6 +5472,19 @@ "required": { "message": "обавезно" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$ од макс $MAX$ карактера", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Максимум $MAX$ карактера", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Укључено" }, + "off": { + "message": "Искључено" + }, "members": { "message": "Чланови" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Додати Менаџер Тајни" + "subscribeToSecretsManager": { + "message": "Пријави се на Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." @@ -7179,9 +7261,9 @@ "message": "Већ имате налог?" }, "customBillingStart": { - "message": "Custom billing is not reflected. Visit the " + "message": "Прилагођени обрачун се не одражава. Посетите " }, "customBillingEnd": { - "message": " page for latest invoicing." + "message": " страницу за најновије фактуре." } } diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 78ab8fa1c70..47e86ccb131 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Napravi Nalog" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index c5880efe924..9940c818b90 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Logga in med huvudlösenord" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Anpassat namn" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Försök igen" + }, "createAccount": { "message": "Skapa konto" }, @@ -1261,7 +1327,7 @@ "message": "Data har importerats till ditt valv" }, "importSuccessNumberOfItems": { - "message": "A total of $AMOUNT$ items were imported.", + "message": "Sammanlagt $AMOUNT$ objekt importerades.", "placeholders": { "amount": { "content": "$1", @@ -5406,6 +5472,19 @@ "required": { "message": "obligatoriskt" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Max $MAX$ tecken", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "På" }, + "off": { + "message": "Off" + }, "members": { "message": "Medlemmar" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Lägg till Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index 7d1a4bebebd..28b3af6c2d5 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Log in with master password" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Create account" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index b429ed92dae..f2b7fce7408 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "เข้าสู่ระบบด้วยรหัสผ่านหลัก" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "สร้างบัญชีผู้ใช้" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 627eec657cb..7561db89d67 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Ana parola ile giriş yap" }, + "loginWithPasskey": { + "message": "Şifreyle giriş yapın" + }, + "loginWithPasskeyInfo": { + "message": "Parola olmadan otomatik olarak oturum açmanızı sağlayacak oluşturulmuş bir geçiş anahtarı kullanın. Yüz tanıma veya parmak izi gibi biyometri veya başka bir FIDO2 güvenlik yöntemi kimliğinizi doğrulayacaktır." + }, + "newPasskey": { + "message": "Yeni şifre" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Şifre anahtarıyla oturum açma ayarlarını değiştirmek için ana şifrenizi girin." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Bu pencereyi açık tutun ve tarayıcınızdan gelen talimatları izleyin." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "Şifreniz oluşturulurken bir sorun oluştu." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ kaydedildi", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Hesap aç" }, @@ -5406,6 +5472,19 @@ "required": { "message": "zorunlu" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "en fazla $MAX$ karakter", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Açık" }, + "off": { + "message": "Kapalı" + }, "members": { "message": "Üyeler" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Secrets Manager'a abone olun" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 29111deeb91..878063b9bee 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Увійти з головним паролем" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Створити обліковий запис" }, @@ -5406,6 +5472,19 @@ "required": { "message": "обов'язково" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "Максимум $MAX$ символів", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "Увімкнено" }, + "off": { + "message": "Off" + }, "members": { "message": "Учасники" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Додати менеджер секретів" + "subscribeToSecretsManager": { + "message": "Передплатити менеджер секретів" }, "addSecretsManagerUpgradeDesc": { "message": "Додайте менеджер секретів до свого оновленого плану, щоб підтримувати доступ до будь-яких секретів, створених у вашому минулому плані." diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 1483e23a2be..c8d4017e30d 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "Đăng nhập bằng mật khẩu chính" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "Tạo tài khoản" }, @@ -5406,6 +5472,19 @@ "required": { "message": "required" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ ký tự tối đa", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "On" }, + "off": { + "message": "Off" + }, "members": { "message": "Members" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "Add Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "Add Secrets Manager to your upgraded plan to maintain access to any secrets created with your previous plan." diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 7f3fc7f09fa..daee6752f5f 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "使用主密码登录" }, + "loginWithPasskey": { + "message": "使用通行密钥登录" + }, + "loginWithPasskeyInfo": { + "message": "使用已生成的通行密钥,无需密码即可自动登录。生物识别技术(例如面部识别或指纹)或其他 FIDO2 安全方法将用于验证您的身份。" + }, + "newPasskey": { + "message": "新增通行密钥" + }, + "learnMoreAboutPasswordless": { + "message": "了解更多关于无密码登录的信息" + }, + "passkeyEnterMasterPassword": { + "message": "输入您的主密码以修改通行密钥登录设置。" + }, + "creatingPasskeyLoading": { + "message": "正在创建通行密钥..." + }, + "creatingPasskeyLoadingInfo": { + "message": "保持此窗口打开然后按照浏览器的提示操作。" + }, + "errorCreatingPasskey": { + "message": "创建通行密钥时出错" + }, + "errorCreatingPasskeyInfo": { + "message": "创建通行密钥时出现问题。" + }, + "passkeySuccessfullyCreated": { + "message": "通行密钥创建成功!" + }, + "customName": { + "message": "自定义名称" + }, + "customPasskeyNameInfo": { + "message": "为您的通行密钥命名以帮助您识别它。" + }, + "encryptionNotSupported": { + "message": "不支持加密" + }, + "loginWithPasskeyEnabled": { + "message": "已启用通行密钥登录" + }, + "passkeySaved": { + "message": "$NAME$ 已保存", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "通行密钥已移除" + }, + "removePasskey": { + "message": "移除通行密钥" + }, + "removePasskeyInfo": { + "message": "如果移除了所有通行密钥,没有主密码您将无法登录新的设备。" + }, + "passkeyLimitReachedInfo": { + "message": "通行密钥已达上限。移除一个通行密钥以添加另一个。" + }, + "tryAgain": { + "message": "再试一次" + }, "createAccount": { "message": "创建账户" }, @@ -5406,6 +5472,19 @@ "required": { "message": "必填" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$ / 最大字符数 $MAX$", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "最多 $MAX$ 个字符", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "开启" }, + "off": { + "message": "Off" + }, "members": { "message": "成员" }, @@ -5913,7 +5995,7 @@ "description": "A machine user which can be used to automate processes and access secrets in the system." }, "serviceAccounts": { - "message": "服务帐户", + "message": "服务账户", "description": "The title for the section that deals with service accounts." }, "secrets": { @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "添加机密管理器" + "subscribeToSecretsManager": { + "message": "订阅机密管理器" }, "addSecretsManagerUpgradeDesc": { "message": "将机密管理器添加到升级后的计划中,以保留对使用之前的计划创建的所有机密的访问权限。" diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index eba26af5767..cb040a728dc 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -611,6 +611,72 @@ "loginWithMasterPassword": { "message": "使用主密碼登入" }, + "loginWithPasskey": { + "message": "Log in with passkey" + }, + "loginWithPasskeyInfo": { + "message": "Use a generated passkey that will automatically log you in without a password. Biometrics, like facial recognition or fingerprint, or another FIDO2 security method will verify your identity." + }, + "newPasskey": { + "message": "New passkey" + }, + "learnMoreAboutPasswordless": { + "message": "Learn more about passwordless" + }, + "passkeyEnterMasterPassword": { + "message": "Enter your master password to modify log in with passkey settings." + }, + "creatingPasskeyLoading": { + "message": "Creating passkey..." + }, + "creatingPasskeyLoadingInfo": { + "message": "Keep this window open and follow prompts from your browser." + }, + "errorCreatingPasskey": { + "message": "Error creating passkey" + }, + "errorCreatingPasskeyInfo": { + "message": "There was a problem creating your passkey." + }, + "passkeySuccessfullyCreated": { + "message": "Passkey successfully created!" + }, + "customName": { + "message": "Custom name" + }, + "customPasskeyNameInfo": { + "message": "Name your passkey to help you identify it." + }, + "encryptionNotSupported": { + "message": "Encryption not supported" + }, + "loginWithPasskeyEnabled": { + "message": "Log in with passkey turned on" + }, + "passkeySaved": { + "message": "$NAME$ saved", + "placeholders": { + "name": { + "content": "$1", + "example": "Personal yubikey" + } + } + }, + "passkeyRemoved": { + "message": "Passkey removed" + }, + "removePasskey": { + "message": "Remove passkey" + }, + "removePasskeyInfo": { + "message": "If all passkeys are removed, you will be unable to log into new devices without your master password." + }, + "passkeyLimitReachedInfo": { + "message": "Passkey limit reached. Remove a passkey to add another." + }, + "tryAgain": { + "message": "Try again" + }, "createAccount": { "message": "建立帳戶" }, @@ -5406,6 +5472,19 @@ "required": { "message": "必填" }, + "charactersCurrentAndMaximum": { + "message": "$CURRENT$/$MAX$ character maximum", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "max": { + "content": "$2", + "example": "100" + } + } + }, "characterMaximum": { "message": "$MAX$ character maximum", "placeholders": { @@ -5754,6 +5833,9 @@ "on": { "message": "開啟" }, + "off": { + "message": "Off" + }, "members": { "message": "成員" }, @@ -7096,8 +7178,8 @@ } } }, - "addSecretsManager": { - "message": "新增 Secrets Manager" + "subscribeToSecretsManager": { + "message": "Subscribe to Secrets Manager" }, "addSecretsManagerUpgradeDesc": { "message": "將 Secrets Manager 加入您的升級方案,來記錄維持存取於先前方案中保存的秘密資訊。" From 67fa1e06d05cb395c2121cbdb6f53012283cdb81 Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:41:47 +0200 Subject: [PATCH 24/33] [PM-4195] Lastpass access lib refactors (#6566) * Fix setUserTypeContext by adding missing return * Throw new Error instead of just string * Move enums and models into separate folders * Move UI classes into separate folder * Move FederatedUserContext import * Move services into a separate folder * Add barrel file for lastpass access lib * Fix build by updating imports after move --------- Co-authored-by: Daniel James Smith --- .../lastpass/access/enums/duo-factor.ts | 6 +++ .../lastpass/access/enums/duo-status.ts | 5 +++ .../lastpass/access/enums/idp-provider.ts | 8 ++++ .../importers/lastpass/access/enums/index.ts | 6 +++ .../access/enums/lastpass-login-type.ts | 5 +++ .../lastpass/access/{ => enums}/otp-method.ts | 0 .../lastpass/access/{ => enums}/platform.ts | 0 .../src/importers/lastpass/access/index.ts | 1 + .../lastpass/access/{ => models}/account.ts | 0 .../lastpass/access/{ => models}/chunk.ts | 0 .../access/{ => models}/client-info.ts | 2 +- .../{ => models}/federated-user-context.ts | 0 .../importers/lastpass/access/models/index.ts | 10 +++++ .../access/{ => models}/oob-result.ts | 0 .../access/{ => models}/otp-result.ts | 0 .../access/{ => models}/parser-options.ts | 0 .../lastpass/access/{ => models}/session.ts | 2 +- .../access/{ => models}/shared-folder.ts | 0 .../access/{ => models}/user-type-context.ts | 23 +++------- .../access/{ => services}/binary-reader.ts | 6 +-- .../lastpass/access/{ => services}/client.ts | 42 ++++++++++-------- .../access/{ => services}/crypto-utils.ts | 4 +- .../lastpass/access/services/index.ts | 5 +++ .../lastpass/access/{ => services}/parser.ts | 8 ++-- .../access/{ => services}/rest-client.ts | 0 .../lastpass/access/{ => ui}/duo-ui.ts | 15 +------ .../src/importers/lastpass/access/ui/index.ts | 2 + .../importers/lastpass/access/{ => ui}/ui.ts | 4 +- .../src/importers/lastpass/access/vault.ts | 43 ++++++++++--------- 29 files changed, 112 insertions(+), 85 deletions(-) create mode 100644 libs/importer/src/importers/lastpass/access/enums/duo-factor.ts create mode 100644 libs/importer/src/importers/lastpass/access/enums/duo-status.ts create mode 100644 libs/importer/src/importers/lastpass/access/enums/idp-provider.ts create mode 100644 libs/importer/src/importers/lastpass/access/enums/index.ts create mode 100644 libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts rename libs/importer/src/importers/lastpass/access/{ => enums}/otp-method.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => enums}/platform.ts (100%) create mode 100644 libs/importer/src/importers/lastpass/access/index.ts rename libs/importer/src/importers/lastpass/access/{ => models}/account.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => models}/chunk.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => models}/client-info.ts (69%) rename libs/importer/src/importers/lastpass/access/{ => models}/federated-user-context.ts (100%) create mode 100644 libs/importer/src/importers/lastpass/access/models/index.ts rename libs/importer/src/importers/lastpass/access/{ => models}/oob-result.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => models}/otp-result.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => models}/parser-options.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => models}/session.ts (78%) rename libs/importer/src/importers/lastpass/access/{ => models}/shared-folder.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => models}/user-type-context.ts (63%) rename libs/importer/src/importers/lastpass/access/{ => services}/binary-reader.ts (91%) rename libs/importer/src/importers/lastpass/access/{ => services}/client.ts (94%) rename libs/importer/src/importers/lastpass/access/{ => services}/crypto-utils.ts (96%) create mode 100644 libs/importer/src/importers/lastpass/access/services/index.ts rename libs/importer/src/importers/lastpass/access/{ => services}/parser.ts (97%) rename libs/importer/src/importers/lastpass/access/{ => services}/rest-client.ts (100%) rename libs/importer/src/importers/lastpass/access/{ => ui}/duo-ui.ts (81%) create mode 100644 libs/importer/src/importers/lastpass/access/ui/index.ts rename libs/importer/src/importers/lastpass/access/{ => ui}/ui.ts (93%) diff --git a/libs/importer/src/importers/lastpass/access/enums/duo-factor.ts b/libs/importer/src/importers/lastpass/access/enums/duo-factor.ts new file mode 100644 index 00000000000..aa65583935e --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/enums/duo-factor.ts @@ -0,0 +1,6 @@ +export enum DuoFactor { + Push, + Call, + Passcode, + SendPasscodesBySms, +} diff --git a/libs/importer/src/importers/lastpass/access/enums/duo-status.ts b/libs/importer/src/importers/lastpass/access/enums/duo-status.ts new file mode 100644 index 00000000000..6397db5dc91 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/enums/duo-status.ts @@ -0,0 +1,5 @@ +export enum DuoStatus { + Success, + Error, + Info, +} diff --git a/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts b/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts new file mode 100644 index 00000000000..32e74c36ee1 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/enums/idp-provider.ts @@ -0,0 +1,8 @@ +export enum IdpProvider { + Azure = 0, + OktaAuthServer = 1, + OktaNoAuthServer = 2, + Google = 3, + PingOne = 4, + OneLogin = 5, +} diff --git a/libs/importer/src/importers/lastpass/access/enums/index.ts b/libs/importer/src/importers/lastpass/access/enums/index.ts new file mode 100644 index 00000000000..0059030e0aa --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/enums/index.ts @@ -0,0 +1,6 @@ +export { DuoFactor } from "./duo-factor"; +export { DuoStatus } from "./duo-status"; +export { IdpProvider } from "./idp-provider"; +export { LastpassLoginType } from "./lastpass-login-type"; +export { OtpMethod } from "./otp-method"; +export { Platform } from "./platform"; diff --git a/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts b/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts new file mode 100644 index 00000000000..611dd0b6dab --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/enums/lastpass-login-type.ts @@ -0,0 +1,5 @@ +export enum LastpassLoginType { + MasterPassword = 0, + // Not sure what Types 1 and 2 are? + Federated = 3, +} diff --git a/libs/importer/src/importers/lastpass/access/otp-method.ts b/libs/importer/src/importers/lastpass/access/enums/otp-method.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/otp-method.ts rename to libs/importer/src/importers/lastpass/access/enums/otp-method.ts diff --git a/libs/importer/src/importers/lastpass/access/platform.ts b/libs/importer/src/importers/lastpass/access/enums/platform.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/platform.ts rename to libs/importer/src/importers/lastpass/access/enums/platform.ts diff --git a/libs/importer/src/importers/lastpass/access/index.ts b/libs/importer/src/importers/lastpass/access/index.ts new file mode 100644 index 00000000000..a124a44b315 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/index.ts @@ -0,0 +1 @@ +export { Vault } from "./vault"; diff --git a/libs/importer/src/importers/lastpass/access/account.ts b/libs/importer/src/importers/lastpass/access/models/account.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/account.ts rename to libs/importer/src/importers/lastpass/access/models/account.ts diff --git a/libs/importer/src/importers/lastpass/access/chunk.ts b/libs/importer/src/importers/lastpass/access/models/chunk.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/chunk.ts rename to libs/importer/src/importers/lastpass/access/models/chunk.ts diff --git a/libs/importer/src/importers/lastpass/access/client-info.ts b/libs/importer/src/importers/lastpass/access/models/client-info.ts similarity index 69% rename from libs/importer/src/importers/lastpass/access/client-info.ts rename to libs/importer/src/importers/lastpass/access/models/client-info.ts index fbe13d57d65..275cdc00d3f 100644 --- a/libs/importer/src/importers/lastpass/access/client-info.ts +++ b/libs/importer/src/importers/lastpass/access/models/client-info.ts @@ -1,4 +1,4 @@ -import { Platform } from "./platform"; +import { Platform } from "../enums"; export class ClientInfo { platform: Platform; diff --git a/libs/importer/src/importers/lastpass/access/federated-user-context.ts b/libs/importer/src/importers/lastpass/access/models/federated-user-context.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/federated-user-context.ts rename to libs/importer/src/importers/lastpass/access/models/federated-user-context.ts diff --git a/libs/importer/src/importers/lastpass/access/models/index.ts b/libs/importer/src/importers/lastpass/access/models/index.ts new file mode 100644 index 00000000000..a0c6121a354 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/models/index.ts @@ -0,0 +1,10 @@ +export { Account } from "./account"; +export { Chunk } from "./chunk"; +export { ClientInfo } from "./client-info"; +export { FederatedUserContext } from "./federated-user-context"; +export { OobResult } from "./oob-result"; +export { OtpResult } from "./otp-result"; +export { ParserOptions } from "./parser-options"; +export { Session } from "./session"; +export { SharedFolder } from "./shared-folder"; +export { UserTypeContext } from "./user-type-context"; diff --git a/libs/importer/src/importers/lastpass/access/oob-result.ts b/libs/importer/src/importers/lastpass/access/models/oob-result.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/oob-result.ts rename to libs/importer/src/importers/lastpass/access/models/oob-result.ts diff --git a/libs/importer/src/importers/lastpass/access/otp-result.ts b/libs/importer/src/importers/lastpass/access/models/otp-result.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/otp-result.ts rename to libs/importer/src/importers/lastpass/access/models/otp-result.ts diff --git a/libs/importer/src/importers/lastpass/access/parser-options.ts b/libs/importer/src/importers/lastpass/access/models/parser-options.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/parser-options.ts rename to libs/importer/src/importers/lastpass/access/models/parser-options.ts diff --git a/libs/importer/src/importers/lastpass/access/session.ts b/libs/importer/src/importers/lastpass/access/models/session.ts similarity index 78% rename from libs/importer/src/importers/lastpass/access/session.ts rename to libs/importer/src/importers/lastpass/access/models/session.ts index 4c712872632..f691968a7a7 100644 --- a/libs/importer/src/importers/lastpass/access/session.ts +++ b/libs/importer/src/importers/lastpass/access/models/session.ts @@ -1,4 +1,4 @@ -import { Platform } from "./platform"; +import { Platform } from "../enums"; export class Session { id: string; diff --git a/libs/importer/src/importers/lastpass/access/shared-folder.ts b/libs/importer/src/importers/lastpass/access/models/shared-folder.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/shared-folder.ts rename to libs/importer/src/importers/lastpass/access/models/shared-folder.ts diff --git a/libs/importer/src/importers/lastpass/access/user-type-context.ts b/libs/importer/src/importers/lastpass/access/models/user-type-context.ts similarity index 63% rename from libs/importer/src/importers/lastpass/access/user-type-context.ts rename to libs/importer/src/importers/lastpass/access/models/user-type-context.ts index f2629d59516..9d849281c2d 100644 --- a/libs/importer/src/importers/lastpass/access/user-type-context.ts +++ b/libs/importer/src/importers/lastpass/access/models/user-type-context.ts @@ -1,17 +1,19 @@ +import { IdpProvider, LastpassLoginType } from "../enums"; + export class UserTypeContext { - type: Type; + type: LastpassLoginType; IdentityProviderGUID: string; IdentityProviderURL: string; OpenIDConnectAuthority: string; OpenIDConnectClientId: string; CompanyId: number; - Provider: Provider; + Provider: IdpProvider; PkceEnabled: boolean; IsPasswordlessEnabled: boolean; isFederated(): boolean { return ( - this.type === Type.Federated && + this.type === LastpassLoginType.Federated && this.hasValue(this.IdentityProviderURL) && this.hasValue(this.OpenIDConnectAuthority) && this.hasValue(this.OpenIDConnectClientId) @@ -22,18 +24,3 @@ export class UserTypeContext { return str != null && str.trim() !== ""; } } - -export enum Provider { - Azure = 0, - OktaAuthServer = 1, - OktaNoAuthServer = 2, - Google = 3, - PingOne = 4, - OneLogin = 5, -} - -export enum Type { - MasterPassword = 0, - // Not sure what Types 1 and 2 are? - Federated = 3, -} diff --git a/libs/importer/src/importers/lastpass/access/binary-reader.ts b/libs/importer/src/importers/lastpass/access/services/binary-reader.ts similarity index 91% rename from libs/importer/src/importers/lastpass/access/binary-reader.ts rename to libs/importer/src/importers/lastpass/access/services/binary-reader.ts index 706afbd9e9b..e7a434e957f 100644 --- a/libs/importer/src/importers/lastpass/access/binary-reader.ts +++ b/libs/importer/src/importers/lastpass/access/services/binary-reader.ts @@ -12,7 +12,7 @@ export class BinaryReader { readBytes(count: number): Uint8Array { if (this.position + count > this.arr.length) { - throw "End of array reached"; + throw new Error("End of array reached"); } const slice = this.arr.subarray(this.position, this.position + count); this.position += count; @@ -62,10 +62,10 @@ export class BinaryReader { seekFromCurrentPosition(offset: number) { const newPosition = this.position + offset; if (newPosition < 0) { - throw "Position cannot be negative"; + throw new Error("Position cannot be negative"); } if (newPosition > this.arr.length) { - throw "Array not large enough to seek to this position"; + throw new Error("Array not large enough to seek to this position"); } this.position = newPosition; } diff --git a/libs/importer/src/importers/lastpass/access/client.ts b/libs/importer/src/importers/lastpass/access/services/client.ts similarity index 94% rename from libs/importer/src/importers/lastpass/access/client.ts rename to libs/importer/src/importers/lastpass/access/services/client.ts index 0a3c8fefe52..2d8b503f01d 100644 --- a/libs/importer/src/importers/lastpass/access/client.ts +++ b/libs/importer/src/importers/lastpass/access/services/client.ts @@ -1,21 +1,23 @@ import { HttpStatusCode } from "@bitwarden/common/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { Account } from "./account"; +import { OtpMethod, Platform } from "../enums"; +import { + Account, + Chunk, + ClientInfo, + OobResult, + OtpResult, + ParserOptions, + Session, + SharedFolder, +} from "../models"; +import { Ui } from "../ui"; + import { BinaryReader } from "./binary-reader"; -import { Chunk } from "./chunk"; -import { ClientInfo } from "./client-info"; import { CryptoUtils } from "./crypto-utils"; -import { OobResult } from "./oob-result"; -import { OtpMethod } from "./otp-method"; -import { OtpResult } from "./otp-result"; import { Parser } from "./parser"; -import { ParserOptions } from "./parser-options"; -import { Platform } from "./platform"; import { RestClient } from "./rest-client"; -import { Session } from "./session"; -import { SharedFolder } from "./shared-folder"; -import { Ui } from "./ui"; const PlatformToUserAgent = new Map([ [Platform.Desktop, "cli"], @@ -68,7 +70,7 @@ export class Client { const reader = new BinaryReader(blob); const chunks = this.parser.extractChunks(reader); if (!this.isComplete(chunks)) { - throw "Blob is truncated or corrupted"; + throw new Error("Blob is truncated or corrupted"); } return await this.parseAccounts(chunks, encryptionKey, privateKey, options); } @@ -236,11 +238,11 @@ export class Client { passcode = ui.provideYubikeyPasscode(); break; default: - throw "Invalid OTP method"; + throw new Error("Invalid OTP method"); } if (passcode == OtpResult.cancel) { - throw "Second factor step is canceled by the user"; + throw new Error("Second factor step is canceled by the user"); } const response = await this.performSingleLoginRequest( @@ -273,7 +275,7 @@ export class Client { ): Promise { const answer = this.approveOob(username, parameters, ui, rest); if (answer == OobResult.cancel) { - throw "Out of band step is canceled by the user"; + throw new Error("Out of band step is canceled by the user"); } const extraParameters = new Map(); @@ -319,7 +321,7 @@ export class Client { private approveOob(username: string, parameters: Map, ui: Ui, rest: RestClient) { const method = parameters.get("outofbandtype"); if (method == null) { - throw "Out of band method is not specified"; + throw new Error("Out of band method is not specified"); } switch (method) { case "lastpassauth": @@ -329,7 +331,7 @@ export class Client { case "salesforcehash": return ui.approveSalesforceAuth(); default: - throw "Out of band method " + method + " is not supported"; + throw new Error("Out of band method " + method + " is not supported"); } } @@ -410,7 +412,7 @@ export class Client { if (attr != null) { return attr; } - throw "Unknown response schema: attribute " + name + " is missing"; + throw new Error("Unknown response schema: attribute " + name + " is missing"); } private getOptionalErrorAttribute(response: Document, name: string): string { @@ -505,7 +507,9 @@ export class Client { private makeError(response: Response) { // TODO: error parsing - throw "HTTP request to " + response.url + " failed with status " + response.status + "."; + throw new Error( + "HTTP request to " + response.url + " failed with status " + response.status + "." + ); } private makeLoginError(response: Document): string { diff --git a/libs/importer/src/importers/lastpass/access/crypto-utils.ts b/libs/importer/src/importers/lastpass/access/services/crypto-utils.ts similarity index 96% rename from libs/importer/src/importers/lastpass/access/crypto-utils.ts rename to libs/importer/src/importers/lastpass/access/services/crypto-utils.ts index c8d9f8a168b..4de046f2aa3 100644 --- a/libs/importer/src/importers/lastpass/access/crypto-utils.ts +++ b/libs/importer/src/importers/lastpass/access/services/crypto-utils.ts @@ -6,7 +6,7 @@ export class CryptoUtils { async deriveKey(username: string, password: string, iterationCount: number) { if (iterationCount < 0) { - throw "Iteration count should be positive"; + throw new Error("Iteration count should be positive"); } if (iterationCount == 1) { return await this.cryptoFunctionService.hash(username + password, "sha256"); @@ -27,7 +27,7 @@ export class CryptoUtils { ExclusiveOr(arr1: Uint8Array, arr2: Uint8Array) { if (arr1.length !== arr2.length) { - throw "Arrays must be the same length."; + throw new Error("Arrays must be the same length."); } const result = new Uint8Array(arr1.length); for (let i = 0; i < arr1.length; i++) { diff --git a/libs/importer/src/importers/lastpass/access/services/index.ts b/libs/importer/src/importers/lastpass/access/services/index.ts new file mode 100644 index 00000000000..2610efdb694 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/services/index.ts @@ -0,0 +1,5 @@ +export { BinaryReader } from "./binary-reader"; +export { Client } from "./client"; +export { CryptoUtils } from "./crypto-utils"; +export { Parser } from "./parser"; +export { RestClient } from "./rest-client"; diff --git a/libs/importer/src/importers/lastpass/access/parser.ts b/libs/importer/src/importers/lastpass/access/services/parser.ts similarity index 97% rename from libs/importer/src/importers/lastpass/access/parser.ts rename to libs/importer/src/importers/lastpass/access/services/parser.ts index fc4b3b4a49a..3d64490be12 100644 --- a/libs/importer/src/importers/lastpass/access/parser.ts +++ b/libs/importer/src/importers/lastpass/access/services/parser.ts @@ -1,12 +1,10 @@ import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { Account } from "./account"; +import { Account, Chunk, ParserOptions, SharedFolder } from "../models"; + import { BinaryReader } from "./binary-reader"; -import { Chunk } from "./chunk"; import { CryptoUtils } from "./crypto-utils"; -import { ParserOptions } from "./parser-options"; -import { SharedFolder } from "./shared-folder"; const AllowedSecureNoteTypes = new Set([ "Server", @@ -285,7 +283,7 @@ export class Parser { const header = "LastPassPrivateKey<"; const footer = ">LastPassPrivateKey"; if (!decrypted.startsWith(header) || !decrypted.endsWith(footer)) { - throw "Failed to decrypt private key"; + throw new Error("Failed to decrypt private key"); } const parsedKey = decrypted.substring(header.length, decrypted.length - footer.length); diff --git a/libs/importer/src/importers/lastpass/access/rest-client.ts b/libs/importer/src/importers/lastpass/access/services/rest-client.ts similarity index 100% rename from libs/importer/src/importers/lastpass/access/rest-client.ts rename to libs/importer/src/importers/lastpass/access/services/rest-client.ts diff --git a/libs/importer/src/importers/lastpass/access/duo-ui.ts b/libs/importer/src/importers/lastpass/access/ui/duo-ui.ts similarity index 81% rename from libs/importer/src/importers/lastpass/access/duo-ui.ts rename to libs/importer/src/importers/lastpass/access/ui/duo-ui.ts index 61b52d2582a..60afd0ad9df 100644 --- a/libs/importer/src/importers/lastpass/access/duo-ui.ts +++ b/libs/importer/src/importers/lastpass/access/ui/duo-ui.ts @@ -1,3 +1,5 @@ +import { DuoFactor, DuoStatus } from "../enums"; + // Adds Duo functionality to the module-specific Ui class. export abstract class DuoUi { // To cancel return null @@ -8,19 +10,6 @@ export abstract class DuoUi { updateDuoStatus: (status: DuoStatus, text: string) => void; } -export enum DuoFactor { - Push, - Call, - Passcode, - SendPasscodesBySms, -} - -export enum DuoStatus { - Success, - Error, - Info, -} - export interface DuoChoice { device: DuoDevice; factor: DuoFactor; diff --git a/libs/importer/src/importers/lastpass/access/ui/index.ts b/libs/importer/src/importers/lastpass/access/ui/index.ts new file mode 100644 index 00000000000..e4edc3b6b48 --- /dev/null +++ b/libs/importer/src/importers/lastpass/access/ui/index.ts @@ -0,0 +1,2 @@ +export { DuoUi, DuoChoice, DuoDevice } from "./duo-ui"; +export { Ui } from "./ui"; diff --git a/libs/importer/src/importers/lastpass/access/ui.ts b/libs/importer/src/importers/lastpass/access/ui/ui.ts similarity index 93% rename from libs/importer/src/importers/lastpass/access/ui.ts rename to libs/importer/src/importers/lastpass/access/ui/ui.ts index fad86596187..2338e8a291e 100644 --- a/libs/importer/src/importers/lastpass/access/ui.ts +++ b/libs/importer/src/importers/lastpass/access/ui/ui.ts @@ -1,6 +1,6 @@ +import { OobResult, OtpResult } from "../models"; + import { DuoUi } from "./duo-ui"; -import { OobResult } from "./oob-result"; -import { OtpResult } from "./otp-result"; export abstract class Ui extends DuoUi { // To cancel return OtpResult.Cancel, otherwise only valid data is expected. diff --git a/libs/importer/src/importers/lastpass/access/vault.ts b/libs/importer/src/importers/lastpass/access/vault.ts index 157965804c2..a461239eea8 100644 --- a/libs/importer/src/importers/lastpass/access/vault.ts +++ b/libs/importer/src/importers/lastpass/access/vault.ts @@ -3,16 +3,16 @@ import { HttpStatusCode } from "@bitwarden/common/enums"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { Account } from "./account"; -import { Client } from "./client"; -import { ClientInfo } from "./client-info"; -import { CryptoUtils } from "./crypto-utils"; -import { FederatedUserContext } from "./federated-user-context"; -import { Parser } from "./parser"; -import { ParserOptions } from "./parser-options"; -import { RestClient } from "./rest-client"; +import { IdpProvider } from "./enums"; +import { + Account, + ClientInfo, + FederatedUserContext, + ParserOptions, + UserTypeContext, +} from "./models"; +import { Client, CryptoUtils, Parser, RestClient } from "./services"; import { Ui } from "./ui"; -import { Provider, UserTypeContext } from "./user-type-context"; export class Vault { accounts: Account[]; @@ -47,7 +47,7 @@ export class Vault { parserOptions: ParserOptions = ParserOptions.default ): Promise { if (federatedUser == null) { - throw "Federated user context is not set."; + throw new Error("Federated user context is not set."); } const k1 = await this.getK1(federatedUser); const k2 = await this.getK2(federatedUser); @@ -77,32 +77,33 @@ export class Vault { this.userType.PkceEnabled = json.PkceEnabled; this.userType.Provider = json.Provider; this.userType.type = json.type; + return; } - throw "Cannot determine LastPass user type."; + throw new Error("Cannot determine LastPass user type."); } private async getK1(federatedUser: FederatedUserContext): Promise { if (this.userType == null) { - throw "User type is not set."; + throw new Error("User type is not set."); } if (!this.userType.isFederated()) { - throw "Cannot get k1 for LastPass user that is not federated."; + throw new Error("Cannot get k1 for LastPass user that is not federated."); } if (federatedUser == null) { - throw "Federated user is not set."; + throw new Error("Federated user is not set."); } let k1: Uint8Array = null; if (federatedUser.idpUserInfo?.LastPassK1 !== null) { return Utils.fromByteStringToArray(federatedUser.idpUserInfo.LastPassK1); - } else if (this.userType.Provider === Provider.Azure) { + } else if (this.userType.Provider === IdpProvider.Azure) { k1 = await this.getK1Azure(federatedUser); - } else if (this.userType.Provider === Provider.Google) { + } else if (this.userType.Provider === IdpProvider.Google) { k1 = await this.getK1Google(federatedUser); } else { - const b64Encoded = this.userType.Provider === Provider.PingOne; + const b64Encoded = this.userType.Provider === IdpProvider.PingOne; k1 = this.getK1FromAccessToken(federatedUser, b64Encoded); } @@ -110,7 +111,7 @@ export class Vault { return k1; } - throw "Cannot get k1."; + throw new Error("Cannot get k1."); } private async getK1Azure(federatedUser: FederatedUserContext) { @@ -175,11 +176,11 @@ export class Vault { private async getK2(federatedUser: FederatedUserContext): Promise { if (this.userType == null) { - throw "User type is not set."; + throw new Error("User type is not set."); } if (!this.userType.isFederated()) { - throw "Cannot get k2 for LastPass user that is not federated."; + throw new Error("Cannot get k2 for LastPass user that is not federated."); } const rest = new RestClient(); @@ -195,6 +196,6 @@ export class Vault { return Utils.fromB64ToArray(k2); } } - throw "Cannot get k2."; + throw new Error("Cannot get k2."); } } From 3dab77ba9e28b02bdee42fa06c69e135257b3c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Fri, 13 Oct 2023 12:20:27 +0200 Subject: [PATCH 25/33] [PM-3680] Remove ipcRenderer from desktop-theming.service (#6478) --- apps/desktop/src/app/services/desktop-theming.service.ts | 7 ++----- apps/desktop/src/platform/preload.ts | 7 ++++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/app/services/desktop-theming.service.ts b/apps/desktop/src/app/services/desktop-theming.service.ts index 21277dfd736..3157ad9f661 100644 --- a/apps/desktop/src/app/services/desktop-theming.service.ts +++ b/apps/desktop/src/app/services/desktop-theming.service.ts @@ -1,5 +1,4 @@ import { Injectable } from "@angular/core"; -import { ipcRenderer } from "electron"; import { ThemingService } from "@bitwarden/angular/services/theming/theming.service"; import { ThemeType } from "@bitwarden/common/enums"; @@ -7,12 +6,10 @@ import { ThemeType } from "@bitwarden/common/enums"; @Injectable() export class DesktopThemingService extends ThemingService { protected async getSystemTheme(): Promise { - return await ipcRenderer.invoke("systemTheme"); + return await ipc.platform.getSystemTheme(); } protected monitorSystemThemeChanges(): void { - ipcRenderer.on("systemThemeUpdated", (_event, theme: ThemeType) => - this.updateSystemTheme(theme) - ); + ipc.platform.onSystemThemeUpdated((theme: ThemeType) => this.updateSystemTheme(theme)); } } diff --git a/apps/desktop/src/platform/preload.ts b/apps/desktop/src/platform/preload.ts index b8aed8f65d1..1ea4f3b91b4 100644 --- a/apps/desktop/src/platform/preload.ts +++ b/apps/desktop/src/platform/preload.ts @@ -1,6 +1,6 @@ import { ipcRenderer } from "electron"; -import { DeviceType } from "@bitwarden/common/enums/device-type.enum"; +import { DeviceType, ThemeType } from "@bitwarden/common/enums"; import { isDev, isWindowsStore } from "../utils"; @@ -12,6 +12,11 @@ export default { isDev: isDev(), isWindowsStore: isWindowsStore(), reloadProcess: () => ipcRenderer.send("reload-process"), + + getSystemTheme: (): Promise => ipcRenderer.invoke("systemTheme"), + onSystemThemeUpdated: (callback: (theme: ThemeType) => void) => { + ipcRenderer.on("systemThemeUpdated", (_event, theme: ThemeType) => callback(theme)); + }, }; function deviceType(): DeviceType { From bb9de00ad715f5932ec1897859d41815b78deedc Mon Sep 17 00:00:00 2001 From: Will Martin Date: Fri, 13 Oct 2023 10:26:56 -0400 Subject: [PATCH 26/33] [PM-4300] downgrade electron to v25.9.1 (#6573) --- apps/desktop/electron-builder.json | 2 +- package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 0830fabf13d..69d1c0074fa 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -19,7 +19,7 @@ "**/node_modules/@bitwarden/desktop-native/index.js", "**/node_modules/@bitwarden/desktop-native/desktop_native.${platform}-${arch}*.node" ], - "electronVersion": "26.3.0", + "electronVersion": "25.9.1", "generateUpdatesFilesForAllChannels": true, "publish": { "provider": "generic", diff --git a/package-lock.json b/package-lock.json index 0c1a4a69ea2..d6436616218 100644 --- a/package-lock.json +++ b/package-lock.json @@ -123,7 +123,7 @@ "cross-env": "7.0.3", "css-loader": "6.8.1", "del": "6.1.1", - "electron": "26.3.0", + "electron": "25.9.1", "electron-builder": "^23.6.0", "electron-log": "4.4.8", "electron-reload": "2.0.0-alpha.1", @@ -20179,9 +20179,9 @@ } }, "node_modules/electron": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-26.3.0.tgz", - "integrity": "sha512-7ZpvSHu+jmqialSvywTZnOQZZGLqlyj+yV5HGDrEzFnMiFaXBRpbByHgoUhaExJ/8t/0xKQjKlMRAY65w+zNZQ==", + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-25.9.1.tgz", + "integrity": "sha512-Uo/Fh7igjoUXA/f90iTATZJesQEArVL1uLA672JefNWTLymdKSZkJKiCciu/Xnd0TS6qvdIOUGuJFSTQnKskXQ==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/package.json b/package.json index 2cd1718c1e5..763897c388c 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "cross-env": "7.0.3", "css-loader": "6.8.1", "del": "6.1.1", - "electron": "26.3.0", + "electron": "25.9.1", "electron-builder": "^23.6.0", "electron-log": "4.4.8", "electron-reload": "2.0.0-alpha.1", From 95d4406a7ef1fbb98eef55445c679689aa2d37ee Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 13 Oct 2023 18:22:59 +0200 Subject: [PATCH 27/33] Update duo and add allow-popups and allow-popups-to-escape-sandbox (#6561) --- apps/browser/src/auth/popup/two-factor.component.html | 5 ++++- apps/desktop/src/auth/two-factor.component.html | 5 ++++- apps/web/src/app/auth/two-factor.component.html | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/browser/src/auth/popup/two-factor.component.html b/apps/browser/src/auth/popup/two-factor.component.html index 7fec67378cc..d03c675abdc 100644 --- a/apps/browser/src/auth/popup/two-factor.component.html +++ b/apps/browser/src/auth/popup/two-factor.component.html @@ -113,7 +113,10 @@

" >
- +
diff --git a/apps/desktop/src/auth/two-factor.component.html b/apps/desktop/src/auth/two-factor.component.html index cd21f91f59e..2b9a1722ee0 100644 --- a/apps/desktop/src/auth/two-factor.component.html +++ b/apps/desktop/src/auth/two-factor.component.html @@ -83,7 +83,10 @@

{{ title }}

" >
- +
diff --git a/apps/web/src/app/auth/two-factor.component.html b/apps/web/src/app/auth/two-factor.component.html index e3617a16589..99d40e1f3e0 100644 --- a/apps/web/src/app/auth/two-factor.component.html +++ b/apps/web/src/app/auth/two-factor.component.html @@ -92,7 +92,7 @@
From ee2f2e1fb13f3039bcc26b14e6a93f0ba0217686 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Fri, 13 Oct 2023 13:38:48 -0400 Subject: [PATCH 28/33] [PM-4127] Bugfix - Check original target tab URL before executing deferred action due to reprompt (#6434) * remove solve for pm-3613 (will readdress in pm-4014) * check original target tab URL before executing deferred action due to reprompt * only check if target tab host+path changed during reprompt --- apps/browser/src/autofill/content/autofill.js | 5 --- .../insert-autofill-content.service.spec.ts | 34 ------------------- .../insert-autofill-content.service.ts | 13 +------ .../popup/components/vault/view.component.ts | 12 ++++++- 4 files changed, 12 insertions(+), 52 deletions(-) diff --git a/apps/browser/src/autofill/content/autofill.js b/apps/browser/src/autofill/content/autofill.js index 2f3857d3fa8..ef0fb73408b 100644 --- a/apps/browser/src/autofill/content/autofill.js +++ b/apps/browser/src/autofill/content/autofill.js @@ -993,11 +993,6 @@ function fillTheElement(el, op) { var shouldCheck; if (el && null !== op && void 0 !== op && !(el.disabled || el.a || el.readOnly)) { - const tabURLChanged = !fillScript.savedUrls?.some(url => url.startsWith(window.location.origin)) - // Check to make sure the page location didn't change - if (tabURLChanged) { - return; - } switch (markTheFilling && el.form && !el.form.opfilled && (el.form.opfilled = true), el.type ? el.type.toLowerCase() : null) { case 'checkbox': diff --git a/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts b/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts index 0ab74875fbf..828d768ca25 100644 --- a/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts +++ b/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts @@ -108,7 +108,6 @@ describe("InsertAutofillContentService", () => { jest.spyOn(insertAutofillContentService as any, "fillingWithinSandboxedIframe"); jest.spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill"); jest.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill"); - jest.spyOn(insertAutofillContentService as any, "tabURLChanged"); jest.spyOn(insertAutofillContentService as any, "runFillScriptAction"); insertAutofillContentService.fillForm(fillScript); @@ -120,7 +119,6 @@ describe("InsertAutofillContentService", () => { expect( insertAutofillContentService["userCancelledUntrustedIframeAutofill"] ).not.toHaveBeenCalled(); - expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled(); expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled(); }); @@ -130,7 +128,6 @@ describe("InsertAutofillContentService", () => { .mockReturnValue(true); jest.spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill"); jest.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill"); - jest.spyOn(insertAutofillContentService as any, "tabURLChanged"); jest.spyOn(insertAutofillContentService as any, "runFillScriptAction"); insertAutofillContentService.fillForm(fillScript); @@ -142,7 +139,6 @@ describe("InsertAutofillContentService", () => { expect( insertAutofillContentService["userCancelledUntrustedIframeAutofill"] ).not.toHaveBeenCalled(); - expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled(); expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled(); }); @@ -154,7 +150,6 @@ describe("InsertAutofillContentService", () => { .spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill") .mockReturnValue(true); jest.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill"); - jest.spyOn(insertAutofillContentService as any, "tabURLChanged"); jest.spyOn(insertAutofillContentService as any, "runFillScriptAction"); insertAutofillContentService.fillForm(fillScript); @@ -164,7 +159,6 @@ describe("InsertAutofillContentService", () => { expect( insertAutofillContentService["userCancelledUntrustedIframeAutofill"] ).not.toHaveBeenCalled(); - expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled(); expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled(); }); @@ -178,7 +172,6 @@ describe("InsertAutofillContentService", () => { jest .spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill") .mockReturnValue(true); - jest.spyOn(insertAutofillContentService as any, "tabURLChanged").mockReturnValue(false); jest.spyOn(insertAutofillContentService as any, "runFillScriptAction"); insertAutofillContentService.fillForm(fillScript); @@ -188,31 +181,6 @@ describe("InsertAutofillContentService", () => { expect( insertAutofillContentService["userCancelledUntrustedIframeAutofill"] ).toHaveBeenCalled(); - expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled(); - expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled(); - }); - - it("returns early if the page location origin does not match against any of the cipher saved URLs", () => { - jest - .spyOn(insertAutofillContentService as any, "fillingWithinSandboxedIframe") - .mockReturnValue(false); - jest - .spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill") - .mockReturnValue(false); - jest - .spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill") - .mockReturnValue(false); - jest.spyOn(insertAutofillContentService as any, "tabURLChanged").mockReturnValue(true); - jest.spyOn(insertAutofillContentService as any, "runFillScriptAction"); - - insertAutofillContentService.fillForm(fillScript); - - expect(insertAutofillContentService["fillingWithinSandboxedIframe"]).toHaveBeenCalled(); - expect(insertAutofillContentService["userCancelledInsecureUrlAutofill"]).toHaveBeenCalled(); - expect( - insertAutofillContentService["userCancelledUntrustedIframeAutofill"] - ).toHaveBeenCalled(); - expect(insertAutofillContentService["tabURLChanged"]).toHaveBeenCalled(); expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled(); }); @@ -226,7 +194,6 @@ describe("InsertAutofillContentService", () => { jest .spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill") .mockReturnValue(false); - jest.spyOn(insertAutofillContentService as any, "tabURLChanged").mockReturnValue(false); jest.spyOn(insertAutofillContentService as any, "runFillScriptAction"); insertAutofillContentService.fillForm(fillScript); @@ -236,7 +203,6 @@ describe("InsertAutofillContentService", () => { expect( insertAutofillContentService["userCancelledUntrustedIframeAutofill"] ).toHaveBeenCalled(); - expect(insertAutofillContentService["tabURLChanged"]).toHaveBeenCalled(); expect(insertAutofillContentService["runFillScriptAction"]).toHaveBeenCalledTimes(3); expect(insertAutofillContentService["runFillScriptAction"]).toHaveBeenNthCalledWith( 1, diff --git a/apps/browser/src/autofill/services/insert-autofill-content.service.ts b/apps/browser/src/autofill/services/insert-autofill-content.service.ts index ad40b76fbcd..46cb53d4f59 100644 --- a/apps/browser/src/autofill/services/insert-autofill-content.service.ts +++ b/apps/browser/src/autofill/services/insert-autofill-content.service.ts @@ -38,8 +38,7 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf !fillScript.script?.length || this.fillingWithinSandboxedIframe() || this.userCancelledInsecureUrlAutofill(fillScript.savedUrls) || - this.userCancelledUntrustedIframeAutofill(fillScript) || - this.tabURLChanged(fillScript.savedUrls) + this.userCancelledUntrustedIframeAutofill(fillScript) ) { return; } @@ -47,16 +46,6 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf fillScript.script.forEach(this.runFillScriptAction); } - /** - * Determines if the page URL no longer matches one of the cipher's savedURL domains - * @param {string[] | null} savedUrls - * @returns {boolean} - * @private - */ - private tabURLChanged(savedUrls?: AutofillScript["savedUrls"]): boolean { - return savedUrls && !savedUrls.some((url) => url.startsWith(window.location.origin)); - } - /** * Identifies if the execution of this script is happening * within a sandboxed iframe. diff --git a/apps/browser/src/vault/popup/components/vault/view.component.ts b/apps/browser/src/vault/popup/components/vault/view.component.ts index 6c9f3967d56..29027b33505 100644 --- a/apps/browser/src/vault/popup/components/vault/view.component.ts +++ b/apps/browser/src/vault/popup/components/vault/view.component.ts @@ -331,11 +331,21 @@ export class ViewComponent extends BaseViewComponent { } private async doAutofill() { + const originalTabURL = this.tab.url?.length && new URL(this.tab.url); + if (!(await this.promptPassword())) { return false; } - if (this.pageDetails == null || this.pageDetails.length === 0) { + const currentTabURL = this.tab.url?.length && new URL(this.tab.url); + + const originalTabHostPath = + originalTabURL && `${originalTabURL.origin}${originalTabURL.pathname}`; + const currentTabHostPath = currentTabURL && `${currentTabURL.origin}${currentTabURL.pathname}`; + + const tabUrlChanged = originalTabHostPath !== currentTabHostPath; + + if (this.pageDetails == null || this.pageDetails.length === 0 || tabUrlChanged) { this.platformUtilsService.showToast("error", null, this.i18nService.t("autofillError")); return false; } From 2dc94ede97ddf6d6eec41bb03b849fa540cf9956 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 16 Oct 2023 15:43:38 +0200 Subject: [PATCH 29/33] [PM-3538] Migrate AddOrganizationComponent Web (#6275) Migrate add organization in provider portal to use component library. --- .../clients/add-organization.component.html | 72 +++++---------- .../clients/add-organization.component.ts | 91 ++++++++++--------- .../providers/clients/clients.component.html | 2 - .../providers/clients/clients.component.ts | 30 ++---- .../providers/providers.module.ts | 12 +-- libs/angular/src/services/modal.service.ts | 7 -- 6 files changed, 84 insertions(+), 130 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.html index 01cbc3c0bc5..0fa39f2f292 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.html @@ -1,47 +1,25 @@ -

{{ credential.name }} + {{ "supportsEncryption" | i18n }} @@ -31,7 +31,7 @@

{{ "encryptionNotSupported" | i18n }}

+
- - - - - -
- - - {{ o.name }} - - -
- -

-
-
-
+ + {{ "addExistingOrganization" | i18n }} + + + + + + + + + {{ o.name }} + + + + + + + + + + + + diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.ts index d3eff4bc53c..0d61c264e29 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/add-organization.component.ts @@ -1,4 +1,5 @@ -import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog"; +import { Component, Inject, OnInit } from "@angular/core"; import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; @@ -10,20 +11,21 @@ import { DialogService } from "@bitwarden/components"; import { WebProviderService } from "../services/web-provider.service"; +interface AddOrganizationDialogData { + providerId: string; + organizations: Organization[]; +} + @Component({ - selector: "provider-add-organization", templateUrl: "add-organization.component.html", }) export class AddOrganizationComponent implements OnInit { - @Input() providerId: string; - @Input() organizations: Organization[]; - @Output() onAddedOrganization = new EventEmitter(); - - provider: Provider; - formPromise: Promise; - loading = true; + protected provider: Provider; + protected loading = true; constructor( + private dialogRef: DialogRef, + @Inject(DIALOG_DATA) protected data: AddOrganizationDialogData, private providerService: ProviderService, private webProviderService: WebProviderService, private i18nService: I18nService, @@ -37,52 +39,53 @@ export class AddOrganizationComponent implements OnInit { } async load() { - if (this.providerId == null) { + if (this.data.providerId == null) { return; } - this.provider = await this.providerService.get(this.providerId); + this.provider = await this.providerService.get(this.data.providerId); this.loading = false; } - async add(organization: Organization) { - // eslint-disable-next-line @typescript-eslint/no-misused-promises - if (this.formPromise) { - return; - } + add(organization: Organization) { + return async () => { + const confirmed = await this.dialogService.openSimpleDialog({ + title: organization.name, + content: { + key: "addOrganizationConfirmation", + placeholders: [organization.name, this.provider.name], + }, + type: "warning", + }); - const confirmed = await this.dialogService.openSimpleDialog({ - title: organization.name, - content: { - key: "addOrganizationConfirmation", - placeholders: [organization.name, this.provider.name], - }, - type: "warning", - }); + if (!confirmed) { + return false; + } - if (!confirmed) { - return false; - } + try { + await this.webProviderService.addOrganizationToProvider( + this.data.providerId, + organization.id + ); + } catch (e) { + this.validationService.showError(e); + return; + } - try { - this.formPromise = this.webProviderService.addOrganizationToProvider( - this.providerId, - organization.id + this.platformUtilsService.showToast( + "success", + null, + this.i18nService.t("organizationJoinedProvider") ); - await this.formPromise; - } catch (e) { - this.validationService.showError(e); - return; - } finally { - this.formPromise = null; - } - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("organizationJoinedProvider") - ); - this.onAddedOrganization.emit(); + this.dialogRef.close(true); + }; + } + + static open(dialogService: DialogService, data: AddOrganizationDialogData) { + return dialogService.open(AddOrganizationComponent, { + data, + }); } } diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html index 59d07f7def8..9e3aaf4d29e 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.html @@ -97,5 +97,3 @@

{{ "clients" | i18n }}

- - diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.ts index 329bf5189e7..758c8120353 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/clients/clients.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; +import { firstValueFrom } from "rxjs"; import { first } from "rxjs/operators"; import { ModalService } from "@bitwarden/angular/services/modal.service"; @@ -33,8 +34,6 @@ const DisallowedPlanTypes = [ }) // eslint-disable-next-line rxjs-angular/prefer-takeuntil export class ClientsComponent implements OnInit { - @ViewChild("add", { read: ViewContainerRef, static: true }) addModalRef: ViewContainerRef; - providerId: string; searchText: string; addableOrganizations: Organization[]; @@ -135,23 +134,14 @@ export class ClientsComponent implements OnInit { } async addExistingOrganization() { - const [modal] = await this.modalService.openViewRef( - AddOrganizationComponent, - this.addModalRef, - (comp) => { - comp.providerId = this.providerId; - comp.organizations = this.addableOrganizations; - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - comp.onAddedOrganization.subscribe(async () => { - try { - await this.load(); - modal.close(); - } catch (e) { - this.logService.error(`Handled exception: ${e}`); - } - }); - } - ); + const dialogRef = AddOrganizationComponent.open(this.dialogService, { + providerId: this.providerId, + organizations: this.addableOrganizations, + }); + + if (await firstValueFrom(dialogRef.closed)) { + await this.load(); + } } async remove(organization: ProviderOrganizationOrganizationDetailsResponse) { diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts index b7f3bf9f382..7995e14825f 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers.module.ts @@ -1,9 +1,8 @@ import { CommonModule } from "@angular/common"; -import { ComponentFactoryResolver, NgModule } from "@angular/core"; +import { NgModule } from "@angular/core"; import { FormsModule } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { ModalService } from "@bitwarden/angular/services/modal.service"; import { SearchModule } from "@bitwarden/components"; import { OrganizationPlansComponent } from "@bitwarden/web-vault/app/billing"; import { OssModule } from "@bitwarden/web-vault/app/oss.module"; @@ -56,11 +55,4 @@ import { SetupComponent } from "./setup/setup.component"; ], providers: [WebProviderService, ProviderPermissionsGuard], }) -export class ProvidersModule { - constructor(modalService: ModalService, componentFactoryResolver: ComponentFactoryResolver) { - modalService.registerComponentFactoryResolver( - AddOrganizationComponent, - componentFactoryResolver - ); - } -} +export class ProvidersModule {} diff --git a/libs/angular/src/services/modal.service.ts b/libs/angular/src/services/modal.service.ts index ba461764ba8..da47368c2fa 100644 --- a/libs/angular/src/services/modal.service.ts +++ b/libs/angular/src/services/modal.service.ts @@ -88,13 +88,6 @@ export class ModalService { return modalRef; } - registerComponentFactoryResolver( - componentType: Type, - componentFactoryResolver: ComponentFactoryResolver - ): void { - this.factoryResolvers.set(componentType, componentFactoryResolver); - } - resolveComponentFactory(componentType: Type): ComponentFactory { if (this.factoryResolvers.has(componentType)) { return this.factoryResolvers.get(componentType).resolveComponentFactory(componentType); From c3856ce821cab1ce4f457f78cc0b1175ad1241e2 Mon Sep 17 00:00:00 2001 From: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:29:03 -0400 Subject: [PATCH 30/33] [SM-896] When org is disabled disable the logic and show warning symbols (#6225) * When org is disabled disable the logic and show warning symbols * fixing org enabled logic * removing unused code * Adding route gaurd logic and new org suspended page * fixing lint issue * fixing issues * Requested changes * adding back code that was accidentally removed from organization-switcher * Update bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Removing unused code and updating storybook to set enabled:true * removing onDestroy * Will's suggestions * will's suggested change * fix nav-item color in story * Thomas Rittson's suggested changes * adding back removed spaces * Adding back white space * updating guard * Update bitwarden_license/bit-web/src/app/secrets-manager/guards/sm-org-enabled.guard.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * removing ununsed data * Updating incorrect messages --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: William Martin Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> --- .../product-switcher-content.component.ts | 7 +- .../product-switcher.stories.ts | 2 +- apps/web/src/locales/en/messages.json | 12 +++ .../guards/sm-org-enabled.guard.ts | 29 +++++++ .../secrets-manager/{ => guards}/sm.guard.ts | 0 .../layout/org-switcher.component.html | 10 +++ .../layout/org-switcher.component.ts | 8 +- .../overview/overview.component.ts | 8 ++ .../dialog/project-dialog.component.ts | 10 +++ .../project/project-secrets.component.ts | 8 +- .../projects/project/project.component.ts | 8 +- .../projects/projects/projects.component.ts | 9 +- .../secrets/dialog/secret-dialog.component.ts | 6 ++ .../secrets/secrets.component.ts | 9 +- .../service-account-dialog.component.ts | 10 +++ .../service-accounts.component.ts | 9 +- .../shared/new-menu.component.ts | 13 ++- .../shared/org-suspended.component.html | 7 ++ .../shared/org-suspended.component.ts | 18 ++++ .../shared/sm-shared.module.ts | 2 + .../app/secrets-manager/sm-routing.module.ts | 87 ++++++++++--------- libs/components/src/icon/icons/index.ts | 1 + libs/components/src/icon/icons/no-access.ts | 12 +++ .../src/navigation/nav-group.component.html | 9 +- .../src/navigation/nav-item.component.html | 2 +- .../src/navigation/nav-item.stories.ts | 6 +- 26 files changed, 242 insertions(+), 60 deletions(-) create mode 100644 bitwarden_license/bit-web/src/app/secrets-manager/guards/sm-org-enabled.guard.ts rename bitwarden_license/bit-web/src/app/secrets-manager/{ => guards}/sm.guard.ts (100%) create mode 100644 bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.html create mode 100644 bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts create mode 100644 libs/components/src/icon/icons/no-access.ts diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.ts b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.ts index e0705dd070b..7a637c642b4 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.ts +++ b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.ts @@ -47,9 +47,10 @@ export class ProductSwitcherContentComponent { map(([orgs, paramMap]) => { const routeOrg = orgs.find((o) => o.id === paramMap.get("organizationId")); // If the active route org doesn't have access to SM, find the first org that does. - const smOrg = routeOrg?.canAccessSecretsManager - ? routeOrg - : orgs.find((o) => o.canAccessSecretsManager); + const smOrg = + routeOrg?.canAccessSecretsManager && routeOrg?.enabled == true + ? routeOrg + : orgs.find((o) => o.canAccessSecretsManager && o.enabled == true); /** * We can update this to the "satisfies" type upon upgrading to TypeScript 4.9 diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts index 87e42027476..46a2df458b0 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts @@ -131,5 +131,5 @@ OrgWithoutSecretsManager.args = { export const OrgWithSecretsManager = Template.bind({}); OrgWithSecretsManager.args = { - mockOrgs: [{ id: "b", canAccessSecretsManager: true }], + mockOrgs: [{ id: "b", canAccessSecretsManager: true, enabled: true }], }; diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index b9d613877f2..60fed7a538e 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3638,6 +3638,18 @@ "organizationIsDisabled": { "message": "Organization suspended" }, + "secretsAccessSuspended": { + "message": "Suspended organizations cannot be accessed. Please contact your organization owner for assistance." + }, + "secretsCannotCreate": { + "message": "Secrets cannot be created in suspended organizations. Please contact your organization owner for assistance." + }, + "projectsCannotCreate": { + "message": "Projects cannot be created in suspended organizations. Please contact your organization owner for assistance." + }, + "serviceAccountsCannotCreate": { + "message": "Service accounts cannot be created in suspended organizations. Please contact your organization owner for assistance." + }, "disabledOrganizationFilterError": { "message": "Items in suspended organizations cannot be accessed. Contact your organization owner for assistance." }, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/guards/sm-org-enabled.guard.ts b/bitwarden_license/bit-web/src/app/secrets-manager/guards/sm-org-enabled.guard.ts new file mode 100644 index 00000000000..3ff4d998a3d --- /dev/null +++ b/bitwarden_license/bit-web/src/app/secrets-manager/guards/sm-org-enabled.guard.ts @@ -0,0 +1,29 @@ +import { inject } from "@angular/core"; +import { ActivatedRouteSnapshot, CanActivateFn, createUrlTreeFromSnapshot } from "@angular/router"; + +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; + +/** + * Redirects from root `/sm` to first organization with access to SM + */ +export const organizationEnabledGuard: CanActivateFn = async (route: ActivatedRouteSnapshot) => { + const syncService = inject(SyncService); + const orgService = inject(OrganizationService); + + /** Workaround to avoid service initialization race condition. */ + if ((await syncService.getLastSync()) == null) { + await syncService.fullSync(false); + } + + const org = orgService.get(route.params.organizationId); + if (org == null || !org.canAccessSecretsManager) { + return createUrlTreeFromSnapshot(route, ["/"]); + } + + if (!org.enabled) { + return createUrlTreeFromSnapshot(route, ["/sm", org.id, "organization-suspended"]); + } + + return true; +}; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/sm.guard.ts b/bitwarden_license/bit-web/src/app/secrets-manager/guards/sm.guard.ts similarity index 100% rename from bitwarden_license/bit-web/src/app/secrets-manager/sm.guard.ts rename to bitwarden_license/bit-web/src/app/secrets-manager/guards/sm.guard.ts diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/org-switcher.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/layout/org-switcher.component.html index e639c5f126d..d7a404bf1dd 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/org-switcher.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/org-switcher.component.html @@ -7,6 +7,11 @@ [(open)]="open" [exactMatch]="true" > + + = this.organizationService.organizations$.pipe( - map((orgs) => orgs.filter(this.filter).sort((a, b) => a.name.localeCompare(b.name))) + map((orgs) => + orgs + .filter((org) => this.filter(org)) + .sort((a, b) => a.name.localeCompare(b.name)) + .sort((a, b) => (a.enabled ? -1 : 1)) + ) ); + protected activeOrganization$: Observable = combineLatest([ this.route.paramMap, this.organizations$, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts index 86fab25608a..868026a8431 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts @@ -70,6 +70,7 @@ export class OverviewComponent implements OnInit, OnDestroy { protected userIsAdmin: boolean; protected showOnboarding = false; protected loading = true; + protected organizationEnabled = false; protected view$: Observable<{ allProjects: ProjectListView[]; @@ -107,6 +108,7 @@ export class OverviewComponent implements OnInit, OnDestroy { this.organizationName = org.name; this.userIsAdmin = org.isAdmin; this.loading = true; + this.organizationEnabled = org.enabled; }); const projects$ = combineLatest([ @@ -208,6 +210,7 @@ export class OverviewComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Edit, + organizationEnabled: this.organizationEnabled, projectId: projectId, }, }); @@ -218,6 +221,7 @@ export class OverviewComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } @@ -227,6 +231,7 @@ export class OverviewComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } @@ -246,6 +251,7 @@ export class OverviewComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } @@ -256,6 +262,7 @@ export class OverviewComponent implements OnInit, OnDestroy { organizationId: this.organizationId, operation: OperationType.Edit, secretId: secretId, + organizationEnabled: this.organizationEnabled, }, }); } @@ -273,6 +280,7 @@ export class OverviewComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts index a6a3c958d09..3fd723c7580 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/dialog/project-dialog.component.ts @@ -18,6 +18,7 @@ export enum OperationType { export interface ProjectOperation { organizationId: string; operation: OperationType; + organizationEnabled: boolean; projectId?: string; } @@ -63,6 +64,15 @@ export class ProjectDialogComponent implements OnInit { } submit = async () => { + if (!this.data.organizationEnabled) { + this.platformUtilsService.showToast( + "error", + null, + this.i18nService.t("projectsCannotCreate") + ); + return; + } + this.formGroup.markAllAsTouched(); if (this.formGroup.invalid) { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.ts index 2d1690ef0ec..a952a351537 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.ts @@ -2,6 +2,7 @@ import { Component } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { combineLatest, combineLatestWith, filter, Observable, startWith, switchMap } from "rxjs"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogService } from "@bitwarden/components"; @@ -31,6 +32,7 @@ export class ProjectSecretsComponent { private organizationId: string; private projectId: string; protected project$: Observable; + private organizationEnabled: boolean; constructor( private route: ActivatedRoute, @@ -38,7 +40,8 @@ export class ProjectSecretsComponent { private secretService: SecretService, private dialogService: DialogService, private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService + private i18nService: I18nService, + private organizationService: OrganizationService ) {} ngOnInit() { @@ -60,6 +63,7 @@ export class ProjectSecretsComponent { switchMap(async ([_, params]) => { this.organizationId = params.organizationId; this.projectId = params.projectId; + this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled; return await this.getSecretsByProject(); }) ); @@ -75,6 +79,7 @@ export class ProjectSecretsComponent { organizationId: this.organizationId, operation: OperationType.Edit, secretId: secretId, + organizationEnabled: this.organizationEnabled, }, }); } @@ -93,6 +98,7 @@ export class ProjectSecretsComponent { organizationId: this.organizationId, operation: OperationType.Add, projectId: this.projectId, + organizationEnabled: this.organizationEnabled, }, }); } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts index c87d238d6a8..148ccc79d26 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts @@ -12,6 +12,7 @@ import { takeUntil, } from "rxjs"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogService } from "@bitwarden/components"; @@ -33,7 +34,7 @@ export class ProjectComponent implements OnInit, OnDestroy { private organizationId: string; private projectId: string; - + private organizationEnabled: boolean; private destroy$ = new Subject(); constructor( @@ -42,7 +43,8 @@ export class ProjectComponent implements OnInit, OnDestroy { private router: Router, private dialogService: DialogService, private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService + private i18nService: I18nService, + private organizationService: OrganizationService ) {} ngOnInit(): void { @@ -69,6 +71,7 @@ export class ProjectComponent implements OnInit, OnDestroy { this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => { this.organizationId = params.organizationId; this.projectId = params.projectId; + this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled; }); } @@ -82,6 +85,7 @@ export class ProjectComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Edit, + organizationEnabled: this.organizationEnabled, projectId: this.projectId, }, }); diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects/projects.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects/projects.component.ts index 7128e26a3d8..1066828f216 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects/projects.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects/projects.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { combineLatest, lastValueFrom, Observable, startWith, switchMap } from "rxjs"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { DialogService } from "@bitwarden/components"; import { ProjectListView } from "../../models/view/project-list.view"; @@ -32,12 +33,14 @@ export class ProjectsComponent implements OnInit { protected search: string; private organizationId: string; + private organizationEnabled: boolean; constructor( private route: ActivatedRoute, private projectService: ProjectService, private accessPolicyService: AccessPolicyService, - private dialogService: DialogService + private dialogService: DialogService, + private organizationService: OrganizationService ) {} ngOnInit() { @@ -48,6 +51,8 @@ export class ProjectsComponent implements OnInit { ]).pipe( switchMap(async ([params]) => { this.organizationId = params.organizationId; + this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled; + return await this.getProjects(); }) ); @@ -62,6 +67,7 @@ export class ProjectsComponent implements OnInit { data: { organizationId: this.organizationId, operation: OperationType.Edit, + organizationEnabled: this.organizationEnabled, projectId: projectId, }, }); @@ -72,6 +78,7 @@ export class ProjectsComponent implements OnInit { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts index 426542823f9..70eca54e3c5 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/dialog/secret-dialog.component.ts @@ -29,6 +29,7 @@ export interface SecretOperation { operation: OperationType; projectId?: string; secretId?: string; + organizationEnabled: boolean; } @Component({ @@ -163,6 +164,11 @@ export class SecretDialogComponent implements OnInit { } submit = async () => { + if (!this.data.organizationEnabled) { + this.platformUtilsService.showToast("error", null, this.i18nService.t("secretsCannotCreate")); + return; + } + this.formGroup.markAllAsTouched(); if (this.formGroup.invalid) { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts index 7c05f169a3d..b23393de60a 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { combineLatestWith, Observable, startWith, switchMap } from "rxjs"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogService } from "@bitwarden/components"; @@ -29,13 +30,15 @@ export class SecretsComponent implements OnInit { protected search: string; private organizationId: string; + private organizationEnabled: boolean; constructor( private route: ActivatedRoute, private secretService: SecretService, private dialogService: DialogService, private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService + private i18nService: I18nService, + private organizationService: OrganizationService ) {} ngOnInit() { @@ -44,6 +47,8 @@ export class SecretsComponent implements OnInit { combineLatestWith(this.route.params), switchMap(async ([_, params]) => { this.organizationId = params.organizationId; + this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled; + return await this.getSecrets(); }) ); @@ -63,6 +68,7 @@ export class SecretsComponent implements OnInit { organizationId: this.organizationId, operation: OperationType.Edit, secretId: secretId, + organizationEnabled: this.organizationEnabled, }, }); } @@ -80,6 +86,7 @@ export class SecretsComponent implements OnInit { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts index 1f42537f956..decd042cc14 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/dialog/service-account-dialog.component.ts @@ -18,6 +18,7 @@ export interface ServiceAccountOperation { organizationId: string; serviceAccountId?: string; operation: OperationType; + organizationEnabled: boolean; } @Component({ @@ -62,6 +63,15 @@ export class ServiceAccountDialogComponent { } submit = async () => { + if (!this.data.organizationEnabled) { + this.platformUtilsService.showToast( + "error", + null, + this.i18nService.t("serviceAccountsCannotCreate") + ); + return; + } + this.formGroup.markAllAsTouched(); if (this.formGroup.invalid) { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts.component.ts index 808073ba810..bebd9ddca62 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { combineLatest, Observable, startWith, switchMap } from "rxjs"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { DialogService } from "@bitwarden/components"; import { @@ -30,12 +31,14 @@ export class ServiceAccountsComponent implements OnInit { protected search: string; private organizationId: string; + private organizationEnabled: boolean; constructor( private route: ActivatedRoute, private dialogService: DialogService, private accessPolicyService: AccessPolicyService, - private serviceAccountService: ServiceAccountService + private serviceAccountService: ServiceAccountService, + private organizationService: OrganizationService ) {} ngOnInit() { @@ -46,6 +49,8 @@ export class ServiceAccountsComponent implements OnInit { ]).pipe( switchMap(async ([params]) => { this.organizationId = params.organizationId; + this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled; + return await this.getServiceAccounts(); }) ); @@ -56,6 +61,7 @@ export class ServiceAccountsComponent implements OnInit { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } @@ -66,6 +72,7 @@ export class ServiceAccountsComponent implements OnInit { organizationId: this.organizationId, serviceAccountId: serviceAccountId, operation: OperationType.Edit, + organizationEnabled: this.organizationEnabled, }, }); } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/new-menu.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/new-menu.component.ts index 7ecc2f917a4..67a93e8ad87 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/new-menu.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/new-menu.component.ts @@ -2,6 +2,7 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { Subject, takeUntil } from "rxjs"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { DialogService } from "@bitwarden/components"; import { @@ -24,13 +25,18 @@ import { }) export class NewMenuComponent implements OnInit, OnDestroy { private organizationId: string; + private organizationEnabled: boolean; private destroy$: Subject = new Subject(); - - constructor(private route: ActivatedRoute, private dialogService: DialogService) {} + constructor( + private route: ActivatedRoute, + private dialogService: DialogService, + private organizationService: OrganizationService + ) {} ngOnInit() { this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params: any) => { this.organizationId = params.organizationId; + this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled; }); } @@ -44,6 +50,7 @@ export class NewMenuComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } @@ -53,6 +60,7 @@ export class NewMenuComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } @@ -62,6 +70,7 @@ export class NewMenuComponent implements OnInit, OnDestroy { data: { organizationId: this.organizationId, operation: OperationType.Add, + organizationEnabled: this.organizationEnabled, }, }); } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.html new file mode 100644 index 00000000000..8de68f65988 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.html @@ -0,0 +1,7 @@ + + + + + {{ "organizationIsDisabled" | i18n }} + {{ "secretsAccessSuspended" | i18n }} + diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts new file mode 100644 index 00000000000..73f89c0826d --- /dev/null +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts @@ -0,0 +1,18 @@ +import { Component } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { map } from "rxjs"; + +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { Icon, Icons } from "@bitwarden/components"; + +@Component({ + templateUrl: "./org-suspended.component.html", +}) +export class OrgSuspendedComponent { + constructor(private organizationService: OrganizationService, private route: ActivatedRoute) {} + + protected NoAccess: Icon = Icons.NoAccess; + protected organizationName$ = this.route.params.pipe( + map((params) => this.organizationService.get(params.organizationId)?.name) + ); +} diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/sm-shared.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/sm-shared.module.ts index 6d59503b50a..d2990f4c67f 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/sm-shared.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/sm-shared.module.ts @@ -17,6 +17,7 @@ import { BulkConfirmationDialogComponent } from "./dialogs/bulk-confirmation-dia import { BulkStatusDialogComponent } from "./dialogs/bulk-status-dialog.component"; import { HeaderComponent } from "./header.component"; import { NewMenuComponent } from "./new-menu.component"; +import { OrgSuspendedComponent } from "./org-suspended.component"; import { ProjectsListComponent } from "./projects-list.component"; import { SecretsListComponent } from "./secrets-list.component"; @@ -55,6 +56,7 @@ import { SecretsListComponent } from "./secrets-list.component"; ProjectsListComponent, SecretsListComponent, AccessSelectorComponent, + OrgSuspendedComponent, ], providers: [], bootstrap: [], diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts index 5c18bab4e42..0cad3129a40 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/sm-routing.module.ts @@ -2,10 +2,10 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { AuthGuard } from "@bitwarden/angular/auth/guards"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { OrganizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard"; import { buildFlaggedRoute } from "@bitwarden/web-vault/app/oss-routing.module"; +import { organizationEnabledGuard } from "./guards/sm-org-enabled.guard"; +import { canActivateSM } from "./guards/sm.guard"; import { LayoutComponent } from "./layout/layout.component"; import { NavigationComponent } from "./layout/navigation.component"; import { OverviewModule } from "./overview/overview.module"; @@ -13,7 +13,7 @@ import { ProjectsModule } from "./projects/projects.module"; import { SecretsModule } from "./secrets/secrets.module"; import { ServiceAccountsModule } from "./service-accounts/service-accounts.module"; import { SettingsModule } from "./settings/settings.module"; -import { canActivateSM } from "./sm.guard"; +import { OrgSuspendedComponent } from "./shared/org-suspended.component"; import { TrashModule } from "./trash/trash.module"; const routes: Routes = [ @@ -29,10 +29,7 @@ const routes: Routes = [ { path: ":organizationId", component: LayoutComponent, - canActivate: [AuthGuard, OrganizationPermissionsGuard], - data: { - organizationPermissions: (org: Organization) => org.canAccessSecretsManager, - }, + canActivate: [AuthGuard], children: [ { path: "", @@ -40,41 +37,51 @@ const routes: Routes = [ outlet: "sidebar", }, { - path: "secrets", - loadChildren: () => SecretsModule, - data: { - titleId: "secrets", - }, - }, - { - path: "projects", - loadChildren: () => ProjectsModule, - data: { - titleId: "projects", - }, - }, - { - path: "service-accounts", - loadChildren: () => ServiceAccountsModule, - data: { - titleId: "serviceAccounts", - }, - }, - { - path: "trash", - loadChildren: () => TrashModule, - data: { - titleId: "trash", - }, - }, - { - path: "settings", - loadChildren: () => SettingsModule, + path: "", + canActivate: [organizationEnabledGuard], + children: [ + { + path: "secrets", + loadChildren: () => SecretsModule, + data: { + titleId: "secrets", + }, + }, + { + path: "projects", + loadChildren: () => ProjectsModule, + data: { + titleId: "projects", + }, + }, + { + path: "service-accounts", + loadChildren: () => ServiceAccountsModule, + data: { + titleId: "serviceAccounts", + }, + }, + { + path: "trash", + loadChildren: () => TrashModule, + data: { + titleId: "trash", + }, + }, + { + path: "settings", + loadChildren: () => SettingsModule, + }, + { + path: "", + loadChildren: () => OverviewModule, + pathMatch: "full", + }, + ], }, { - path: "", - loadChildren: () => OverviewModule, - pathMatch: "full", + path: "organization-suspended", + component: OrgSuspendedComponent, }, ], }, diff --git a/libs/components/src/icon/icons/index.ts b/libs/components/src/icon/icons/index.ts index 03fdb729bc7..02cb975e095 100644 --- a/libs/components/src/icon/icons/index.ts +++ b/libs/components/src/icon/icons/index.ts @@ -1 +1,2 @@ export * from "./search"; +export * from "./no-access"; diff --git a/libs/components/src/icon/icons/no-access.ts b/libs/components/src/icon/icons/no-access.ts new file mode 100644 index 00000000000..f9ad048752a --- /dev/null +++ b/libs/components/src/icon/icons/no-access.ts @@ -0,0 +1,12 @@ +import { svgIcon } from "../icon"; + +export const NoAccess = svgIcon` + + + + + + + + +`; diff --git a/libs/components/src/navigation/nav-group.component.html b/libs/components/src/navigation/nav-group.component.html index ca9a7c3aecf..118f78a1865 100644 --- a/libs/components/src/navigation/nav-group.component.html +++ b/libs/components/src/navigation/nav-group.component.html @@ -17,7 +17,7 @@ [bitIconButton]=" open ? 'bwi-angle-up' : variant === 'tree' ? 'bwi-angle-right' : 'bwi-angle-down' " - [buttonType]="'main'" + [buttonType]="'light'" (click)="toggle($event)" size="small" [title]="'toggleCollapse' | i18n" @@ -32,8 +32,11 @@ - - + + + + + diff --git a/libs/components/src/navigation/nav-item.component.html b/libs/components/src/navigation/nav-item.component.html index 32c8dfbf980..02705e821eb 100644 --- a/libs/components/src/navigation/nav-item.component.html +++ b/libs/components/src/navigation/nav-item.component.html @@ -73,7 +73,7 @@
diff --git a/libs/components/src/navigation/nav-item.stories.ts b/libs/components/src/navigation/nav-item.stories.ts index 7fdbadce31a..c8f90eabcff 100644 --- a/libs/components/src/navigation/nav-item.stories.ts +++ b/libs/components/src/navigation/nav-item.stories.ts @@ -64,7 +64,7 @@ export const WithChildButtons: Story = { slot="start" class="tw-ml-auto" [bitIconButton]="'bwi-clone'" - [buttonType]="'contrast'" + [buttonType]="'light'" size="small" aria-label="option 1" > @@ -72,7 +72,7 @@ export const WithChildButtons: Story = { slot="end" class="tw-ml-auto" [bitIconButton]="'bwi-pencil-square'" - [buttonType]="'contrast'" + [buttonType]="'light'" size="small" aria-label="option 2" > @@ -80,7 +80,7 @@ export const WithChildButtons: Story = { slot="end" class="tw-ml-auto" [bitIconButton]="'bwi-check'" - [buttonType]="'contrast'" + [buttonType]="'light'" size="small" aria-label="option 3" > From b1a92ba04b96d6260e1445da7bad29948a41d6ca Mon Sep 17 00:00:00 2001 From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:10:04 -0400 Subject: [PATCH 31/33] [PM-2411] Update `billing-sync-api-key` to use Dialog (#6537) * Update billing-sync-api-key dialog * Oscar's feedback --- .../billing-sync-api-key.component.html | 186 +++++++----------- .../billing-sync-api-key.component.ts | 74 ++++--- ...ganization-subscription-cloud.component.ts | 30 +-- 3 files changed, 124 insertions(+), 166 deletions(-) diff --git a/apps/web/src/app/billing/organizations/billing-sync-api-key.component.html b/apps/web/src/app/billing/organizations/billing-sync-api-key.component.html index a196845a395..f5225bc29a0 100644 --- a/apps/web/src/app/billing/organizations/billing-sync-api-key.component.html +++ b/apps/web/src/app/billing/organizations/billing-sync-api-key.component.html @@ -1,117 +1,75 @@ - + + + + {{ hostname }} + + + diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.component.ts index 0b7625a3902..6b62b28ca6d 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.component.ts @@ -5,6 +5,7 @@ import { combineLatest, map, Observable } from "rxjs"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { AccountProfile } from "@bitwarden/common/platform/models/domain/account"; @@ -26,10 +27,13 @@ export class HeaderComponent { protected routeData$: Observable<{ titleId: string }>; protected account$: Observable; protected canLock$: Observable; + protected selfHosted: boolean; + protected hostname = location.hostname; constructor( private route: ActivatedRoute, private stateService: StateService, + private platformUtilsService: PlatformUtilsService, private vaultTimeoutSettingsService: VaultTimeoutSettingsService, private messagingService: MessagingService ) { @@ -41,6 +45,8 @@ export class HeaderComponent { }) ); + this.selfHosted = this.platformUtilsService.isSelfHost(); + this.account$ = combineLatest([ this.stateService.activeAccount$, this.stateService.accounts$, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.stories.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.stories.ts index 8e480ae50a1..1231ba100a4 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.stories.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/header.stories.ts @@ -13,6 +13,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { AvatarModule, @@ -50,6 +51,12 @@ class MockVaultTimeoutService { } } +class MockPlatformUtilsService { + isSelfHost() { + return false; + } +} + @Component({ selector: "product-switcher", template: ``, @@ -97,6 +104,7 @@ export default { declarations: [HeaderComponent, MockProductSwitcher, MockDynamicAvatar], providers: [ { provide: StateService, useClass: MockStateService }, + { provide: PlatformUtilsService, useClass: MockPlatformUtilsService }, { provide: VaultTimeoutSettingsService, useClass: MockVaultTimeoutService }, { provide: MessagingService,