From c6be3fa19ccb60cf01c58173ca31568fbc1599cd Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Thu, 8 Jun 2023 09:12:52 -0700 Subject: [PATCH 01/29] [AC-1437] Introduce Feature Flag route guard (#5465) * Add feature flag route guard and tests * Add additional test for not showing error toast * Strengthen error toast test with message check * Cleanup leaking test state in platformService mock * Negate if statement to reduce nesting * Update return type to CanActivateFn * Use null check instead of undefined * Introduce interface to support different feature flag types - Switch to observable pattern to access serverConfig$ subject - Add catchError handler to allow navigation in case of unexpected exception - Add additional tests * Add additional test for missing feature flag * Remove subscription to the serverConfig observable Introduce type checking logic to determine the appropriately typed flag getter to use in configService * Update the feature flag to fallback to blocking the route on an unexpected exception * Trigger test action * Fix imports after merge with master --- .../src/guard/feature-flag.guard.spec.ts | 152 ++++++++++++++++++ libs/angular/src/guard/feature-flag.guard.ts | 58 +++++++ 2 files changed, 210 insertions(+) create mode 100644 libs/angular/src/guard/feature-flag.guard.spec.ts create mode 100644 libs/angular/src/guard/feature-flag.guard.ts diff --git a/libs/angular/src/guard/feature-flag.guard.spec.ts b/libs/angular/src/guard/feature-flag.guard.spec.ts new file mode 100644 index 00000000000..bba879278ff --- /dev/null +++ b/libs/angular/src/guard/feature-flag.guard.spec.ts @@ -0,0 +1,152 @@ +import { Component } from "@angular/core"; +import { TestBed } from "@angular/core/testing"; +import { CanActivateFn, Router } from "@angular/router"; +import { RouterTestingModule } from "@angular/router/testing"; +import { mock, MockProxy } from "jest-mock-extended"; + +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; +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 { I18nMockService } from "@bitwarden/components/src"; + +import { canAccessFeature } from "./feature-flag.guard"; + +@Component({ template: "" }) +export class EmptyComponent {} + +describe("canAccessFeature", () => { + const testFlag: FeatureFlag = "test-flag" as FeatureFlag; + const featureRoute = "enabled-feature"; + const redirectRoute = "redirect"; + + let mockConfigService: MockProxy; + let mockPlatformUtilsService: MockProxy; + + const setup = (featureGuard: CanActivateFn, flagValue: any) => { + mockConfigService = mock(); + mockPlatformUtilsService = mock(); + + // Mock the correct getter based on the type of flagValue; also mock default values if one is not provided + if (typeof flagValue === "boolean") { + mockConfigService.getFeatureFlagBool.mockImplementation((flag, defaultValue = false) => + flag == testFlag ? Promise.resolve(flagValue) : Promise.resolve(defaultValue) + ); + } else if (typeof flagValue === "string") { + mockConfigService.getFeatureFlagString.mockImplementation((flag, defaultValue = "") => + flag == testFlag ? Promise.resolve(flagValue) : Promise.resolve(defaultValue) + ); + } else if (typeof flagValue === "number") { + mockConfigService.getFeatureFlagNumber.mockImplementation((flag, defaultValue = 0) => + flag == testFlag ? Promise.resolve(flagValue) : Promise.resolve(defaultValue) + ); + } + + const testBed = TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes([ + { path: "", component: EmptyComponent }, + { + path: featureRoute, + component: EmptyComponent, + canActivate: [featureGuard], + }, + { path: redirectRoute, component: EmptyComponent }, + ]), + ], + providers: [ + { provide: ConfigServiceAbstraction, useValue: mockConfigService }, + { provide: PlatformUtilsService, useValue: mockPlatformUtilsService }, + { provide: LogService, useValue: mock() }, + { + provide: I18nService, + useValue: new I18nMockService({ + accessDenied: "Access Denied!", + }), + }, + ], + }); + return { + router: testBed.inject(Router), + }; + }; + + it("successfully navigates when the feature flag is enabled", async () => { + const { router } = setup(canAccessFeature(testFlag), true); + + await router.navigate([featureRoute]); + + expect(router.url).toBe(`/${featureRoute}`); + }); + + it("successfully navigates when the feature flag value matches the required value", async () => { + const { router } = setup(canAccessFeature(testFlag, "some-value"), "some-value"); + + await router.navigate([featureRoute]); + + expect(router.url).toBe(`/${featureRoute}`); + }); + + it("fails to navigate when the feature flag is disabled", async () => { + const { router } = setup(canAccessFeature(testFlag), false); + + await router.navigate([featureRoute]); + + expect(router.url).toBe("/"); + }); + + it("fails to navigate when the feature flag value does not match the required value", async () => { + const { router } = setup(canAccessFeature(testFlag, "some-value"), "some-wrong-value"); + + await router.navigate([featureRoute]); + + expect(router.url).toBe("/"); + }); + + it("fails to navigate when the feature flag does not exist", async () => { + const { router } = setup(canAccessFeature("missing-flag" as FeatureFlag), true); + + await router.navigate([featureRoute]); + + expect(router.url).toBe("/"); + }); + + it("shows an error toast when the feature flag is disabled", async () => { + const { router } = setup(canAccessFeature(testFlag), false); + + await router.navigate([featureRoute]); + + expect(mockPlatformUtilsService.showToast).toHaveBeenCalledWith( + "error", + null, + "Access Denied!" + ); + }); + + it("does not show an error toast when the feature flag is enabled", async () => { + const { router } = setup(canAccessFeature(testFlag), true); + + await router.navigate([featureRoute]); + + expect(mockPlatformUtilsService.showToast).not.toHaveBeenCalled(); + }); + + it("redirects to the specified redirect url when the feature flag is disabled", async () => { + const { router } = setup(canAccessFeature(testFlag, true, redirectRoute), false); + + await router.navigate([featureRoute]); + + expect(router.url).toBe(`/${redirectRoute}`); + }); + + it("fails to navigate when the config service throws an unexpected exception", async () => { + const { router } = setup(canAccessFeature(testFlag), true); + + mockConfigService.getFeatureFlagBool.mockImplementation(() => Promise.reject("Some error")); + + await router.navigate([featureRoute]); + + expect(router.url).toBe("/"); + }); +}); diff --git a/libs/angular/src/guard/feature-flag.guard.ts b/libs/angular/src/guard/feature-flag.guard.ts new file mode 100644 index 00000000000..f4596f3cf4b --- /dev/null +++ b/libs/angular/src/guard/feature-flag.guard.ts @@ -0,0 +1,58 @@ +import { inject } from "@angular/core"; +import { CanActivateFn, Router } from "@angular/router"; + +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; +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"; + +// Replace this with a type safe lookup of the feature flag values in PM-2282 +type FlagValue = boolean | number | string; + +/** + * Returns a CanActivateFn that checks if the feature flag is enabled. If not, it shows an "Access Denied!" + * toast and optionally redirects to the specified url. + * @param featureFlag - The feature flag to check + * @param requiredFlagValue - Optional value to the feature flag must be equal to, defaults to true + * @param redirectUrlOnDisabled - Optional url to redirect to if the feature flag is disabled + */ +export const canAccessFeature = ( + featureFlag: FeatureFlag, + requiredFlagValue: FlagValue = true, + redirectUrlOnDisabled?: string +): CanActivateFn => { + return async () => { + const configService = inject(ConfigServiceAbstraction); + const platformUtilsService = inject(PlatformUtilsService); + const router = inject(Router); + const i18nService = inject(I18nService); + const logService = inject(LogService); + + let flagValue: FlagValue; + + try { + if (typeof requiredFlagValue === "boolean") { + flagValue = await configService.getFeatureFlagBool(featureFlag); + } else if (typeof requiredFlagValue === "number") { + flagValue = await configService.getFeatureFlagNumber(featureFlag); + } else if (typeof requiredFlagValue === "string") { + flagValue = await configService.getFeatureFlagString(featureFlag); + } + + if (flagValue === requiredFlagValue) { + return true; + } + + platformUtilsService.showToast("error", null, i18nService.t("accessDenied")); + + if (redirectUrlOnDisabled != null) { + return router.createUrlTree([redirectUrlOnDisabled]); + } + return false; + } catch (e) { + logService.error(e); + return false; + } + }; +}; From 109b74051ef44e94d9c01471ad361d79d8893e87 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:09:05 +0200 Subject: [PATCH 02/29] Autosync the updated translations (#5583) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 12 ++--- apps/browser/src/_locales/pt_PT/messages.json | 50 +++++++++---------- apps/browser/store/locales/pt_PT/copy.resx | 2 +- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 71cd3d1a66b..519115d2a81 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -1412,13 +1412,13 @@ "message": "استنساخ" }, "passwordGeneratorPolicyInEffect": { - "message": "One or more organization policies are affecting your generator settings." + "message": "واحدة أو أكثر من سياسات المؤسسة تؤثر على إعدادات المولدات الخاصة بك." }, "vaultTimeoutAction": { - "message": "Vault timeout action" + "message": "إجراء مهلة المخزن" }, "lock": { - "message": "Lock", + "message": "قفل", "description": "Verb form: to make secure or inaccesible by" }, "trash": { @@ -1426,7 +1426,7 @@ "description": "Noun: a special folder to hold deleted items" }, "searchTrash": { - "message": "Search trash" + "message": "البحث عن سلة المهملات" }, "permanentlyDeleteItem": { "message": "حذف العنصر بشكل دائم" @@ -1435,13 +1435,13 @@ "message": "هل أنت متأكد من أنك تريد حذف هذا العنصر بشكل دائم؟" }, "permanentlyDeletedItem": { - "message": "Item permanently deleted" + "message": "تم حذف العنصر بشكل دائم" }, "restoreItem": { "message": "استعادة العنصر" }, "restoreItemConfirmation": { - "message": "Are you sure you want to restore this item?" + "message": "هل أنت متأكد من أنك تريد استعادة هذا العنصر؟" }, "restoredItem": { "message": "Item restored" diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index abb193ecbab..06474f83c48 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -98,7 +98,7 @@ "message": "Copiar nome do campo personalizado" }, "noMatchingLogins": { - "message": "Sem inícios de sessão correspondentes" + "message": "Sem credenciais correspondentes" }, "unlockVaultMenu": { "message": "Desbloqueie o seu cofre" @@ -107,10 +107,10 @@ "message": "Inicie sessão para abrir o seu cofre" }, "autoFillInfo": { - "message": "Não existem inícios de sessão disponíveis para preenchimento automático no separador atual do navegador." + "message": "Não existem credenciais disponíveis para preenchimento automático no separador atual do navegador." }, "addLogin": { - "message": "Adicionar um início de sessão" + "message": "Adicionar uma credencial" }, "addItem": { "message": "Adicionar item" @@ -221,7 +221,7 @@ "description": "Short for 'Password Generator'." }, "passGenInfo": { - "message": "Gera automaticamente palavras-passe fortes e únicas para os seus inícios de sessão." + "message": "Gera automaticamente palavras-passe fortes e únicas para as suas credenciais." }, "bitWebVault": { "message": "Cofre web Bitwarden" @@ -415,7 +415,7 @@ "message": "No bloqueio do sistema" }, "onRestart": { - "message": "Ao reiniciar o sistema" + "message": "Ao reiniciar o navegador" }, "never": { "message": "Nunca" @@ -583,7 +583,7 @@ "message": "Procurar no tipo" }, "noneFolder": { - "message": "Em nenhuma pasta", + "message": "Sem pasta", "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { @@ -641,7 +641,7 @@ "description": "Default URI match detection for auto-fill." }, "defaultUriMatchDetectionDesc": { - "message": "Escolha a forma predefinida como a deteção de correspondência de URI é tratada para inícios de sessão ao executar ações como o preenchimento automático." + "message": "Escolha a forma predefinida como a deteção de correspondência de URI é tratada para credenciais ao executar ações como o preenchimento automático." }, "theme": { "message": "Tema" @@ -793,7 +793,7 @@ "message": "Higiene de palavras-passe, saúde da conta e relatórios de violação de dados para manter o seu cofre seguro." }, "ppremiumSignUpTotp": { - "message": "Gerador de código de verificação TOTP (2FA) para inícios de sessão no seu cofre." + "message": "Gerador de códigos de verificação TOTP (2FA) para credenciais no seu cofre." }, "ppremiumSignUpSupport": { "message": "Prioridade no apoio ao cliente." @@ -829,7 +829,7 @@ "message": "Copy TOTP automatically" }, "disableAutoTotpCopyDesc": { - "message": "Se um início de sessão tiver uma chave de autenticação, copie o código de verificação TOTP para a sua área de transferência quando preencher automaticamente o início de sessão." + "message": "Se uma credencial tiver uma chave de autenticação, copie o código de verificação TOTP para a sua área de transferência quando preencher automaticamente o início de sessão." }, "enableAutoBiometricsPrompt": { "message": "Ask for biometrics on launch" @@ -865,7 +865,7 @@ "message": "Memorizar-me" }, "sendVerificationCodeEmailAgain": { - "message": "Enviar código de verificação novamente" + "message": "Enviar e-mail com o código de verificação novamente" }, "useAnotherTwoStepMethod": { "message": "Utilizar outro método de verificação de dois passos" @@ -892,7 +892,7 @@ "message": "Esta conta tem a verificação de dois passos configurada, no entanto, nenhum dos fornecedores da verificação de dois passos configurada é suportado por este navegador web." }, "noTwoStepProviders2": { - "message": "Utilize um navegador web suportado (como o Chrome) e/ou adicione fornecedores adicionais que sejam mais bem suportados nos navegadores web (como uma aplicação de autenticação)." + "message": "Por favor, utilize um navegador web suportado (como o Chrome) e/ou adicione fornecedores adicionais que sejam mais bem suportados nos navegadores web (como uma aplicação de autenticação)." }, "twoStepOptions": { "message": "Opções de verificação de dois passos" @@ -1146,7 +1146,7 @@ "message": "Mx" }, "firstName": { - "message": "Primeiro nome" + "message": "Nome próprio" }, "middleName": { "message": "Segundo nome" @@ -1179,16 +1179,16 @@ "message": "Telefone" }, "address": { - "message": "Morada" + "message": "Endereço" }, "address1": { - "message": "1.ª morada" + "message": "Endereço 1" }, "address2": { - "message": "2.ª morada" + "message": "Endereço 2" }, "address3": { - "message": "3.ª morada" + "message": "Endereço 3" }, "cityTown": { "message": "Cidade / Localidade" @@ -1206,10 +1206,10 @@ "message": "Tipo" }, "typeLogin": { - "message": "Início de sessão" + "message": "Credencial" }, "typeLogins": { - "message": "Inícios de sessão" + "message": "Credenciais" }, "typeSecureNote": { "message": "Nota segura" @@ -1245,7 +1245,7 @@ "message": "Identidades" }, "logins": { - "message": "Inícios de sessão" + "message": "Credenciais" }, "secureNotes": { "message": "Notas seguras" @@ -1406,10 +1406,10 @@ "message": "Deve selecionar pelo menos uma coleção." }, "cloneItem": { - "message": "Clonar item" + "message": "Duplicar item" }, "clone": { - "message": "Clonar" + "message": "Duplicar" }, "passwordGeneratorPolicyInEffect": { "message": "Uma ou mais políticas da organização estão a afetar as suas definições do gerador." @@ -1432,7 +1432,7 @@ "message": "Eliminar item permanentemente" }, "permanentlyDeleteItemConfirmation": { - "message": "Tem a certeza de que pretende eliminar este item permanentemente?" + "message": "Tem a certeza de que pretende eliminar permanentemente este item?" }, "permanentlyDeletedItem": { "message": "Item eliminado permanentemente" @@ -1799,7 +1799,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Send saved", + "message": "Send editado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { @@ -1869,10 +1869,10 @@ "message": "Atualizar palavra-passe mestra" }, "updateMasterPasswordWarning": { - "message": "A sua palavra-passe mestra foi recentemente alterada por um administrador da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra foi recentemente alterada por um administrador da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "updateWeakMasterPasswordWarning": { - "message": "A sua palavra-passe mestra não cumpre uma ou mais políticas da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra não cumpre uma ou mais políticas da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "resetPasswordPolicyAutoEnroll": { "message": "Inscrição automática" diff --git a/apps/browser/store/locales/pt_PT/copy.resx b/apps/browser/store/locales/pt_PT/copy.resx index df8db70e3ee..199b5e9810a 100644 --- a/apps/browser/store/locales/pt_PT/copy.resx +++ b/apps/browser/store/locales/pt_PT/copy.resx @@ -158,7 +158,7 @@ Secure and share sensitive data within your Bitwarden Vault from any browser, mo Sincronize e aceda ao seu cofre através de vários dispositivos - Gira todos os seus inícios de sessão e palavras-passe a partir de um cofre seguro + Gira todas as suas credenciais e palavras-passe a partir de um cofre seguro Preencha rapidamente e de forma automática as suas credenciais de início de sessão em qualquer site que visite From 48128c8a2e3550980d960e0af37d4b327c0ddf67 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:09:35 +0200 Subject: [PATCH 03/29] Autosync the updated translations (#5582) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/ar/messages.json | 8 +-- apps/desktop/src/locales/be/messages.json | 8 +-- apps/desktop/src/locales/pt_PT/messages.json | 52 ++++++++++---------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 7e558adc15e..e4ff6a202b2 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -2253,17 +2253,17 @@ "message": "تحديث الإعدادات الموصى بها" }, "region": { - "message": "Region" + "message": "المنطقة" }, "eu": { - "message": "EU", + "message": "الاتحاد الأوروبي", "description": "European Union" }, "us": { - "message": "US", + "message": "الولايات المتحدة", "description": "United States" }, "selfHosted": { - "message": "Self-hosted" + "message": "استضافة ذاتية" } } diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index efd52d6444f..3d4d8221684 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -2253,17 +2253,17 @@ "message": "Рэкамендаваныя налады абнаўлення" }, "region": { - "message": "Region" + "message": "Рэгіён" }, "eu": { - "message": "EU", + "message": "ЕС", "description": "European Union" }, "us": { - "message": "US", + "message": "ЗША", "description": "United States" }, "selfHosted": { - "message": "Self-hosted" + "message": "Уласнае размяшчэнне" } } diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 13e57dda795..fde7d53d0fc 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -15,7 +15,7 @@ "message": "Tipos" }, "typeLogin": { - "message": "Início de sessão" + "message": "Credencial" }, "typeCard": { "message": "Cartão" @@ -61,7 +61,7 @@ } }, "moveToOrgDesc": { - "message": "Escolha uma organização para a qual pretende mover este item. Mover para uma organização transfere a propriedade do item para essa organização. Deixará de ser o proprietário directo deste item depois de este ter sido movido." + "message": "Escolha uma organização para a qual pretende mover este item. Mover para uma organização transfere a propriedade do item para essa organização. Deixará de ser o proprietário direto deste item depois de este ter sido movido." }, "attachments": { "message": "Anexos" @@ -172,7 +172,7 @@ "message": "Telefone" }, "address": { - "message": "Morada" + "message": "Endereço" }, "premiumRequired": { "message": "É necessária uma subscrição Premium" @@ -263,7 +263,7 @@ "message": "Tipo" }, "firstName": { - "message": "Primeiro nome" + "message": "Nome próprio" }, "middleName": { "message": "Segundo nome" @@ -275,13 +275,13 @@ "message": "Nome completo" }, "address1": { - "message": "1.ª morada" + "message": "Endereço 1" }, "address2": { - "message": "2.ª morada" + "message": "Endereço 2" }, "address3": { - "message": "3.ª morada" + "message": "Endereço 3" }, "cityTown": { "message": "Cidade / Localidade" @@ -379,7 +379,7 @@ "message": "Tem a certeza de que pretende substituir o nome de utilizador atual?" }, "noneFolder": { - "message": "Em nenhuma pasta", + "message": "Sem pasta", "description": "This is the folder for uncategorized items" }, "addFolder": { @@ -398,7 +398,7 @@ "message": "Copiar URI" }, "copyVerificationCodeTotp": { - "message": "Copy verification code (TOTP)" + "message": "Copiar código de verificação (TOTP)" }, "length": { "message": "Comprimento" @@ -618,7 +618,7 @@ "message": "Memorizar-me" }, "sendVerificationCodeEmailAgain": { - "message": "Enviar código de verificação novamente" + "message": "Enviar e-mail com o código de verificação novamente" }, "useAnotherTwoStepMethod": { "message": "Utilizar outro método de verificação de dois passos" @@ -744,7 +744,7 @@ "message": "Terminar sessão" }, "addNewLogin": { - "message": "Novo início de sessão" + "message": "Nova credencial" }, "addNewItem": { "message": "Novo item" @@ -771,7 +771,7 @@ "message": "Contacte-nos" }, "helpAndFeedback": { - "message": "Help and feedback" + "message": "Ajuda e feedback" }, "getHelp": { "message": "Obter ajuda" @@ -1423,19 +1423,19 @@ "message": "Bloquear com a palavra-passe mestra ao reiniciar" }, "deleteAccount": { - "message": "Delete account" + "message": "Eliminar conta" }, "deleteAccountDesc": { - "message": "Proceed below to delete your account and all vault data." + "message": "Proceda da seguinte forma para eliminar a sua conta e todos os dados do cofre." }, "deleteAccountWarning": { - "message": "Deleting your account is permanent. It cannot be undone." + "message": "A eliminação da sua conta é permanente. Não pode ser desfeita." }, "accountDeleted": { - "message": "Account deleted" + "message": "Conta eliminada" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "A sua conta foi encerrada e todos os dados associados foram eliminados." }, "preferences": { "message": "Preferências" @@ -1478,7 +1478,7 @@ "message": "Alterações por guardar" }, "clone": { - "message": "Clonar" + "message": "Duplicar" }, "passwordGeneratorPolicyInEffect": { "message": "Uma ou mais políticas da organização estão a afetar as suas definições do gerador." @@ -1507,7 +1507,7 @@ "message": "Eliminar item permanentemente" }, "permanentlyDeleteItemConfirmation": { - "message": "Tem a certeza de que pretende eliminar este item permanentemente?" + "message": "Tem a certeza de que pretende eliminar permanentemente este item?" }, "permanentlyDeletedItem": { "message": "Item eliminado permanentemente" @@ -1739,15 +1739,15 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { - "message": "Send added", + "message": "Send criado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Send saved", + "message": "Send editado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deletedSend": { - "message": "Send deleted", + "message": "Send eliminado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { @@ -1856,10 +1856,10 @@ "message": "Atualizar palavra-passe mestra" }, "updateMasterPasswordWarning": { - "message": "A sua palavra-passe mestra foi recentemente alterada por um administrador da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra foi recentemente alterada por um administrador da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "updateWeakMasterPasswordWarning": { - "message": "A sua palavra-passe mestra não cumpre uma ou mais políticas da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra não cumpre uma ou mais políticas da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "hours": { "message": "Horas" @@ -2040,7 +2040,7 @@ "message": "Random word" }, "websiteName": { - "message": "Website name" + "message": "Nome do site" }, "service": { "message": "Service" @@ -2153,7 +2153,7 @@ "message": "Device Type" }, "ipAddress": { - "message": "IP Address" + "message": "Endereço IP" }, "time": { "message": "Time" From 57cc3f4acd87707dacb4810369938694446f9df6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:23:20 +0200 Subject: [PATCH 04/29] Autosync the updated translations (#5584) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 11 +- apps/web/src/locales/ar/messages.json | 11 +- apps/web/src/locales/az/messages.json | 11 +- apps/web/src/locales/be/messages.json | 41 +- apps/web/src/locales/bg/messages.json | 11 +- apps/web/src/locales/bn/messages.json | 11 +- apps/web/src/locales/bs/messages.json | 11 +- apps/web/src/locales/ca/messages.json | 11 +- apps/web/src/locales/cs/messages.json | 11 +- apps/web/src/locales/cy/messages.json | 11 +- apps/web/src/locales/da/messages.json | 11 +- apps/web/src/locales/de/messages.json | 11 +- apps/web/src/locales/el/messages.json | 11 +- apps/web/src/locales/en_GB/messages.json | 11 +- apps/web/src/locales/en_IN/messages.json | 11 +- apps/web/src/locales/eo/messages.json | 11 +- apps/web/src/locales/es/messages.json | 11 +- apps/web/src/locales/et/messages.json | 11 +- apps/web/src/locales/eu/messages.json | 11 +- apps/web/src/locales/fa/messages.json | 11 +- apps/web/src/locales/fi/messages.json | 11 +- apps/web/src/locales/fil/messages.json | 11 +- apps/web/src/locales/fr/messages.json | 11 +- apps/web/src/locales/gl/messages.json | 11 +- apps/web/src/locales/he/messages.json | 11 +- apps/web/src/locales/hi/messages.json | 11 +- apps/web/src/locales/hr/messages.json | 11 +- apps/web/src/locales/hu/messages.json | 11 +- apps/web/src/locales/id/messages.json | 11 +- apps/web/src/locales/it/messages.json | 37 +- apps/web/src/locales/ja/messages.json | 11 +- apps/web/src/locales/ka/messages.json | 11 +- apps/web/src/locales/km/messages.json | 11 +- apps/web/src/locales/kn/messages.json | 11 +- apps/web/src/locales/ko/messages.json | 11 +- apps/web/src/locales/lv/messages.json | 11 +- apps/web/src/locales/ml/messages.json | 11 +- apps/web/src/locales/my/messages.json | 11 +- apps/web/src/locales/nb/messages.json | 11 +- apps/web/src/locales/ne/messages.json | 11 +- apps/web/src/locales/nl/messages.json | 11 +- apps/web/src/locales/nn/messages.json | 11 +- apps/web/src/locales/or/messages.json | 11 +- apps/web/src/locales/pl/messages.json | 11 +- apps/web/src/locales/pt_BR/messages.json | 11 +- apps/web/src/locales/pt_PT/messages.json | 817 ++++++++++++----------- apps/web/src/locales/ro/messages.json | 11 +- apps/web/src/locales/ru/messages.json | 39 +- apps/web/src/locales/si/messages.json | 11 +- apps/web/src/locales/sk/messages.json | 11 +- apps/web/src/locales/sl/messages.json | 11 +- apps/web/src/locales/sr/messages.json | 11 +- apps/web/src/locales/sr_CS/messages.json | 11 +- apps/web/src/locales/sv/messages.json | 11 +- apps/web/src/locales/te/messages.json | 11 +- apps/web/src/locales/th/messages.json | 11 +- apps/web/src/locales/tr/messages.json | 11 +- apps/web/src/locales/uk/messages.json | 11 +- apps/web/src/locales/vi/messages.json | 11 +- apps/web/src/locales/zh_CN/messages.json | 11 +- apps/web/src/locales/zh_TW/messages.json | 11 +- 61 files changed, 1055 insertions(+), 506 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index ff0c6b00573..23d2b02c024 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index ac093d7a8ef..050c10195c1 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index ebf1c08bec1..39faf0806a3 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "Bu seçim istifadə edildikdə avto-qeydiyyat ilə işə salınacaq.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ tapılmadı", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Hesabı bərpa et" diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index a7d5aa376e4..87b82e5ea69 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -4493,13 +4493,13 @@ "message": "Падказка для пароля не можа супадаць з паролем." }, "enrollAccountRecovery": { - "message": "Enroll in account recovery" + "message": "Зарэгістравацца на аднаўленне ўліковага запісу" }, "enrolledAccountRecovery": { - "message": "Enrolled in account recovery" + "message": "Зарэгістравацца на аднаўленне ўліковага запісу" }, "withdrawAccountRecovery": { - "message": "Withdraw from account recovery" + "message": "Адклікаць аднаўленне ўліковага запісу" }, "enrollPasswordResetSuccess": { "message": "Паспяховая рэгістрацыя!" @@ -4508,7 +4508,7 @@ "message": "Адмова паспяхова ўжыта!" }, "eventEnrollAccountRecovery": { - "message": "User $ID$ enrolled in account recovery.", + "message": "Карыстальнік $ID$ зарэгістраваўся на аднаўленне ўліковага запісу.", "placeholders": { "id": { "content": "$1", @@ -4517,7 +4517,7 @@ } }, "eventWithdrawAccountRecovery": { - "message": "User $ID$ withdrew from account recovery.", + "message": "Карыстальнік $ID$ адклікаў аднаўленне ўліковага запісу.", "placeholders": { "id": { "content": "$1", @@ -4577,10 +4577,10 @@ "message": "Рэгістрацыя дазволіць адміністратарам арганізацыі змяняць ваш асноўны пароль" }, "accountRecoveryPolicy": { - "message": "Account recovery administration" + "message": "Адміністраванне аднаўлення ўліковага запісу" }, "accountRecoveryPolicyDescription": { - "message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method." + "message": "Аднаўленне ўліковага запісу ўдзельніка, калі асноўны пароль забыты або давераная прылада страчана. Працэс аднаўлення заснаваны на метадзе шыфравання ўліковага запісу." }, "resetPasswordPolicyWarning": { "message": "Карыстальнікі арганізацыі павінны зарэгістравацца самастойна або быць зарэгістраванымі аўтаматычна, каб адміністратары маглі скінуць іх асноўны пароль." @@ -5231,11 +5231,11 @@ "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Connect login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their master passwords to decrypt vault data. The require SSO authentication and single organization policies are required to set up Key Connector decryption. Contact Bitwarden Support for set up assistance.'" }, "memberDecryptionKeyConnectorDescLink": { - "message": "Для наладжвання расшыфроўкі Key Connector патрабуецца аўтэнтыфікацыя SSO", + "message": "Патрабуецца аўтэнтыфікацыя SSO і палітыкі адзінай арганізацыі", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Connect login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their master passwords to decrypt vault data. The require SSO authentication and single organization policies are required to set up Key Connector decryption. Contact Bitwarden Support for set up assistance.'" }, "memberDecryptionKeyConnectorDescEnd": { - "message": "are required to set up Key Connector decryption. Contact Bitwarden Support for set up assistance.", + "message": "для наладжвання шыфравання з дапамогай Key Connector. Звярніцеся ў службу падтрымкі Bitwarden, каб атрымаць дапамогу пры наладжванні.", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Connect login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their master passwords to decrypt vault data. The require SSO authentication and single organization policies are required to set up Key Connector decryption. Contact Bitwarden Support for set up assistance.'" }, "keyConnectorPolicyRestriction": { @@ -6776,7 +6776,7 @@ } }, "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." }, "dismiss": { @@ -6793,7 +6793,7 @@ "message": "Патрабаваць ад існуючых удзельнікаў змены пароляў" }, "region": { - "message": "Region" + "message": "Рэгіён" }, "eu": { "message": "ЕС", @@ -6822,17 +6822,26 @@ "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionTdeDescriptionLink": { - "message": "account recovery administration 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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionTdeDescriptionEnd": { - "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration 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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ не знойдзены", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { - "message": "Recover account" + "message": "Аднавіць уліковы запіс" }, "updatedTempPassword": { - "message": "User updated a password issued through account recovery." + "message": "Карыстальнік абнавіў пароль пры аднаўленні ўліковага запісу." } } diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index ea8c19f598a..ad960a9915d 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "Няма намерен $RESOURCE$", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Възстановяване на профила" diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index 65ad3e657dd..075c6717d5f 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 76f7d77f7e2..15caf7c5352 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 45d0419ce87..f1b140dd2c0 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "amb inscripció automàtica s'activarà quan s'utilitze aquesta opció.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "No s'ha trobat $RESOURCE$", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recupera el compte" diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index cf40e3aa982..7a2eee2c14f 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "budou použity zásady obnovení účtu s automatickým zápisem.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ nebyl nalezen", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Obnovit účet" diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index dd62b4d4a3b..7595e610b1a 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index ca561401096..48432de1a73 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "med automatisk indrullering aktiveres ved brug af denne indstilling.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ ikke fundet", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Gendan konto" diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 517e3471a9e..614a34b02e5 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "mit automatischer Registrierung wird aktiviert, wenn diese Option verwendet wird.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ nicht gefunden", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Konto wiederherstellen" diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index a80a770d666..f3066236705 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index fceab3da98b..d83c8086090 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 252dbac7139..97d57c86b78 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index d260b90c71b..6b33860e04f 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index bf306eeac75..c265a165d43 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ no encontrado", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recuperar cuenta" diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 844f0962eb4..a9d5dc71807 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index d85626fb323..e9f83043ec6 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index c9bf21478f8..a0788ccc87f 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index cb33045e44d..861ed165129 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "automaattisella liitoksella otetaan tämän asetuksen yhteydessä käyttöön.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ ei löytynyt", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Palauta tili" diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index 590fc37578a..7dc03130dd0 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index 54a9dd1b000..8696bdb08a5 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "par inscription automatique s'active lorsque cette option est utilisée.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ introuvable", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Récupérer le compte" diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index dd62b4d4a3b..7595e610b1a 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index fbea7c75944..19696d8fe16 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 03d30612488..02913eecf51 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 403f7ba0e63..107ef8398a6 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index 1a370bc0e17..eb326f55a29 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "automatikus regisztrációval bekapcsol, ha ez az opció van használatban.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ nem található.", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Fiók helyreállítás" diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 85c7748b0ff..d1aadca4830 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index bebe2370869..781acee518c 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -4493,13 +4493,13 @@ "message": "Il suggerimento per la password non può essere uguale alla tua password." }, "enrollAccountRecovery": { - "message": "Enroll in account recovery" + "message": "Iscriviti al recupero dell'account" }, "enrolledAccountRecovery": { - "message": "Enrolled in account recovery" + "message": "Iscritto al recupero dell'account" }, "withdrawAccountRecovery": { - "message": "Withdraw from account recovery" + "message": "Rifiuta il recupero dell'account" }, "enrollPasswordResetSuccess": { "message": "Iscrizione riuscita!" @@ -4508,7 +4508,7 @@ "message": "Rinuncia riuscita!" }, "eventEnrollAccountRecovery": { - "message": "User $ID$ enrolled in account recovery.", + "message": "Utente $ID$ si è iscritto al recupero dell'account.", "placeholders": { "id": { "content": "$1", @@ -4517,7 +4517,7 @@ } }, "eventWithdrawAccountRecovery": { - "message": "User $ID$ withdrew from account recovery.", + "message": "Utente $ID$ ha rifiutato il recupero dell'account.", "placeholders": { "id": { "content": "$1", @@ -4577,10 +4577,10 @@ "message": "Iscriversi consentirà agli amministratori dell'organizzazione di cambiare la tua password principale" }, "accountRecoveryPolicy": { - "message": "Account recovery administration" + "message": "Amministrazione del recupero dell'account" }, "accountRecoveryPolicyDescription": { - "message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method." + "message": "Recupera gli account dei membri quando la password principale o i dispositivi fidati sono dimenticati o persi. I processi di recupero sono basati sul metodo di criptografia dell'account." }, "resetPasswordPolicyWarning": { "message": "I membri dell'organizzazione dovranno iscriversi o essere iscritti automaticamente prima che gli amministratori possano ripristinare la loro password principale." @@ -6776,7 +6776,7 @@ } }, "inputTrimValidator": { - "message": "Input must not contain only whitespace.", + "message": "L'input non deve contenere solo spazi.", "description": "Notification to inform the user that a form's input can't contain only whitespace." }, "dismiss": { @@ -6818,21 +6818,30 @@ "message": "Criptografia dispositivo fidato" }, "memberDecryptionTdeDescriptionStart": { - "message": "Once authenticated, members will decrypt vault data using a key stored on their device. The", + "message": "Una volta autenticati, i membri decriptograferanno i dati della cassaforte usando una chiave memorizzata sul proprio dispositivo. La", "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionTdeDescriptionLink": { - "message": "account recovery administration policy", + "message": "politica di amministrazione del recupero dell'account", "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionTdeDescriptionEnd": { - "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "message": "con registrazione automatica si attiverà quando questa opzione è usata.", + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ non trovato", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { - "message": "Recover account" + "message": "Recupera account" }, "updatedTempPassword": { - "message": "User updated a password issued through account recovery." + "message": "L'utente ha aggiornato una password emessa tramite il recupero dell'account." } } diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 245f98b9619..5ee525b8e28 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ が見つかりません", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "アカウント回復" diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 0a592ddc986..5e7369c3e0f 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index dd62b4d4a3b..7595e610b1a 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 05aac870602..e330147c5c3 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 18ac87d7b03..3e0ce79be9b 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index cdcb5457bfd..179fbc6c06d 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "ar automātisku ievietošanu sarakstā tiks ieslēgts, kad šī iespēja tiek izmantota.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ netika atrasts", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Atkopt kontu" diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 8f6e77449bd..78817866d29 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index dd62b4d4a3b..7595e610b1a 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 3643facf387..eb63814dc60 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 8dd7892f58a..00b22a5f77b 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 614f1921b69..9588f81390f 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "in met automatische inschrijving wanneer deze optie wordt gebruikt.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Account herstellen" diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 3f849590eb5..34eb407911c 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index dd62b4d4a3b..7595e610b1a 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 5618ee0a096..271175c1c20 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "z automatycznym zapisem włączy się, gdy ta opcja jest używana.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ nie znaleziony", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Odzyskaj konto" diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 80bea39bbd1..6644a96c823 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ não encontrado", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 8d323419635..b127e71e201 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -50,7 +50,7 @@ "message": "Campos personalizados" }, "cardholderName": { - "message": "Titular do Cartão" + "message": "Titular do cartão" }, "number": { "message": "Número" @@ -140,13 +140,13 @@ "message": "Dr." }, "expirationMonth": { - "message": "Mês de expiração" + "message": "Mês de validade" }, "expirationYear": { - "message": "Ano de expiração" + "message": "Ano de validade" }, "authenticatorKeyTotp": { - "message": "Chave do autenticador (TOTP)" + "message": "Chave de autenticação (TOTP)" }, "folder": { "message": "Pasta" @@ -170,7 +170,7 @@ "message": "Booleano" }, "cfTypeLinked": { - "message": "Ligado", + "message": "Associado", "description": "This describes a field that is 'linked' (related) to another field." }, "remove": { @@ -180,7 +180,7 @@ "message": "Não atribuído" }, "noneFolder": { - "message": "Em nenhuma pasta", + "message": "Sem pasta", "description": "This is the folder for uncategorized items" }, "addFolder": { @@ -194,7 +194,7 @@ "description": "Domain name. Example: website.com" }, "domainName": { - "message": "Nome do Domínio", + "message": "Nome do domínio", "description": "Domain name. Example: website.com" }, "host": { @@ -272,10 +272,10 @@ "message": "Editar" }, "searchCollection": { - "message": "Pesquisar Coleção" + "message": "Procurar na coleção" }, "searchFolder": { - "message": "Pesquisar Pasta" + "message": "Procurar na pasta" }, "searchFavorites": { "message": "Procurar nos favoritos" @@ -321,7 +321,7 @@ "message": "Tipos" }, "typeLogin": { - "message": "Início de sessão" + "message": "Credencial" }, "typeCard": { "message": "Cartão" @@ -351,7 +351,7 @@ "message": "Coleções" }, "firstName": { - "message": "Nome Próprio" + "message": "Nome próprio" }, "middleName": { "message": "Segundo nome" @@ -363,13 +363,13 @@ "message": "Nome completo" }, "address1": { - "message": "1.ª morada" + "message": "Endereço 1" }, "address2": { - "message": "2.ª morada" + "message": "Endereço 2" }, "address3": { - "message": "3.ª morada" + "message": "Endereço 3" }, "cityTown": { "message": "Cidade / Localidade" @@ -422,7 +422,7 @@ "message": "Partilhar" }, "moveToOrganization": { - "message": "Mover para organização" + "message": "Mover para a organização" }, "valueCopied": { "message": "$VALUE$ copiado(a)", @@ -465,7 +465,7 @@ "message": "O meu cofre" }, "allVaults": { - "message": "Todos os Cofres" + "message": "Todos os cofres" }, "vault": { "message": "Cofre" @@ -474,7 +474,7 @@ "message": "Cofres" }, "vaultItems": { - "message": "Itens do Cofre" + "message": "Itens do cofre" }, "filter": { "message": "Filter" @@ -483,16 +483,16 @@ "message": "Mover selecionados para a organização" }, "deleteSelected": { - "message": "Eliminar seleção" + "message": "Eliminar selecionados" }, "moveSelected": { - "message": "Mover seleção" + "message": "Mover selecionados" }, "selectAll": { "message": "Selecionar tudo" }, "unselectAll": { - "message": "Desfazer seleção" + "message": "Desmarcar tudo" }, "launch": { "message": "Iniciar" @@ -507,7 +507,7 @@ "message": "Tem a certeza de que pretende eliminar este anexo?" }, "attachmentSaved": { - "message": "O anexo foi guardado." + "message": "Anexo guardado" }, "file": { "message": "Ficheiro" @@ -525,7 +525,7 @@ "message": "Item adicionado" }, "editedItem": { - "message": "Item alterado" + "message": "Item guardado" }, "movedItemToOrg": { "message": "$ITEMNAME$ movido para $ORGNAME$", @@ -565,7 +565,7 @@ "message": "Item movido para o lixo" }, "deletedItems": { - "message": "Item movido para o lixo" + "message": "Itens movidos para o lixo" }, "movedItems": { "message": "Itens movidos" @@ -574,7 +574,7 @@ "message": "Tem a certeza de que pretende substituir a palavra-passe atual?" }, "editedFolder": { - "message": "Pasta alterada" + "message": "Pasta guardada" }, "addedFolder": { "message": "Pasta adicionada" @@ -631,7 +631,7 @@ "message": "É novo por cá?" }, "startTrial": { - "message": "Iniciar avaliação" + "message": "Iniciar período experimental" }, "logIn": { "message": "Iniciar sessão" @@ -664,7 +664,7 @@ "message": "Uma dica da palavra-passe mestra pode ajudá-lo a lembrar-se da sua palavra-passe, caso se esqueça dela." }, "reTypeMasterPass": { - "message": "Reescreva a palavra-passe mestra" + "message": "Reintroduza a palavra-passe mestra" }, "masterPassHint": { "message": "Dica da palavra-passe mestra (opcional)" @@ -679,16 +679,16 @@ "message": "Dica da palavra-passe" }, "enterEmailToGetHint": { - "message": "Introduza o endereço de email da sua conta para receber a dica da sua palavra-passe mestra." + "message": "Introduza o endereço de e-mail da sua conta para receber a dica da sua palavra-passe mestra." }, "getMasterPasswordHint": { "message": "Obter dica da palavra-passe mestra" }, "emailRequired": { - "message": "O endereço de email é requerido." + "message": "É necessário o endereço de e-mail." }, "invalidEmail": { - "message": "Endereço de email inválido." + "message": "Endereço de e-mail inválido." }, "masterPasswordRequired": { "message": "É necessária a palavra-passe mestra." @@ -710,19 +710,19 @@ "message": "A confirmação da palavra-passe mestra não corresponde." }, "newAccountCreated": { - "message": "A sua nova conta foi criada! Agora pode iniciar sessão." + "message": "A sua nova conta foi criada! Pode agora iniciar sessão." }, "trialAccountCreated": { "message": "Conta criada com sucesso." }, "masterPassSent": { - "message": "Enviámos-lhe um email com a dica da sua palavra-passe mestra." + "message": "Enviámos-lhe um e-mail com a dica da sua palavra-passe mestra." }, "unexpectedError": { "message": "Ocorreu um erro inesperado." }, "emailAddress": { - "message": "Endereço de email" + "message": "Endereço de e-mail" }, "yourVaultIsLocked": { "message": "O seu cofre está bloqueado. Verifique a sua palavra-passe mestra para continuar." @@ -747,7 +747,7 @@ "message": "Palavra-passe mestra inválida" }, "invalidFilePassword": { - "message": "Senha do ficheiro inválida, por favor use a senha que definiu quando criou o arquivo de exportação." + "message": "Palavra-passe de ficheiro inválida, utilize a palavra-passe que introduziu quando criou o ficheiro de exportação." }, "lockNow": { "message": "Bloquear agora" @@ -792,10 +792,10 @@ } }, "enterVerificationCodeApp": { - "message": "Introduza o código de verificação de 6 dígitos da sua aplicação de autenticador." + "message": "Introduza o código de verificação de 6 dígitos da sua aplicação de autenticação." }, "enterVerificationCodeEmail": { - "message": "Introduza o código de verificação de 6 dígitos que foi enviado por email para $EMAIL$.", + "message": "Introduza o código de verificação de 6 dígitos que foi enviado por e-mail para $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -804,7 +804,7 @@ } }, "verificationCodeEmailSent": { - "message": "Email de verificação enviado para $EMAIL$.", + "message": "E-mail de verificação enviado para $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -816,7 +816,7 @@ "message": "Memorizar-me" }, "sendVerificationCodeEmailAgain": { - "message": "Enviar email com o código de confirmação novamente" + "message": "Enviar e-mail com o código de verificação novamente" }, "useAnotherTwoStepMethod": { "message": "Utilizar outro método de verificação de dois passos" @@ -834,22 +834,22 @@ "message": "Esta conta tem a verificação de dois passos configurada, no entanto, nenhum dos fornecedores da verificação de dois passos configurada é suportado por este navegador web." }, "noTwoStepProviders2": { - "message": "Por favor utilize um navegador web suportado (tal como o Chrome) e/ou adicione provedores adicionais que são melhor suportados entre navegadores web (tal como uma aplicação de autenticador)." + "message": "Por favor, utilize um navegador web suportado (como o Chrome) e/ou adicione fornecedores adicionais que sejam mais bem suportados nos navegadores web (como uma aplicação de autenticação)." }, "twoStepOptions": { "message": "Opções de verificação de dois passos" }, "recoveryCodeDesc": { - "message": "Perdeu o acesso a todos os seus provedores de dois passos? Utilize o seu código de recuperação para desativar todos os provedores de dois passos da sua conta." + "message": "Perdeu o acesso a todos os seus fornecedores de verificação de dois passos? Utilize o seu código de recuperação para desativar todos os fornecedores de verificação de dois passos da sua conta." }, "recoveryCodeTitle": { "message": "Código de recuperação" }, "authenticatorAppTitle": { - "message": "Aplicação de autenticador" + "message": "Aplicação de autenticação" }, "authenticatorAppDesc": { - "message": "Utilize uma aplicação de autenticador (tal como Authy ou Google Authenticator) para gerar códigos de verificação baseados na hora.", + "message": "Utilize uma aplicação de autenticação (como o Authy ou o Google Authenticator) para gerar códigos de verificação baseados no tempo.", "description": "'Authy' and 'Google Authenticator' are product names and should not be translated." }, "yubiKeyTitle": { @@ -867,7 +867,7 @@ "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "u2fDesc": { - "message": "Utilize qualquer chave de segurança ativada por FIDO U2F para aceder à sua conta." + "message": "Utilize qualquer chave de segurança compatível com o FIDO U2F para aceder à sua conta." }, "u2fTitle": { "message": "Chave de segurança FIDO U2F" @@ -876,13 +876,13 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Utilize qualquer chave de segurança ativada pela WebAuthn para aceder à sua conta." + "message": "Utilize qualquer chave de segurança compatível com o WebAuthn para aceder à sua conta." }, "webAuthnMigrated": { - "message": "(Migrado de FIDO)" + "message": "(Migrado do FIDO)" }, "emailTitle": { - "message": "Email" + "message": "E-mail" }, "emailDesc": { "message": "Os códigos de verificação ser-lhe-ão enviados por e-mail." @@ -897,13 +897,13 @@ "message": "Organizações" }, "moveToOrgDesc": { - "message": "Escolha uma organização para a qual pretende mover este item. Mover para uma organização transfere a propriedade do item para essa organização. Deixará de ser o proprietário directo deste item depois de este ter sido movido." + "message": "Escolha uma organização para a qual pretende mover este item. Mover para uma organização transfere a propriedade do item para essa organização. Deixará de ser o proprietário direto deste item depois de este ter sido movido." }, "moveManyToOrgDesc": { - "message": "Escolha uma organização para a qual deseja mover este item. A mudança para uma organização transfere a propriedade do item para essa organização. Deixará de ser o proprietário directo deste item uma vez que tenha sido movido." + "message": "Escolha uma organização para a qual pretende mover estes itens. Mover para uma organização transfere a propriedade dos itens para essa organização. Deixará de ser o proprietário direto destes itens depois de terem sido movidos." }, "collectionsDesc": { - "message": "Edite as coleções em que este item está a ser partilhado. Apenas utilizadores da organização com acesso a estas coleções podem ver este item." + "message": "Edite as coleções com as quais este item está a ser partilhado. Apenas os utilizadores da organização com acesso a estas coleções poderão ver este item." }, "deleteSelectedItemsDesc": { "message": "Serão movidos $COUNT$ item(ns) para o lixo.", @@ -927,7 +927,7 @@ "message": "Are you sure you want to continue?" }, "moveSelectedItemsDesc": { - "message": "Escolha a pasta para onde que mover o(s) $COUNT$ item(s) selecionado(s).", + "message": "Escolha uma pasta para a qual pretende mover o(s) $COUNT$ item(ns) selecionado(s).", "placeholders": { "count": { "content": "$1", @@ -953,19 +953,19 @@ } }, "verificationCodeTotp": { - "message": "Código de Verificação (TOTP)" + "message": "Código de verificação (TOTP)" }, "copyVerificationCode": { - "message": "Copiar código de confirmação" + "message": "Copiar código de verificação" }, "warning": { "message": "Aviso" }, "confirmVaultExport": { - "message": "Confirmar exportação de cofre" + "message": "Confirmar a exportação do cofre" }, "exportWarningDesc": { - "message": "Esta exportação contém os seus dados do cofre num formato desencriptado. Não deve armazenar ou enviar o ficheiro exportado através de canais inseguros (como email). Elimine-o imediatamente após o utilizar." + "message": "Esta exportação contém os dados do seu cofre num formato não encriptado. Não deve armazenar ou enviar o ficheiro exportado através de canais não seguros (como o e-mail). Elimine-o imediatamente após terminar a sua utilização." }, "encExportKeyWarningDesc": { "message": "Esta exportação encripta os seus dados utilizando a chave de encriptação da sua conta. Se alguma vez mudar a chave de encriptação da sua conta, deve exportar novamente, uma vez que não conseguirá desencriptar este ficheiro de exportação." @@ -983,28 +983,28 @@ "message": "Formato do ficheiro" }, "fileEncryptedExportWarningDesc": { - "message": "Esta exportação de arquivo será protegida por senha e exigirá a senha do arquivo para descriptografar." + "message": "A exportação deste ficheiro será protegida por uma palavra-passe e exigirá a palavra-passe do ficheiro para ser desencriptada." }, "exportPasswordDescription": { - "message": "Esta senha será usada para exportar e importar este arquivo" + "message": "Esta palavra-passe será utilizada para exportar e importar este ficheiro" }, "confirmMasterPassword": { - "message": "Confirme a Senha Mestra" + "message": "Confirmar a palavra-passe mestra" }, "confirmFormat": { - "message": "Confirmar Formato" + "message": "Confirmar formato" }, "filePassword": { - "message": "Senha do Arquivo" + "message": "Palavra-passe do ficheiro" }, "confirmFilePassword": { - "message": "Confirmar senha do arquivo" + "message": "Confirmar a palavra-passe do ficheiro" }, "accountRestrictedOptionDescription": { "message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account." }, "passwordProtectedOptionDescription": { - "message": "Crie uma senha gerada pelo utilizador para proteger a exportação. Use isto para criar uma exportação que pode ser usada em outras contas." + "message": "Defina uma palavra-passe do ficheiro para encriptar a exportação e importe-a para qualquer conta Bitwarden utilizando a palavra-passe de desencriptação." }, "exportTypeHeading": { "message": "Export type" @@ -1013,19 +1013,19 @@ "message": "Account restricted" }, "passwordProtected": { - "message": "Protegido por senha" + "message": "Protegido por palavra-passe" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "\"Senha do ficheiro\" e \"Confirmação da senha do ficheiro\" não correspondem." + "message": "\"Palavra-passe do ficheiro\" e \"Confirmar palavra-passe do ficheiro\" não correspondem." }, "confirmVaultImport": { - "message": "Confirmar Importação do Cofre" + "message": "Confirmar a importação do cofre" }, "confirmVaultImportDesc": { - "message": "Este ficheiro é protegido por senha. Por favor, digite a senha do ficheiro para importar os dados." + "message": "Este ficheiro está protegido por palavra-passe. Introduza a palavra-passe do ficheiro para importar os dados." }, "exportSuccess": { - "message": "Os dados do seu cofre foram exportados." + "message": "Dados do cofre exportados" }, "passwordGenerator": { "message": "Gerador de palavras-passe" @@ -1037,7 +1037,7 @@ "message": "Números mínimos" }, "minSpecial": { - "message": "Especiais mínimos", + "message": "Caracteres especiais minímos", "description": "Minimum special characters" }, "ambiguous": { @@ -1061,7 +1061,7 @@ "message": "Números (0-9)" }, "specialCharacters": { - "message": "Caracteres Especiais (!@#$%^&*)" + "message": "Caracteres especiais (!@#$%^&*)" }, "numWords": { "message": "Número de palavras" @@ -1087,22 +1087,22 @@ "description": "To clear something out. Example: To clear browser history." }, "accountUpdated": { - "message": "Conta atualizada" + "message": "Conta guardada" }, "changeEmail": { - "message": "Alterar email" + "message": "Alterar e-mail" }, "changeEmailTwoFactorWarning": { - "message": "O procedimento alterará o endereço de e-mail da sua conta. Não alterará o endereço de e-mail utilizado para autenticação de início de sessão em duas etapas. Pode alterar este endereço de e-mail nas definições de início de sessão em duas etapas." + "message": "Ao prosseguir, o endereço de e-mail da sua conta será alterado. Não alterará o endereço de e-mail utilizado para a autenticação da verificação de dois passos. Pode alterar este endereço de e-mail nas definições de verificação de dois passos." }, "newEmail": { - "message": "Novo email" + "message": "Novo e-mail" }, "code": { "message": "Código" }, "changeEmailDesc": { - "message": "Enviámos um código de verificação para $EMAIL$. Por favor verifique este código no seu email e introduza-o abaixo para finalizar a alteração de endereço de email.", + "message": "Enviámos um código de verificação para $EMAIL$. Verifique este código no seu e-mail e introduza-o abaixo para finalizar a alteração do endereço de e-mail.", "placeholders": { "email": { "content": "$1", @@ -1111,16 +1111,16 @@ } }, "loggedOutWarning": { - "message": "Proceder irá terminar a sua sessão atual, requerendo-lhe voltar a iniciar sessão. Sessões ativas noutros dispositivos podem continuar ativas por até uma hora." + "message": "Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "emailChanged": { - "message": "Email alterado" + "message": "E-mail alterado" }, "logBackIn": { - "message": "Por favor volte a iniciar sessão." + "message": "Por favor, inicie sessão novamente." }, "logBackInOthersToo": { - "message": "Por favor volte a iniciar sessão. Se estiver a usar outras aplicações Bitwarden termine sessão e volte a iniciar sessão nessas também." + "message": "Por favor, inicie sessão novamente. Se estiver a utilizar outras aplicações Bitwarden, termine a sessão e volte a iniciar sessão nessas também." }, "changeMasterPassword": { "message": "Alterar palavra-passe mestra" @@ -1147,7 +1147,7 @@ "message": "Iterações KDF" }, "kdfIterationsDesc": { - "message": "Iterações KDF mais altas podem ajudar a proteger a sua palavra-passe mestra de ser forçada por um atacante. Nós recomendamos um valor de $VALUE$ ou mais.", + "message": "As iterações KDF mais elevadas podem ajudar a proteger a sua palavra-passe mestra de ser forçada por um atacante. Recomendamos um valor de $VALUE$ ou mais.", "placeholders": { "value": { "content": "$1", @@ -1156,7 +1156,7 @@ } }, "kdfIterationsWarning": { - "message": "Definir as suas iterações KDF muito altas pode resultar em desempenho fraco ao iniciar sessão (e desbloquear) o Bitwarden em dispositivos com CPUs mais lentos. Nós recomendamos que aumente o valor em incrementos de $INCREMENT$ e depois testar todos os seus dispositivos.", + "message": "Definir as suas iterações KDF muito altas pode resultar em desempenho fraco ao iniciar sessão (e desbloquear) o Bitwarden em dispositivos com CPUs mais lentos. Recomendamos que aumente o valor em incrementos de $INCREMENT$ e depois teste todos os seus dispositivos.", "placeholders": { "increment": { "content": "$1", @@ -1184,7 +1184,7 @@ "message": "Definições da chave de encriptação alteradas" }, "dangerZone": { - "message": "Zona perigosa" + "message": "Zona de perigo" }, "dangerZoneDesc": { "message": "Cuidado, estas ações não são reversíveis!" @@ -1193,10 +1193,10 @@ "message": "Desautorizar sessões" }, "deauthorizeSessionsDesc": { - "message": "Preocupado pela sua conta ter sessão iniciada noutro dispositivo? Proceda abaixo para desautorizar todos os computadores ou dispositivos que tenha utilizado previamente. Este passo de segurança é recomendado se utilizou um computador público previamente ou guardou acidentalmente a sua palavra-passe num dispositivo que não lhe pertence. Este passo também irá limpar todas as sessões de dois passos previamente memorizadas." + "message": "Preocupado com o facto de a sua conta ter iniciado sessão noutro dispositivo? Proceda abaixo para desautorizar todos os computadores ou dispositivos que utilizou anteriormente. Este passo de segurança é recomendado se tiver utilizado anteriormente um computador público ou se tiver guardado acidentalmente a sua palavra-passe num dispositivo que não é seu. Este passo também apagará todas as sessões de verificação de dois passos anteriormente recordadas." }, "deauthorizeSessionsWarning": { - "message": "Proceder também irá terminar a sua sessão atual, requerendo-lhe voltara a iniciar sessão. Irá ser-lhe solicitado o código de início de sessão de dois passos, se ativado. Sessões ativas noutros dispositivos podem continuar ativas por até uma hora." + "message": "Ao prosseguir, também terminará a sua sessão atual e terá de iniciar sessão novamente. Ser-lhe-á também pedido que volte efetuar a verificação de dois passos, se estiver configurada. As sessões ativas noutros dispositivos podem continuar ativas até uma hora." }, "sessionsDeauthorized": { "message": "Todas as sessões desautorizadas" @@ -1208,25 +1208,25 @@ "message": "Cofre da organização purgado." }, "vaultAccessedByProvider": { - "message": "Cofre acessado pelo provedor." + "message": "Cofre acedido pelo fornecedor." }, "purgeVaultDesc": { - "message": "Proceda abaixo para eliminar todos os itens e pastas do seu cofre. Itens que pertençam a uma organização que partilhe não serão eliminados." + "message": "Proceda da seguinte forma para eliminar todos os itens e pastas do seu cofre. Os itens que pertencem a uma organização com a qual partilha não serão eliminados." }, "purgeOrgVaultDesc": { - "message": "Proceda abaixo para eliminar todos os itens no cofre da organização." + "message": "Proceda da seguinte forma para eliminar todos os itens do cofre da organização." }, "purgeVaultWarning": { - "message": "Purgar o seu cofre é permanente. Não pode ser desfeito." + "message": "A purgação do seu cofre é permanente. Não pode ser desfeita." }, "vaultPurged": { - "message": "O seu cofre foi purgado." + "message": "Cofre purgado." }, "deleteAccount": { "message": "Eliminar conta" }, "deleteAccountDesc": { - "message": "Proceda abaixo para eliminar a sua conta e todos os seus dados associados." + "message": "Proceda da seguinte forma para eliminar a sua conta e todos os dados do cofre." }, "deleteAccountWarning": { "message": "A eliminação da sua conta é permanente. Não pode ser desfeita." @@ -1235,10 +1235,10 @@ "message": "Conta eliminada" }, "accountDeletedDesc": { - "message": "A sua conta foi encerrada e todos os dados associados eliminados." + "message": "A sua conta foi encerrada e todos os dados associados foram eliminados." }, "myAccount": { - "message": "Minha conta" + "message": "A minha conta" }, "tools": { "message": "Ferramentas" @@ -1247,13 +1247,13 @@ "message": "Importar dados" }, "importError": { - "message": "Erro de Importação" + "message": "Erro de importação" }, "importErrorDesc": { - "message": "Havia um problema com os dados que tentou importar. Por favor, resolva os erros listados abaixo no seu ficheiro-fonte e tente novamente." + "message": "Ocorreu um problema com os dados que tentou importar. Por favor, resolva os erros indicados abaixo no seu ficheiro de origem e tente novamente." }, "importSuccess": { - "message": "Os dados foram importados com sucesso para o seu cofre." + "message": "Dados importados com sucesso" }, "importSuccessNumberOfItems": { "message": "A total of $AMOUNT$ items were imported.", @@ -1277,13 +1277,13 @@ } }, "importFormatError": { - "message": "Os dados não estão formatados corretamente. Por favor verifique o ficheiro de importação e tente novamente." + "message": "Os dados não estão formatados corretamente. Por favor, verifique o seu ficheiro de importação e tente novamente." }, "importNothingError": { "message": "Nada foi importado." }, "importEncKeyError": { - "message": "Erro ao desencriptaro arquivo exportado. A sua chave de criptografia não corresponde à chave de criptografia usada para exportar os dados." + "message": "Erro ao desencriptar o ficheiro exportado. A sua chave de encriptação não corresponde à chave de encriptação utilizada para exportar os dados." }, "selectFormat": { "message": "Selecione o formato do ficheiro a importar" @@ -1332,10 +1332,10 @@ "message": "Mostrar ícones do site" }, "faviconDesc": { - "message": "Mostre uma imagem reconhecível ao lado de cada login." + "message": "Mostrar uma imagem reconhecível junto a cada credencial." }, "enableFullWidth": { - "message": "Ativar layout de largura total", + "message": "Apresentar o esquema de largura total", "description": "Allows scaling the web vault UI's width" }, "enableFullWidthDesc": { @@ -1348,7 +1348,7 @@ "message": "Regras de domínios" }, "domainRulesDesc": { - "message": "Se tiver o mesmo início de sessão em múltiplos websites de domínios diferentes, pode marcar o website como \"equivalente\". Domínios \"globais\" são aqueles já criados para si pelo Bitwarden." + "message": "Se tiver o mesmo início de sessão em vários domínios de sites diferentes, pode marcar o site como \"equivalente\". Os domínios \"globais\" são aqueles já criados para si pelo Bitwarden." }, "globalEqDomains": { "message": "Domínios equivalentes globais" @@ -1369,7 +1369,7 @@ "message": "Novo domínio personalizado" }, "newCustomDomainDesc": { - "message": "Introduza uma lista de domínios separados por vírgulas. Apenas são permitidos domínios \"base\". Por exemplo, introduza \"google.com\" em vez de \"www.google.com\". Pode também introduzir \"androidapp://package.name\" para associar uma aplicação android a outros domínios." + "message": "Introduza uma lista de domínios separados por vírgulas. Só são permitidos os domínios \"base\". Não introduza subdomínios. Por exemplo, introduza \"google.com\" em vez de \"www.google.com\". Também pode introduzir \"androidapp://package.name\" para associar uma aplicação android a outros domínios de sites." }, "customDomainX": { "message": "Domínio personalizado $INDEX$", @@ -1387,26 +1387,26 @@ "message": "Verificação de dois passos" }, "twoStepLoginEnforcement": { - "message": "Aplicação do Início de Sessão de Dois Passos" + "message": "Aplicação de verificação de dois passos" }, "twoStepLoginDesc": { - "message": "Reforce a segurança da sua conta ao requerer um passo adicional para iniciar sessão." + "message": "Proteja a sua conta exigindo um passo adicional ao iniciar sessão." }, "twoStepLoginOrganizationDescStart": { - "message": "Aplique as opções do Início de Sessão de Dois Passos do Bitwarden para membros ao utilizar as ", + "message": "Reforce as opções de verificação de dois passos do Bitwarden para os membros, utilizando as ", "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": { - "message": "Políticas do Início de Sessão de Dois Passos" + "message": "Políticas da verificação de dois passos" }, "twoStepLoginOrganizationDuoDesc": { - "message": "Para aplicar o Início de Sessão de Dois Passos através do Duo, utilize as opções abaixo." + "message": "Para aplicar verificação de dois passos através do Duo, utilize as opções abaixo." }, "twoStepLoginOrganizationSsoDesc": { - "message": "Se tiver a configuração SSO, ou planeia tê-la, o Início de Sessão de Dois Passos já pode ser aplicado pelo seu Fornecedor de Identidade." + "message": "Se tiver a configuração SSO, ou planeia tê-la, a verificação de dois passos já pode ser aplicada pelo seu fornecedor de identidade." }, "twoStepLoginRecoveryWarning": { - "message": "Ativar o início de sessão de dois passos pode bloquear-lhe permanentemente o acesso à sua conta Bitwarden. Um código de recuperação permite-lhe aceder à sua conta caso já não possa utilizar o seu provedor normal de início de sessão de dois passos (ex. perde o seu dispositivo). O apoio do Bitwarden não o poderá ajudar se perder acesso à sua conta. Recomendamos que anote ou imprima o código de recuperação e mantenha-o em local seguro." + "message": "A configuração da verificação de dois passos pode bloquear permanentemente a sua conta Bitwarden. Um código de recuperação permite-lhe aceder à sua conta no caso de já não poder utilizar o seu fornecedor normal de verificação de dois passos (por exemplo, se perder o seu dispositivo). O suporte Bitwarden não poderá ajudá-lo se perder o acesso à sua conta. Recomendamos que anote ou imprima o código de recuperação e o guarde num local seguro." }, "viewRecoveryCode": { "message": "Ver código de recuperação" @@ -1422,23 +1422,23 @@ "message": "Ativado" }, "restoreAccess": { - "message": "Restaurar acesso" + "message": "Restaurar o acesso" }, "premium": { "message": "Premium", "description": "Premium membership" }, "premiumMembership": { - "message": "Adesão Premium" + "message": "Subscrição Premium" }, "premiumRequired": { - "message": "Premium requerido" + "message": "É necessária uma subscrição Premium" }, "premiumRequiredDesc": { - "message": "É requerida uma adesão premium para utilizar esta funcionalidade." + "message": "É necessária uma subscrição Premium para utilizar esta funcionalidade." }, "youHavePremiumAccess": { - "message": "Tem acesso premium" + "message": "Tem acesso Premium" }, "alreadyPremiumFromOrg": { "message": "Já tem acesso a funcionalidades Premium devido a uma organização de que é membro." @@ -1450,22 +1450,22 @@ "message": "Desativar" }, "revokeAccess": { - "message": "Revogar acesso" + "message": "Revogar o acesso" }, "twoStepLoginProviderEnabled": { - "message": "Este provedor de início de sessão de dois passos está ativado na sua conta." + "message": "Este fornecedor de verificação de dois passos está ativado na sua conta." }, "twoStepLoginAuthDesc": { - "message": "Introduza a sua palavra-passe mestra para modificar as definições do início de sessão de dois passos." + "message": "Introduza a sua palavra-passe mestra para modificar as definições da verificação de dois passos." }, "twoStepAuthenticatorDesc": { - "message": "Siga estes passos para ativar o início de sessão de dois passos com uma aplicação de autenticador:" + "message": "Siga estes passos para ativar a verificação de dois passos com uma aplicação de autenticação:" }, "twoStepAuthenticatorDownloadApp": { - "message": "Transfira uma aplicação de autenticador de dois passos" + "message": "Descarregue uma aplicação de autenticação de dois passos" }, "twoStepAuthenticatorNeedApp": { - "message": "Precisa de uma aplicação de autenticador de dois passos? Transfira uma das seguintes" + "message": "Precisa de uma aplicação de autenticação de dois passos? Descarregue uma das seguintes aplicações" }, "iosDevices": { "message": "Dispositivos iOS" @@ -1477,10 +1477,10 @@ "message": "Dispositivos Windows" }, "twoStepAuthenticatorAppsRecommended": { - "message": "Estas aplicações são recomendadas, todavia outras aplicações de autenticador também funcionarão." + "message": "Estas aplicações são recomendadas, no entanto, outras aplicações de autenticação também funcionam." }, "twoStepAuthenticatorScanCode": { - "message": "Digitalize este código QR com a sua aplicação de autenticador" + "message": "Digitalize este código QR com a sua aplicação de autenticação" }, "key": { "message": "Chave" @@ -1489,19 +1489,19 @@ "message": "Introduza o código de confirmação de 6 dígitos indicado pela aplicação" }, "twoStepAuthenticatorReaddDesc": { - "message": "No caso de precisar de adicioná-lo a outro dispositivo, abaixo está o código QR (ou chave) requerido pela sua aplicação de autenticador." + "message": "Caso necessite de o adicionar a outro dispositivo, segue-se o código QR (ou chave) exigido pela sua aplicação de autenticação." }, "twoStepDisableDesc": { - "message": "Tem certeza de que pretende desativar este provedor de início de sessão de dois passos?" + "message": "Tem a certeza de que pretende desativar este fornecedor de verificação de dois passos?" }, "twoStepDisabled": { - "message": "Provedor de início de sessão de dois passos desativado." + "message": "Fornecedor de verificação de dois passos desativado." }, "twoFactorYubikeyAdd": { "message": "Adicionar uma nova YubiKey à sua conta" }, "twoFactorYubikeyPlugIn": { - "message": "Ligue a YubiKey (NEO ou série 4) numa porta USB do seu computador." + "message": "Ligue a YubiKey à porta USB do seu computador." }, "twoFactorYubikeySelectKey": { "message": "Selecione o primeiro campo de entrada YubiKey vazio abaixo." @@ -1513,13 +1513,13 @@ "message": "Guarde o formulário." }, "twoFactorYubikeyWarning": { - "message": "Devido a limitações da plataforma, as YubiKeys não podem ser utilizadas em todas as aplicações Bitwarden. Deverá escolher outro método de início de sessão em dois passos quando as YubiKeys não puderem ser utilizadas. Plataformas suportadas:" + "message": "Devido a limitações da plataforma, as YubiKeys não podem ser utilizadas em todas as aplicações Bitwarden. Deverá configurar outro fornecedor de verificação de dois passos para que possa aceder à sua conta quando as YubiKeys não puderem ser utilizadas. Plataformas suportadas:" }, "twoFactorYubikeySupportUsb": { - "message": "Cofre web, aplicação para computador, CLI e todas as extensões de navegador num dispositivo com porta USB que pode aceitar a sua YubiKey." + "message": "Cofre web, aplicação para computador, CLI e todas as extensões do navegador num dispositivo com uma porta USB que possa aceitar a sua YubiKey." }, "twoFactorYubikeySupportMobile": { - "message": "Aplicações móveis num dispositivo com capacidades NFC ou porta de dados que possam aceitar a sua YubiKey." + "message": "Aplicações móveis num dispositivo com capacidades NFC ou uma porta de dados que possa aceitar a sua YubiKey." }, "yubikeyX": { "message": "YubiKey $INDEX$", @@ -1531,7 +1531,7 @@ } }, "u2fkeyX": { - "message": "Chave $INDEX$ U2F", + "message": "Chave U2F $INDEX$", "placeholders": { "index": { "content": "$1", @@ -1555,7 +1555,7 @@ "message": "Uma das minhas chaves suporta NFC." }, "twoFactorYubikeySupportsNfcDesc": { - "message": "Se uma das suas YubiKeys suporta NFC (como a YubiKey NEO), irá ser-lhe solicitado num dispositivo móvel sempre que a disponibilidade NFC seja detetada." + "message": "Se uma das suas YubiKeys suportar NFC (como, por exemplo, uma YubiKey NEO), ser-lhe-á solicitado nos dispositivos móveis sempre que for detetada a disponibilidade de NFC." }, "yubikeysUpdated": { "message": "YubiKeys atualizadas" @@ -1564,7 +1564,7 @@ "message": "Desativar todas as chaves" }, "twoFactorDuoDesc": { - "message": "Introduza a informação da aplicação Bitwarden do painel de administrador do seu Duo." + "message": "Introduza as informações da aplicação Bitwarden a partir do painel de administração do seu Duo." }, "twoFactorDuoIntegrationKey": { "message": "Chave de integração" @@ -1576,16 +1576,16 @@ "message": "Servidor API" }, "twoFactorEmailDesc": { - "message": "Siga estes passos para ativar o início de sessão de dois passos com o email:" + "message": "Siga estes passos para ativar a verificação de dois passos com o e-mail:" }, "twoFactorEmailEnterEmail": { - "message": "Introduza o email onde quer receber códigos de confirmação" + "message": "Introduza o e-mail para o qual pretende receber os códigos de verificação" }, "twoFactorEmailEnterCode": { - "message": "Introduza o código de confirmação de 6 dígitos indicado no email" + "message": "Introduza o código de verificação de 6 dígitos recebido por e-mail" }, "sendEmail": { - "message": "Enviar email" + "message": "Enviar e-mail" }, "twoFactorU2fAdd": { "message": "Adicione uma chave de segurança FIDO U2F à sua conta" @@ -1594,13 +1594,13 @@ "message": "Tem a certeza de que pretende remover esta chave de segurança?" }, "twoFactorWebAuthnAdd": { - "message": "Adicione uma chave de segurança FIDO U2F à sua conta" + "message": "Adicione uma chave de segurança WebAuthn à sua conta" }, "readKey": { "message": "Ler chave" }, "keyCompromised": { - "message": "A chave foi comprometida." + "message": "A chave está comprometida." }, "twoFactorU2fGiveName": { "message": "Dê à chave de segurança um nome amigável para a identificar." @@ -1615,31 +1615,31 @@ "message": "Guarde o formulário." }, "twoFactorU2fWarning": { - "message": "Devido a limitações da plataforma, as FIDO U2F não podem ser utilizadas em todas as aplicações Bitwarden. Deve ativar outro provedor de início de sessão de dois passos para que possa aceder à sua conta quando as FIDO U2F não puderem ser utilizadas. Plataformas suportadas:" + "message": "Devido a limitações da plataforma, o FIDO U2F não pode ser utilizado em todas as aplicações Bitwarden. Deve configurar outro fornecedor de verificação de dois passos para poder aceder à sua conta quando o FIDO U2F não puder ser utilizado. Plataformas suportadas:" }, "twoFactorU2fSupportWeb": { - "message": "Cofre web e extensões de navegador num computador/portátil com um navegador com U2F ativado (Chrome, Opera, Vivaldi ou Firefox com FIDO U2F ativado)." + "message": "Cofre web e extensões do navegador num computador de secretária/portátil com um navegador compatível com U2F (Chrome, Opera, Vivaldi ou Firefox com FIDO U2F ativado)." }, "twoFactorU2fWaiting": { "message": "A aguardar que toque no botão da sua chave de segurança" }, "twoFactorU2fClickSave": { - "message": "Clique no botão \"Guardar\" abaixo para ativar esta chave de segurança para o início de sessão em dois passos." + "message": "Clique no botão \"Guardar\" abaixo para ativar esta chave de segurança para a verificação de dois passos." }, "twoFactorU2fProblemReadingTryAgain": { "message": "Ocorreu um problema ao ler a chave de segurança. Tente novamente." }, "twoFactorWebAuthnWarning": { - "message": "Devido as limitações da plataforma, o WebAuthn não pode ser usado em todos os aplicativos do Bitwarden. Deve habilitar outro provedor de login de duas etapas para aceder à sua conta quando a WebAuthn não puder ser usada. Plataformas suportadas:" + "message": "Devido a limitações da plataforma, o WebAuthn não pode ser utilizado em todas as aplicações Bitwarden. Deve configurar outro fornecedor de verificação de dois passos para que possa aceder à sua conta quando o WebAuthn não puder ser utilizado. Plataformas suportadas:" }, "twoFactorWebAuthnSupportWeb": { - "message": "Cofre web e extensões de navegador em um desktop/laptop com um navegador habilitado para WebAuthn (Chrome, Opera, Vivaldi ou Firefox com o FIDO U2F ativado)." + "message": "Cofre web e extensões do navegador num computador de secretária/portátil com um navegador compatível com WebAuthn (Chrome, Opera, Vivaldi ou Firefox com FIDO U2F ativado)." }, "twoFactorRecoveryYourCode": { - "message": "O seu código Bitwarden de recuperação de início de sessão de dois passos" + "message": "O seu código Bitwarden de recuperação da verificação de dois passos" }, "twoFactorRecoveryNoCode": { - "message": "Ainda não ativou qualquer provedor de início de sessão de dois passos. Depois de ativar um provedor de início de sessão de dois passos pode voltar aqui para obter o seu código de recuperação." + "message": "Ainda não configurou nenhum fornecedor de verificação de dois passos. Depois de ter configurado um fornecedor de verificação de dois passos, pode voltar a consultar aqui o seu código de recuperação." }, "printCode": { "message": "Imprimir código", @@ -1649,7 +1649,7 @@ "message": "Relatórios" }, "reportsDesc": { - "message": "Identifique e feche lacunas de segurança nas suas contas online clicando nos relatórios abaixo.", + "message": "Identifique e elimine as lacunas de segurança nas suas contas online clicando nos relatórios abaixo.", "description": "Vault health reports can be used to evaluate the security of your Bitwarden individual or organization vault." }, "orgsReportsDesc": { @@ -1657,16 +1657,16 @@ "description": "Vault health reports can be used to evaluate the security of your Bitwarden individual or organization vault." }, "unsecuredWebsitesReport": { - "message": "Relatório de websites inseguros" + "message": "Sites inseguros" }, "unsecuredWebsitesReportDesc": { - "message": "Utilizar websites inseguros com o esquema http:// pode ser perigoso. Se o website permitir, deve sempre aceder-lo utilizando o esquema https:// para que a sua ligação seja encriptada." + "message": "Os URLs que começam por http:// não utilizam a melhor encriptação disponível. Altere os URIs das credenciais destas contas para https:// para uma navegação mais segura." }, "unsecuredWebsitesFound": { - "message": "Websites inseguros encontrados" + "message": "Sites inseguros encontrados" }, "unsecuredWebsitesFoundDesc": { - "message": "Encontrámos $COUNT$ itens no seu cofre com URIs inseguros. Deve alterar os seus esquemas de URI para https:// se o website permitir.", + "message": "Encontrámos $COUNT$ itens no seu cofre com URIs não seguros. Deve alterar o esquema de URI para https:// se o site o permitir.", "placeholders": { "count": { "content": "$1", @@ -1678,16 +1678,16 @@ "message": "Nenhum item no seu cofre tem URIs inseguros." }, "inactive2faReport": { - "message": "Relatório de 2FA inativo" + "message": "Verificação de dois passos inativa" }, "inactive2faReportDesc": { - "message": "Autenticação de dois fatores (2FA) é uma definição de segurança importante que ajuda a tornar a as suas contas seguras. Se o website a oferece, deve sempre ativar a autenticação de dois fatores." + "message": "A verificação de dois passos adiciona uma camada de proteção às suas contas. Configure a verificação de dois passos utilizando o autenticador Bitwarden para essas contas ou use um método alternativo." }, "inactive2faFound": { - "message": "Credenciais sem 2FA encontradas" + "message": "Credenciais sem verificação de dois passos encontrados" }, "inactive2faFoundDesc": { - "message": "We found $COUNT$ website(s) in your vault that may not be configured with two-step login (according to 2fa.directory). To further protect these accounts, you should set up two-step login.", + "message": "Encontrámos $COUNT$ site(s) no seu cofre que podem não ter a verificação de dois passos configurada (de acordo com 2fa.directory). Para proteger ainda mais essas contas, deve configurar a verificação de dois passos.", "placeholders": { "count": { "content": "$1", @@ -1696,13 +1696,13 @@ } }, "noInactive2fa": { - "message": "Nenhum website foi encontrado no seu cofre com uma configuração de autenticação de dois fatores em falta." + "message": "Não foram encontrados sites no seu cofre com uma configuração de verificação de dois passos em falta." }, "instructions": { "message": "Instruções" }, "exposedPasswordsReport": { - "message": "Relatório de palavras-passe expostas" + "message": "Palavras-passe expostas" }, "exposedPasswordsReportDesc": { "message": "Passwords exposed in a data breach are easy targets for attackers. Change these passwords to prevent potential break-ins." @@ -1711,7 +1711,7 @@ "message": "Palavras-passe expostas encontradas" }, "exposedPasswordsFoundDesc": { - "message": "Encontrámos $COUNT$ itens no seu cofre que têm palavras-passe que foram expostas em brechas de dados conhecidas. Deve alterá-las para utilizar uma nova palavra-passe.", + "message": "Encontrámos $COUNT$ itens no seu cofre que têm palavras-passe que foram expostas em violações de dados conhecidas. Deve alterá-los para utilizar uma nova palavra-passe.", "placeholders": { "count": { "content": "$1", @@ -1720,7 +1720,7 @@ } }, "noExposedPasswords": { - "message": "Nenhum item no seu cofre tem palavras-passe que foram expostas em brechas de dados conhecidas." + "message": "Nenhum item do seu cofre tem palavras-passe que tenham sido expostas em violações de dados conhecidas." }, "checkExposedPasswords": { "message": "Verificar palavras-passe expostas" @@ -1735,16 +1735,16 @@ } }, "weakPasswordsReport": { - "message": "Relatório de palavras-passe fracas" + "message": "Palavras-passe fracas" }, "weakPasswordsReportDesc": { - "message": "As palavras-passe fracas podem ser facilmente adivinhadas por hackers e ferramentas automáticas que são utilizadas para decifrar palavras-passe. O gerador de palavras-passe do Bitwarden pode ajudar-lhe a criar palavras-passe fortes." + "message": "As palavras-passe fracas podem ser facilmente adivinhadas pelos atacantes. Altere estas palavras-passe para palavras-passe fortes utilizando o gerador de palavras-passe." }, "weakPasswordsFound": { "message": "Palavras-passe fracas encontradas" }, "weakPasswordsFoundDesc": { - "message": "Encontrámos $COUNT$ itens no seu cofre com palavras-passe que não são fortes. Deve atualizá-los para utilizar palavras-passe mais fortes.", + "message": "Encontrámos $COUNT$ itens no seu cofre com palavras-passe que não são fortes. Deve atualizá-los para utilizarem palavras-passe mais fortes.", "placeholders": { "count": { "content": "$1", @@ -1753,13 +1753,13 @@ } }, "noWeakPasswords": { - "message": "Nenhum item no seu cofre tem palavras-passe fracas." + "message": "Nenhum item do seu cofre tem palavras-passe fracas." }, "reusedPasswordsReport": { - "message": "Relatório de palavras-passe reutilizadas" + "message": "Palavras-passe reutilizadas" }, "reusedPasswordsReportDesc": { - "message": "Se um serviço foi comprometido, reutilizar a mesma palavras-passe noutro lugar pode permitir ao hackers ganhar acesso facilmente a mais das suas contas online. Deve utilizar uma palavra-passe única para cada conta ou serviço." + "message": "A reutilização de palavras-passe facilita aos atacantes a invasão de várias contas. Altere estas palavras-passe de modo a que cada uma seja única." }, "reusedPasswordsFound": { "message": "Palavras-passe reutilizadas encontradas" @@ -1774,7 +1774,7 @@ } }, "noReusedPasswords": { - "message": "Nenhuma credencial no seu cofre tem palavras-passe que estão a ser reutilizadas." + "message": "Nenhuma credencial no seu cofre tem palavras-passe que estejam a ser reutilizadas." }, "reusedXTimes": { "message": "Reutilizada $COUNT$ vezes", @@ -1786,19 +1786,19 @@ } }, "dataBreachReport": { - "message": "Relatório de brecha de dados" + "message": "Violação de dados" }, "breachDesc": { - "message": "Uma \"brecha\" é um incidente em que os dados de um site foram ilegalmente acedidos e tornados públicos. Verifique o tipo de dados comprometidos (endereços de email, palavras-passe, cartões de crédito etc.) e tome as medidas apropriadas, como mudar as palavras-passe." + "message": "As contas violadas podem expor as suas informações pessoais. Proteja as contas violadas ativando a 2FA ou criando uma palavra-passe mais forte." }, "breachCheckUsernameEmail": { - "message": "Verifique quaisquer nomes de utilizador ou endereços de email que utilize." + "message": "Verifique os nomes de utilizador ou endereços de e-mail que utiliza." }, "checkBreaches": { - "message": "Verificar brechas" + "message": "Verificar violações" }, "breachUsernameNotFound": { - "message": "$USERNAME$ não encontrado em nenhuma brecha de dados conhecida.", + "message": "$USERNAME$ não encontrado em nenhuma violação de dados conhecida.", "placeholders": { "username": { "content": "$1", @@ -1811,7 +1811,7 @@ "description": "ex. Good News, No Breached Accounts Found!" }, "breachUsernameFound": { - "message": "$USERNAME$ foi encontrado em $COUNT$ diferentes brechas de dados online.", + "message": "$USERNAME$ foi encontrado em $COUNT$ diferentes violações de dados online.", "placeholders": { "username": { "content": "$1", @@ -1824,22 +1824,22 @@ } }, "breachFound": { - "message": "Encontradas contas alvo de brecha" + "message": "Contas violadas encontradas" }, "compromisedData": { "message": "Dados comprometidos" }, "website": { - "message": "Website" + "message": "Site" }, "affectedUsers": { "message": "Utilizadores afetados" }, "breachOccurred": { - "message": "Brecha ocorreu" + "message": "Ocorreu uma violação" }, "breachReported": { - "message": "Brecha relatada" + "message": "Violação comunicada" }, "reportError": { "message": "Ocorreu um erro ao tentar carregar o relatório. Tente novamente" @@ -1848,10 +1848,10 @@ "message": "Faturação" }, "billingPlanLabel": { - "message": "Plano de faturamento" + "message": "Plano de faturação" }, "paymentType": { - "message": "Tipo de Pagamento" + "message": "Método de pagamento" }, "accountCredit": { "message": "Crédito da conta", @@ -1870,23 +1870,23 @@ "description": "Dollar amount, or quantity." }, "creditDelayed": { - "message": "O crédito adicionado irá aparecer na sua conta após o pagamento ser totalmente processado. Alguns métodos de pagamento são mais atrasados e podem levar mais tempo a processar do que outros." + "message": "O crédito adicionado aparecerá na sua conta depois de o pagamento ter sido totalmente processado. Alguns métodos de pagamento têm atrasos e podem demorar mais tempo a ser processados do que outros." }, "makeSureEnoughCredit": { - "message": "Por favor certifique-se de que sua conta tem crédito suficiente disponível para esta compra. Se a sua conta não tem crédito suficiente disponível, o seu método de pagamento predefinido guardado irá ser utilizado para a diferença. Pode adicionar crédito à sua conta a partir da página de faturação." + "message": "Por favor, certifique-se de que a sua conta tem crédito suficiente disponível para esta compra. Se a sua conta não tiver crédito suficiente disponível, será utilizado o seu método de pagamento predefinido registado para cobrir a diferença. Pode adicionar crédito à sua conta a partir da página de faturação." }, "creditAppliedDesc": { - "message": "O crédito da sua conta pode ser utilizado para fazer compras. Qualquer crédito disponível irá ser automaticamente aplicado em faturas geradas para esta conta." + "message": "O crédito da sua conta pode ser utilizado para efetuar compras. Qualquer crédito disponível será automaticamente aplicado às faturas geradas para esta conta." }, "goPremium": { "message": "Tornar-se Premium", "description": "Another way of saying \"Get a Premium membership\"" }, "premiumUpdated": { - "message": "Atualizou para Premium." + "message": "Atualizou para o Premium." }, "premiumUpgradeUnlockFeatures": { - "message": "Atualize a sua conta para uma adesão premium e desbloqueie funcionalidades adicionais fantásticas." + "message": "Atualize a sua conta para uma subscrição Premium e desbloqueie algumas funcionalidades adicionais fantásticas." }, "premiumSignUpStorage": { "message": "1 GB de armazenamento encriptado para anexos de ficheiros." @@ -1898,16 +1898,16 @@ "message": "Acesso de emergência" }, "premiumSignUpReports": { - "message": "Higiene de palavras-passe, saúde das contas, e relatórios de brechas de dados para manter o seu cofre seguro." + "message": "Higiene de palavras-passe, saúde da conta e relatórios de violação de dados para manter o seu cofre seguro." }, "premiumSignUpTotp": { - "message": "Gerador de códigos de verificação TOTP (2FA) para aceder ao seu cofre." + "message": "Gerador de códigos de verificação TOTP (2FA) para credenciais no seu cofre." }, "premiumSignUpSupport": { "message": "Prioridade no apoio ao cliente." }, "premiumSignUpFuture": { - "message": "Todas as funcionalidades premium futuras. Mais a chegar brevemente!" + "message": "Todas as futuras funcionalidades Premium. Mais em breve!" }, "premiumPrice": { "message": "Tudo por apenas $PRICE$ /ano!", @@ -1935,13 +1935,13 @@ "message": "Bitwarden Families plan." }, "addons": { - "message": "Extras" + "message": "Addons" }, "premiumAccess": { "message": "Acesso Premium" }, "premiumAccessDesc": { - "message": "Pode adicionar acesso premium a todos os membros da sua organização por $PRICE$ /$INTERVAL$.", + "message": "Pode adicionar acesso Premium a todos os membros da sua organização por $PRICE$ /$INTERVAL$.", "placeholders": { "price": { "content": "$1", @@ -1960,7 +1960,7 @@ "message": "# de GB adicionais" }, "additionalStorageIntervalDesc": { - "message": "O seu plano vem com $SIZE$ de armazenamento encriptado de ficheiros. Pode adicionar armazenamento adicional por $PRICE$ por GB /$INTERVAL$.", + "message": "O seu plano vem com $SIZE$ de armazenamento de ficheiros encriptados. Pode adicionar armazenamento adicional por $PRICE$ por GB /$INTERVAL$.", "placeholders": { "size": { "content": "$1", @@ -2008,22 +2008,22 @@ } }, "paymentChargedWithTrial": { - "message": "O seu plano inclui um teste gratuito de 7 dias. O seu método de pagamento não irá ser cobrado até o período de teste acabar. A faturação irá ocorreu de forma recorrente a cada $INTERVAL$. Pode cancelar a qualquer momento." + "message": "O seu plano inclui um teste gratuito de 7 dias. O seu método de pagamento não será cobrado até ao fim do período de avaliação. Pode cancelar a qualquer momento." }, "paymentInformation": { - "message": "Informação de pagamento" + "message": "Informações de pagamento" }, "billingInformation": { - "message": "Informação de faturação" + "message": "Informações de faturação" }, "billingTrialSubLabel": { - "message": "O seu método de pagamento não será cobrado durante o teste gratuito de 7 dias." + "message": "O seu método de pagamento não será cobrado durante os 7 dias de teste gratuito." }, "creditCard": { "message": "Cartão de crédito" }, "paypalClickSubmit": { - "message": "Clique no botão PayPal para aceder à sua conta PayPal, depois clique no botão Submeter abaixo para continuar." + "message": "Selecione o botão PayPal para iniciar sessão na sua conta PayPal e, em seguida, clique no botão Submeter abaixo para continuar." }, "cancelSubscription": { "message": "Cancelar subscrição" @@ -2038,7 +2038,7 @@ "message": "Cancelamento pendente" }, "subscriptionPendingCanceled": { - "message": "A subscrição foi marcada para cancelamento no fim do atual período de faturação." + "message": "A subscrição foi marcada para cancelamento no final do período de faturação atual." }, "reinstateSubscription": { "message": "Restabelecer subscrição" @@ -2050,10 +2050,10 @@ "message": "A subscrição foi restabelecida." }, "cancelConfirmation": { - "message": "Tem a certeza de que pretende cancelar? Irá perder acesso a todas as funcionalidades desta subscrição no fim deste ciclo de faturação." + "message": "Tem a certeza de que pretende cancelar? Perderá o acesso a todas as funcionalidades desta subscrição no final deste ciclo de faturação." }, "canceledSubscription": { - "message": "A subscrição foi cancelada." + "message": "Subscrição cancelada" }, "neverExpires": { "message": "Nunca expira" @@ -2089,7 +2089,7 @@ "message": "Remover armazenamento" }, "subscriptionStorage": { - "message": "A sua subscrição tem um total de $MAX_STORAGE$ GB de armazenamento de ficheiros encriptado. Está a utilizar atualmente $USED_STORAGE$.", + "message": "A sua subscrição tem um total de $MAX_STORAGE$ GB de armazenamento de ficheiros encriptados. Atualmente, está a utilizar $USED_STORAGE$.", "placeholders": { "max_storage": { "content": "$1", @@ -2139,7 +2139,7 @@ "description": "Noun. A charge from a payment method." }, "refundNoun": { - "message": "Reembolsado", + "message": "Reembolso", "description": "Noun. A refunded payment that was charged." }, "chargesStatement": { @@ -2158,10 +2158,10 @@ "message": "GB de armazenamento a remover" }, "storageAddNote": { - "message": "Adicionar armazenamento irá resultar em ajustamentos aos seus totais a faturar e imediatamente cobrados no seu método de pagamento registado. A primeira cobrança será alocada pelo remanescente do atual ciclo de faturação." + "message": "A adição de armazenamento resultará em ajustes nos totais de faturação e cobrará imediatamente o método de pagamento registado. A primeira cobrança será proporcional ao remanescente do ciclo de faturação atual." }, "storageRemoveNote": { - "message": "Eliminar armazenamento irá resultar em ajustamentos nos totais a faturar que irão ser alocados como créditos na próxima cobrança de faturação." + "message": "Reduzir o armazenamento alterará o total a ser cobrado que será dividido proporcionalmente em créditos na próxima faturação." }, "adjustedStorage": { "message": "Ajustado $AMOUNT$ GB de armazenamento.", @@ -2173,19 +2173,19 @@ } }, "contactSupport": { - "message": "Contacte o apoio ao cliente" + "message": "Contactar o apoio ao cliente" }, "updatedPaymentMethod": { "message": "Método de pagamento atualizado." }, "purchasePremium": { - "message": "Comprar Premium" + "message": "Adquirir Premium" }, "licenseFile": { "message": "Ficheiro de licença" }, "licenseFileDesc": { - "message": "O seu ficheiro de licença irá ser chamado algo como $FILE_NAME$", + "message": "O nome do seu ficheiro de licença será algo como $FILE_NAME$", "placeholders": { "file_name": { "content": "$1", @@ -2194,19 +2194,19 @@ } }, "uploadLicenseFilePremium": { - "message": "Para atualizar a sua conta para uma adesão premium precisa de carregar um ficheiro de licença válido." + "message": "Para atualizar a sua conta para uma subscrição Premium, tem de carregar um ficheiro de licença válido." }, "uploadLicenseFileOrg": { - "message": "Para criar uma organização alojada nas suas premissas precisa de carregar um ficheiro de licença válido." + "message": "Para criar uma organização alojada no local, é necessário carregar um ficheiro de licença válido." }, "accountEmailMustBeVerified": { - "message": "O endereço de email da sua conta precisa de ser verificado." + "message": "O endereço de e-mail da sua conta deve ser verificado." }, "newOrganizationDesc": { - "message": "Organizações permitem-lhe partilhar partes do seu cofre com outros, bem como gerir utilizadores relacionados com uma entidade específica, como uma família, pequena equipa ou grande empresa." + "message": "As organizações permitem-lhe partilhar partes do seu cofre com outras pessoas, bem como gerir utilizadores relacionados para uma entidade específica, como uma família, uma pequena equipa ou uma grande empresa." }, "generalInformation": { - "message": "Informação geral" + "message": "Informações gerais" }, "organizationName": { "message": "Nome da organização" @@ -2215,7 +2215,7 @@ "message": "Esta conta é propriedade de uma empresa." }, "billingEmail": { - "message": "Email de faturação" + "message": "E-mail de faturação" }, "businessName": { "message": "Nome da empresa" @@ -2236,7 +2236,7 @@ "message": "# de lugares de utilizador" }, "userSeatsAdditionalDesc": { - "message": "O seu plano vem com $BASE_SEATS$ lugares de utilizador. Pode adicionar utilizadores adicionais por $SEAT_PRICE$ por utilizador /mês.", + "message": "O seu plano é fornecido com $BASE_SEATS$ lugares de utilizador. Pode adicionar utilizadores adicionais por $SEAT_PRICE$ por utilizador /mês.", "placeholders": { "base_seats": { "content": "$1", @@ -2249,14 +2249,14 @@ } }, "userSeatsHowManyDesc": { - "message": "De quantos lugares de utilizador precisa? Pode também adicionar lugares adicionais mais tarde se necessário." + "message": "De quantos lugares de utilizador precisa? Também pode adicionar lugares adicionais mais tarde, se necessário." }, "planNameFree": { "message": "Gratuito", "description": "Free as in 'free beer'." }, "planDescFree": { - "message": "Para teste ou utilizadores pessoais partilharem com $COUNT$ outro utilizador.", + "message": "Para utilizadores de teste ou pessoais partilharem com $COUNT$ outro(s) utilizador(es).", "placeholders": { "count": { "content": "$1", @@ -2274,7 +2274,7 @@ "message": "Equipas" }, "planDescTeams": { - "message": "Para empresas e outras equipas e organizações." + "message": "Para empresas e outras organizações de equipas." }, "planNameEnterprise": { "message": "Empresarial" @@ -2307,7 +2307,7 @@ } }, "limitedUsers": { - "message": "Limite de $COUNT$ utilizadores (incluindo o próprio)", + "message": "Limitado a $COUNT$ utilizadores (incluindo o próprio)", "placeholders": { "count": { "content": "$1", @@ -2325,7 +2325,7 @@ } }, "addShareLimitedUsers": { - "message": "Adicione e partilhe com até $COUNT$ utilizadores", + "message": "Adicione e partilhe com um máximo de $COUNT$ utilizadores", "placeholders": { "count": { "content": "$1", @@ -2334,13 +2334,13 @@ } }, "addShareUnlimitedUsers": { - "message": "Adicione e partilhe com utilizadores ilimitados" + "message": "Adicione e partilhe com um número ilimitado de utilizadores" }, "createUnlimitedCollections": { - "message": "Crie coleções ilimitadas" + "message": "Criar coleções ilimitadas" }, "gbEncryptedFileStorage": { - "message": "$SIZE$ de armazenamento de ficheiros encriptado", + "message": "$SIZE$ de armazenamento de ficheiros encriptados", "placeholders": { "size": { "content": "$1", @@ -2349,22 +2349,22 @@ } }, "onPremHostingOptional": { - "message": "Alojamento próprio (opcional)" + "message": "Alojamento local (opcional)" }, "usersGetPremium": { - "message": "Os utilizadores obtêm acesso a funcionalidades de adesão premium" + "message": "Os utilizadores obtêm acesso a funcionalidades Premium" }, "controlAccessWithGroups": { - "message": "Controle o acesso de utilizadores com grupos" + "message": "Controlar o acesso dos utilizadores com grupos" }, "syncUsersFromDirectory": { - "message": "Sincronize os seus utilizadores e grupos de um diretório" + "message": "Sincronizar os seus utilizadores e grupos a partir de um diretório" }, "trackAuditLogs": { - "message": "Siga as ações dos utilizadores com registos de auditoria" + "message": "Acompanhe as ações dos utilizadores com registos de auditoria" }, "enforce2faDuo": { - "message": "Impor 2FA com Duo" + "message": "Impor 2FA com a Duo" }, "priorityCustomerSupport": { "message": "Prioridade no apoio ao cliente" @@ -2388,7 +2388,7 @@ } }, "trialPaidInfoMessage": { - "message": "Seu período de teste gratuito de $PLAN$ por 7 dias será convertido em uma assinatura paga após 7 dias.", + "message": "O seu teste gratuito de 7 dias de $PLAN$ será convertido numa subscrição paga após 7 dias.", "placeholders": { "plan": { "content": "$1", @@ -2397,7 +2397,7 @@ } }, "trialConfirmationEmail": { - "message": "Enviámos um email de confirmação para o email de cobrança da sua equipe em " + "message": "Enviámos um e-mail de confirmação para o e-mail de faturação da sua equipa em " }, "monthly": { "message": "Mensalmente" @@ -2418,16 +2418,16 @@ "message": "A sua nova organização está pronta!" }, "organizationUpgraded": { - "message": "A sua organização foi atualizada." + "message": "Organização atualizada" }, "leave": { "message": "Sair" }, "leaveOrganizationConfirmation": { - "message": "Tem a certeza de que pretende sair desta organização?" + "message": "Tem a certeza de que pretende deixar esta organização?" }, "leftOrganization": { - "message": "Saiu da organização." + "message": "Saiu da organização" }, "defaultCollection": { "message": "Coleção predefinida" @@ -2466,10 +2466,10 @@ "message": "Adicionar grupo" }, "editGroup": { - "message": "Alterar grupo" + "message": "Editar grupo" }, "deleteGroupConfirmation": { - "message": "Tem certeza que pretende eliminar este grupo?" + "message": "Tem a certeza de que pretende eliminar este grupo?" }, "deleteMultipleGroupsConfirmation": { "message": "Are you sure you want to delete the following $QUANTITY$ group(s)?", @@ -2484,19 +2484,19 @@ "message": "Tem a certeza de que pretende remover este utilizador?" }, "removeOrgUserConfirmation": { - "message": "Quando um membro é removido, já não terá acesso aos dados da organização, e esta ação é irreversível. Para adicionar o membro de volta à organização, ele deve ser convidado e integrado novamente." + "message": "Quando um membro é removido, deixa de ter acesso aos dados da organização e esta ação é irreversível. Para adicionar o membro de volta à organização, o mesmo deve ser convidado e integrado novamente." }, "revokeUserConfirmation": { - "message": "Quando um membro é revogado, já não terá acesso aos dados da organização. Para restaurar rapidamente o acesso ao membro vá para a aba Revogada." + "message": "Quando um membro é revogado, deixa de ter acesso aos dados da organização. Para restaurar rapidamente o acesso do membro, vá para o separador Revogados." }, "removeUserConfirmationKeyConnector": { "message": "Atenção! Este utilizador necessita do Key Connector para gerir a sua encriptação. Ao remover este utilizador da sua organização desativará permanentemente a sua conta. Esta ação não pode ser desfeita. Deseja prosseguir?" }, "externalId": { - "message": "Id externa" + "message": "ID externa" }, "externalIdDesc": { - "message": "O id externo pode ser utilizado como uma referência ou para ligar este recurso a um sistema externo como um diretório de utilizadores." + "message": "A ID externa é uma referência não encriptada utilizada pelo Bitwarden Directory Connector e pela API." }, "nestCollectionUnder": { "message": "Nest collection under" @@ -2511,7 +2511,7 @@ "message": "Este grupo pode aceder apenas a coleções selecionadas." }, "readOnly": { - "message": "Apenas leitura" + "message": "Só de leitura" }, "newCollection": { "message": "Nova coleção" @@ -2520,7 +2520,7 @@ "message": "Adicionar coleção" }, "editCollection": { - "message": "Alterar coleção" + "message": "Editar coleção" }, "collectionInfo": { "message": "Collection info" @@ -2541,10 +2541,10 @@ } }, "inviteUserDesc": { - "message": "Convide um novo utilizador para a sua organização ao introduzir abaixo o endereço de email da sua conta Bitwarden. Se ainda não tiver uma conta Bitwarden, irá ser-lhe solicitado criar uma nova conta." + "message": "Convide um novo utilizador para a sua organização introduzindo o endereço de e-mail da sua conta Bitwarden abaixo. Se o utilizador ainda não tiver uma conta Bitwarden, ser-lhe-á pedido que crie uma nova conta." }, "inviteMultipleEmailDesc": { - "message": "Pode convidar até $COUNT$ utilizadores de cada vez separando os endereços de email com vírgulas.", + "message": "Introduza até $COUNT$ e-mails, separando-os com uma vírgula.", "placeholders": { "count": { "content": "$1", @@ -2553,7 +2553,7 @@ } }, "userUsingTwoStep": { - "message": "Este utilizador está a utilizar início de sessão de dois passos para proteger a sua conta." + "message": "Este utilizador está a utilizar a verificação de dois passos para proteger a sua conta." }, "userAccessAllItems": { "message": "Este utilizador pode aceder e modificar todos os itens." @@ -2562,7 +2562,7 @@ "message": "Este utilizador pode aceder apenas a coleções selecionadas." }, "search": { - "message": "Pesquisar" + "message": "Procurar" }, "invited": { "message": "Convidado" @@ -2574,34 +2574,34 @@ "message": "Confirmado" }, "clientOwnerEmail": { - "message": "Cliente proprietário do email" + "message": "E-mail do proprietário do cliente" }, "owner": { "message": "Proprietário" }, "ownerDesc": { - "message": "O utilizador com acesso mais elevado que pode gerir todos os aspetos da sua organização." + "message": "Gerir todos os aspetos da sua organização, incluindo a faturação e as subscrições" }, "clientOwnerDesc": { - "message": "Este utilizador deve ser independente do Provedor. Se o Provedor for desassociado da organização, este utilizador manterá a propriedade da organização." + "message": "Este utilizador deve ser independente do fornecedor. Se o fornecedor for desassociado da organização, este utilizador manterá a propriedade da organização." }, "admin": { "message": "Administrador" }, "adminDesc": { - "message": "Os administradores podem aceder e gerir todos os itens, coleções e utilizadores na sua organização." + "message": "Gerir o acesso à organização, todas as coleções, membros, relatórios e definições de segurança" }, "user": { "message": "Utilizador" }, "userDesc": { - "message": "Um utilizador normal com acesso às coleções atribuídas da sua organização." + "message": "Aceder e adicionar itens às coleções atribuídas" }, "manager": { "message": "Gestor" }, "managerDesc": { - "message": "Os gestores podem aceder e gerir coleções atribuídas na sua organização." + "message": "Criar, eliminar e gerir o acesso a coleções atribuídas" }, "all": { "message": "Todos" @@ -2634,37 +2634,37 @@ "description": "Desktop app" }, "webVault": { - "message": "Cofre Web" + "message": "Cofre web" }, "loggedIn": { - "message": "Sessão iniciada." + "message": "Sessão iniciada" }, "changedPassword": { - "message": "Palavra-passe da conta alterada." + "message": "Palavra-passe da conta alterada" }, "enabledUpdated2fa": { "message": "Verificação de dois passos guardada" }, "disabled2fa": { - "message": "Início de sessão de dois passos desativado." + "message": "Verificação de dois passos desativada" }, "recovered2fa": { - "message": "Conta recuperada de início de sessão de dois passos." + "message": "Conta recuperada da verificação de dois passos." }, "failedLogin": { - "message": "Tentativa de início de sessão falhado com palavra-passe incorreta." + "message": "Tentativa de início de sessão falhada com palavra-passe incorreta." }, "failedLogin2fa": { - "message": "Tentativa de início de sessão falhada com inicio de sessão de dois passos incorreto." + "message": "Tentativa de início de sessão falhada com verificação de dois passos incorreta." }, "exportedVault": { - "message": "Cofre exportado." + "message": "Cofre exportado" }, "exportedOrganizationVault": { "message": "Cofre da organização exportado." }, "editedOrgSettings": { - "message": "Definições de organização editadas." + "message": "Definições da organização editadas." }, "createdItemId": { "message": "Item $ID$ criado.", @@ -2715,7 +2715,7 @@ } }, "viewedPasswordItemId": { - "message": "Palavra-passe vista para o item $ID$.", + "message": "Palavra-passe do item $ID$ vista.", "placeholders": { "id": { "content": "$1", @@ -2724,7 +2724,7 @@ } }, "viewedHiddenFieldItemId": { - "message": "Campo oculto visto para o item $ID$.", + "message": "Campo oculto do item $ID$ visto.", "placeholders": { "id": { "content": "$1", @@ -2733,7 +2733,7 @@ } }, "viewedCardNumberItemId": { - "message": "Número do Cartão Visualizado para o item $ID$.", + "message": "Número do cartão do item $ID$ visualizado.", "placeholders": { "id": { "content": "$1", @@ -2742,7 +2742,7 @@ } }, "viewedSecurityCodeItemId": { - "message": "Código de segurança visto para o item $ID$.", + "message": "Código de segurança do item $ID$ visto.", "placeholders": { "id": { "content": "$1", @@ -2769,7 +2769,7 @@ } }, "copiedPasswordItemId": { - "message": "Palavra-passe copiada para o item $ID$.", + "message": "Palavra-passe do item $ID$ copiada.", "placeholders": { "id": { "content": "$1", @@ -2778,7 +2778,7 @@ } }, "copiedHiddenFieldItemId": { - "message": "Campo oculto copiado para o item $ID$.", + "message": "Campo oculto do item $ID$ copiado.", "placeholders": { "id": { "content": "$1", @@ -2787,7 +2787,7 @@ } }, "copiedSecurityCodeItemId": { - "message": "Código de segurança copiado para o item $ID$.", + "message": "Código de segurança do item $ID$ copiado.", "placeholders": { "id": { "content": "$1", @@ -2835,7 +2835,7 @@ } }, "editedPolicyId": { - "message": "Editou a política $ID$.", + "message": "Política $ID$ editada.", "placeholders": { "id": { "content": "$1", @@ -2889,7 +2889,7 @@ } }, "removeUserIdAccess": { - "message": "Remover acesso de $ID$", + "message": "Remover o acesso de $ID$", "placeholders": { "id": { "content": "$1", @@ -2898,7 +2898,7 @@ } }, "revokedUserId": { - "message": "Acesso revogado da organização para $ID$.", + "message": "Acesso à organização revogado para $ID$.", "placeholders": { "id": { "content": "$1", @@ -2907,7 +2907,7 @@ } }, "restoredUserId": { - "message": "Acesso da organização restaurado para $ID$.", + "message": "Acesso à organização restaurado para $ID$.", "placeholders": { "id": { "content": "$1", @@ -2916,7 +2916,7 @@ } }, "revokeUserId": { - "message": "Revogar acesso de $ID$", + "message": "Revogar o acesso de $ID$", "placeholders": { "id": { "content": "$1", @@ -2925,7 +2925,7 @@ } }, "createdAttachmentForItem": { - "message": "Anexo para o item $ID$ criado.", + "message": "Anexo do item $ID$ criado.", "placeholders": { "id": { "content": "$1", @@ -2934,7 +2934,7 @@ } }, "deletedAttachmentForItem": { - "message": "Anexo para o item $ID$ eliminado.", + "message": "Anexo do item $ID$ eliminado.", "placeholders": { "id": { "content": "$1", @@ -2943,7 +2943,7 @@ } }, "editedCollectionsForItem": { - "message": "Coleções para o item $ID$ editadas.", + "message": "Coleções do item $ID$ editadas.", "placeholders": { "id": { "content": "$1", @@ -2979,7 +2979,7 @@ } }, "editedGroupsForUser": { - "message": "Grupos para o utilizador $ID$ editados.", + "message": "Grupos do utilizador $ID$ editados.", "placeholders": { "id": { "content": "$1", @@ -2988,7 +2988,7 @@ } }, "unlinkedSsoUser": { - "message": "SSO desvinculado para o usuário $ID$.", + "message": "SSO desvinculado para o utilizador $ID$.", "placeholders": { "id": { "content": "$1", @@ -2997,7 +2997,7 @@ } }, "createdOrganizationId": { - "message": "$ID$ organização criada.", + "message": "Organização $ID$ criada.", "placeholders": { "id": { "content": "$1", @@ -3006,7 +3006,7 @@ } }, "addedOrganizationId": { - "message": "$ID$ organização adicionada.", + "message": "Organização $ID$ adicionada.", "placeholders": { "id": { "content": "$1", @@ -3015,7 +3015,7 @@ } }, "removedOrganizationId": { - "message": "$ID$ organização removida.", + "message": "Organização $ID$ removida.", "placeholders": { "id": { "content": "$1", @@ -3039,34 +3039,34 @@ "message": "Ver" }, "invalidDateRange": { - "message": "Período de data inválido." + "message": "Intervalo de datas inválido." }, "errorOccurred": { "message": "Ocorreu um erro." }, "userAccess": { - "message": "Acesso de utilizador" + "message": "Acesso do utilizador" }, "userType": { "message": "Tipo de utilizador" }, "groupAccess": { - "message": "Acesso de grupo" + "message": "Acesso do grupo" }, "groupAccessUserDesc": { - "message": "Edite os grupos a que este utilizador pertence." + "message": "Conceda aos membros acesso às coleções, adicionando-os a 1 ou mais grupos." }, "invitedUsers": { - "message": "Utilizador(es) inválido(s)." + "message": "Utilizador(es) convidado(s)" }, "resendInvitation": { "message": "Reenviar convite" }, "resendEmail": { - "message": "Reenviar Email" + "message": "Reenviar e-mail" }, "hasBeenReinvited": { - "message": "$USER$ foi novamente convidado.", + "message": "$USER$ convidado novamente", "placeholders": { "user": { "content": "$1", @@ -3081,7 +3081,7 @@ "message": "Confirmar utilizador" }, "hasBeenConfirmed": { - "message": "$USER$ foi confirmado.", + "message": "$USER$ confirmado.", "placeholders": { "user": { "content": "$1", @@ -3090,10 +3090,10 @@ } }, "confirmUsers": { - "message": "Confirmar utilizadores" + "message": "Confirmar membros" }, "usersNeedConfirmed": { - "message": "Tem utilizadores que aceitaram os seus convites, mas ainda precisam de ser confirmados. Os utilizadores não irão ter acesso à organização até serem confirmados." + "message": "Tem membros que aceitaram o seu convite, mas que ainda precisam de ser confirmados. Os membros não terão acesso à organização até serem confirmados." }, "startDate": { "message": "Data de início" @@ -3102,22 +3102,22 @@ "message": "Data de fim" }, "verifyEmail": { - "message": "Verificar email" + "message": "Verificar e-mail" }, "verifyEmailDesc": { - "message": "Verifique o endereço de email da sua conta para desbloquear o acesso a todas as funcionalidades." + "message": "Verifique o endereço de e-mail da sua conta para desbloquear o acesso a todas as funcionalidades." }, "verifyEmailFirst": { - "message": "O endereço de email da sua conta deve ser verificado primeiro." + "message": "O endereço de e-mail da sua conta deve ser verificado primeiro." }, "checkInboxForVerification": { - "message": "Verifique a caixa de entrada do seu email pela ligação de verificação." + "message": "Verifique a caixa de entrada do seu e-mail para obter uma ligação de verificação." }, "emailVerified": { - "message": "O seu email foi verificado." + "message": "E-mail da conta verificado" }, "emailVerifiedFailed": { - "message": "Não foi possível verificar o seu email. Tente enviar um novo email de verificação." + "message": "Não foi possível verificar o seu e-mail. Tente enviar um novo e-mail de verificação." }, "emailVerificationRequired": { "message": "Verificação de e-mail necessária" @@ -3132,22 +3132,22 @@ "message": "Está a utilizar um navegador web não suportado. O cofre web pode não funcionar corretamente." }, "joinOrganization": { - "message": "Aderir a organização" + "message": "Aderir à organização" }, "joinOrganizationDesc": { - "message": "Foi convidado para se juntar à organização listada acima. Para aceitar o convite, precisa de iniciar sessão ou criar uma nova conta Bitwarden." + "message": "Foi convidado a juntar-se à organização listada acima. Para aceitar o convite, é necessário iniciar sessão ou criar uma nova conta Bitwarden." }, "inviteAccepted": { "message": "Convite aceite" }, "inviteAcceptedDesc": { - "message": "Pode aceder a esta organização quanto um administrador confirmar a sua adesão. Enviaremos um email quando tal acontecer." + "message": "Pode aceder a esta organização quando um administrador confirmar a sua inscrição. Enviar-lhe-emos um e-mail quando tal acontecer." }, "inviteInitAcceptedDesc": { - "message": "Pode agora aceder a esta organização." + "message": "Já pode aceder a esta organização." }, "inviteAcceptFailed": { - "message": "Não foi possível aceitar o convite. Peça a um administrador da organização para enviar novo convite." + "message": "Não foi possível aceitar o convite. Peça a um administrador da organização para enviar um novo convite." }, "inviteAcceptFailedShort": { "message": "Não foi possível aceitar o convite. $DESCRIPTION$", @@ -3162,28 +3162,28 @@ "message": "Memorizar e-mail" }, "recoverAccountTwoStepDesc": { - "message": "Se não conseguir aceder à sua conta através dos seus métodos normais de início de sessão de dois passos, pode utilizar o seu código de recuperação de dois passos para desativar todos os provedores de início de sessão de dois passos da sua conta." + "message": "Se não conseguir aceder à sua conta através dos seus métodos normais de verificação de dois passos, pode utilizar o seu código de recuperação de verificação de dois passos para desativar todos os fornecedores deste método na sua conta." }, "recoverAccountTwoStep": { - "message": "Recuperar início de sessão de dois passos da conta" + "message": "Recuperar a verificação de dois passos da conta" }, "twoStepRecoverDisabled": { - "message": "O início de sessão de dois passos foi desativado na sua conta." + "message": "A verificação de dois passos foi desativada na sua conta." }, "learnMore": { "message": "Saber mais" }, "deleteRecoverDesc": { - "message": "Introduza o seu endereço de email abaixo para recuperar ou eliminar a sua conta." + "message": "Introduza o seu endereço de e-mail abaixo para recuperar e eliminar a sua conta." }, "deleteRecoverEmailSent": { - "message": "Se a sua conta existe, enviámos-lhe um email com mais instruções." + "message": "Se a sua conta existir, enviámos-lhe um e-mail com mais instruções." }, "deleteRecoverConfirmDesc": { "message": "Pediu para eliminar a sua conta Bitwarden. Clique no botão abaixo para confirmar." }, "myOrganization": { - "message": "Minha organização" + "message": "A minha organização" }, "organizationInfo": { "message": "Informações da organização" @@ -3201,7 +3201,7 @@ } }, "deletingOrganizationActiveUserAccountsWarning": { - "message": "As contas de utilizadores permanecerão ativas após a exclusão, mas não estarão mais associadas a essa organização." + "message": "As contas de utilizador permanecerão ativas após a eliminação, mas deixarão de estar associadas a esta organização." }, "deletingOrganizationIsPermanentWarning": { "message": "A eliminação de $ORGANIZATION$ é permanente e irreversível.", @@ -3222,10 +3222,10 @@ "message": "Organização atualizada" }, "taxInformation": { - "message": "Informação fiscal" + "message": "Informações fiscais" }, "taxInformationDesc": { - "message": "Para clientes dentro dos EUA, o código postal é requerido para satisfazer os requisitos fiscais das vendas, para outros países pode, opcionalmente, providenciar um número de identificação fiscal (IVA/GST) e/ou um endereço para aparecer nas suas faturas." + "message": "Para os clientes nos EUA, o código postal é necessário para satisfazer os requisitos do imposto sobre as vendas. Para os outros países, pode fornecer opcionalmente um número de identificação fiscal (IVA/GST) e/ou um endereço para constar nas suas faturas." }, "billingPlan": { "message": "Plano", @@ -3236,7 +3236,7 @@ "description": "A billing plan/package. For example: Families, Teams, Enterprise, etc." }, "changeBillingPlanUpgrade": { - "message": "Atualize a sua conta para outro plano fornecendo as informações abaixo. Por favor certifique-se de que tem um método de pagamento ativo adicionado na conta.", + "message": "Atualize a sua conta para outro plano, fornecendo as informações abaixo. Por favor, certifique-se de que tem um método de pagamento ativo adicionado à conta.", "description": "A billing plan/package. For example: Families, Teams, Enterprise, etc." }, "invoiceNumber": { @@ -3256,25 +3256,25 @@ "message": "Transferir fatura" }, "verifyBankAccount": { - "message": "Confirmar conta bancária" + "message": "Verificar a conta bancária" }, "verifyBankAccountDesc": { - "message": "Fizemos dois micro-depósitos na sua conta bancária (pode demorar 1-2 dias úteis a aparecer). Introduza estas quantias para verificar a conta bancária." + "message": "Efetuámos dois micro-depósitos na sua conta bancária (podem demorar 1-2 dias úteis a aparecer). Introduza estes montantes para verificar a conta bancária." }, "verifyBankAccountInitialDesc": { - "message": "O pagamento via conta bancária apenas está disponível para clientes nos Estados Unidos. Irá ser-lhe requerido verificar a sua conta bancária. Iremos fazer dois micro-depósitos nos próximos 1-2 dias úteis. Introduza estas quantias na página de faturação da organização para verificar a conta bancária." + "message": "O pagamento com uma conta bancária só está disponível para clientes nos Estados Unidos. Ser-lhe-á pedido que verifique a sua conta bancária. Efetuaremos dois micro-depósitos nos próximos 1-2 dias úteis. Introduza estes montantes na página de faturação da organização para verificar a conta bancária." }, "verifyBankAccountFailureWarning": { - "message": "Falha ao verificar a conta bancária irá resultar na falta de um pagamento e a sua subscrição ser desativada." + "message": "Se a conta bancária não for verificada, o pagamento não será efetuado e a subscrição será suspensa." }, "verifiedBankAccount": { - "message": "Conta bancária verificada." + "message": "Conta bancária verificada" }, "bankAccount": { "message": "Conta bancária" }, "amountX": { - "message": "Quantia $COUNT$", + "message": "Montante $COUNT$", "description": "Used in bank account verification of micro-deposits. Amount, as in a currency amount. Ex. Amount 1 is $2.00, Amount 2 is $1.50", "placeholders": { "count": { @@ -3297,23 +3297,23 @@ "message": "Tipo de conta" }, "bankAccountTypeCompany": { - "message": "Empresa (Empresarial)" + "message": "Empresa (empresarial)" }, "bankAccountTypeIndividual": { - "message": "Individual (Pessoal)" + "message": "Individual (pessoal)" }, "enterInstallationId": { - "message": "Introduza o id da sua instalação" + "message": "Introduza o seu ID de instalação" }, "limitSubscriptionDesc": { - "message": "Defina um limite de utilizadores para sua assinatura. Depois que este limite for atingido, não poderá convidar novos utilizadores." + "message": "Defina um limite de lugares para a sua subscrição. Quando este limite for atingido, não será possível convidar novos membros." }, "maxSeatLimit": { - "message": "Limite Máximo de Assentos (opcional)", + "message": "Limite de lugares (opcional)", "description": "Upper limit of seats to allow through autoscaling" }, "maxSeatCost": { - "message": "Custo máximo potencial de utilizadores" + "message": "Custo máximo potencial do lugar" }, "addSeats": { "message": "Adicionar lugares", @@ -3324,10 +3324,10 @@ "description": "Seat = User Seat" }, "subscriptionDesc": { - "message": "Os ajustes à sua assinatura resultarão em alterações repartidas nos totais de faturamento. Se os utilizadores recém-convidados excederem o número de utilizadores na sua assinatura, receberá imediatamente uma cobrança proporcional pelos utilizadores adicionais." + "message": "Os ajustes à sua subscrição resultarão em alterações proporcionais aos seus totais de faturação. Se os novos utilizadores convidados excederem os lugares da sua subscrição, receberá imediatamente uma cobrança proporcional pelos utilizadores adicionais." }, "subscriptionUserSeats": { - "message": "A sua subscrição permite um total de $COUNT$ utilizadores.", + "message": "A sua subscrição permite um total de $COUNT$ membros.", "placeholders": { "count": { "content": "$1", @@ -3336,25 +3336,25 @@ } }, "limitSubscription": { - "message": "Assinatura Limite (Opcional)" + "message": "Limitar a subscrição (opcional)" }, "subscriptionSeats": { - "message": "Assentos de Assinatura" + "message": "Lugares de subscrição" }, "subscriptionUpdated": { - "message": "Assinatura atualizada" + "message": "Subscrição atualizada" }, "additionalOptions": { "message": "Opções adicionais" }, "additionalOptionsDesc": { - "message": "Para ajuda adicional no gerenciamento da sua assinatura, entre em contato com o suporte ao cliente." + "message": "Para obter ajuda adicional na gestão da sua subscrição, contacte o serviço de apoio ao cliente." }, "subscriptionUserSeatsUnlimitedAutoscale": { - "message": "Os ajustes à sua assinatura resultarão em alterações repartidas nos totais de faturamento. Se os utilizadores recém-convidados excederem o número de utilizadores na sua assinatura, receberá imediatamente uma cobrança proporcional pelos utilizadores adicionais." + "message": "Os ajustes à sua subscrição resultarão em alterações proporcionais aos seus totais de faturação. Se os novos membros convidados excederem os lugares da sua subscrição, receberá imediatamente uma cobrança proporcional pelos membros adicionais." }, "subscriptionUserSeatsLimitedAutoscale": { - "message": "Os ajustes à sua assinatura resultarão em alterações repartidas nos totais de faturamento. Se os utilizadores recém-convidados excederem os seus assentos de assinatura, receberá imediatamente uma cobrança proporcional por utilizador adicional até que o seu limite de $MAX$ seja atingido.", + "message": "Os ajustes à sua subscrição resultarão em alterações proporcionais aos seus totais de faturação. Se os novos membros convidados excederem os lugares da sua subscrição, receberá imediatamente uma cobrança proporcional pelos membros adicionais até que o seu limite de $MAX$ lugares seja atingido.", "placeholders": { "max": { "content": "$1", @@ -3399,19 +3399,19 @@ } }, "seatsToAdd": { - "message": "Lugares a adicionar" + "message": "Lugares a acrescentar" }, "seatsToRemove": { "message": "Lugares a remover" }, "seatsAddNote": { - "message": "Adicionar lugares de utilizador irá resultar em ajustamentos aos seus totais a faturar e imediatamente cobrados no seu método de pagamento registado. A primeira cobrança será alocada pelo remanescente do atual ciclo de faturação." + "message": "A adição de lugares de utilizador resultará em ajustes nos totais de faturação e cobrará imediatamente o método de pagamento registado. A primeira cobrança será proporcional ao remanescente do ciclo de faturação atual." }, "seatsRemoveNote": { - "message": "Remover lugares de utilizador irá resultar em ajustamentos nos totais a faturar que irão ser alocados como créditos na próxima cobrança de faturação." + "message": "Reduzir o número de lugares de utilizador alterará o total a ser cobrado que será dividido proporcionalmente em créditos na próxima faturação." }, "adjustedSeats": { - "message": "Ajustado $AMOUNT$ lugares de utilizador.", + "message": "$AMOUNT$ lugares de utilizador ajustados.", "placeholders": { "amount": { "content": "$1", @@ -3432,10 +3432,10 @@ "message": "Está atualmente a utilizar um esquema de encriptação desatualizado." }, "updateEncryptionKeyDesc": { - "message": "Mudámos para chaves de encriptação maiores que providenciam maior segurança e acesso a funcionalidades mais recentes. Atualizar a sua chave de encriptação é rápido e fácil. Apenas escreva abaixo a sua palavra-passe mestra. Esta atualização eventualmente irá tornar-se obrigatória." + "message": "Passámos a utilizar chaves de encriptação maiores que proporcionam uma melhor segurança e acesso a novas funcionalidades. A atualização da sua chave de encriptação é rápida e fácil. Basta introduzir a sua palavra-passe mestra abaixo. Esta atualização acabará por se tornar obrigatória." }, "updateEncryptionKeyWarning": { - "message": "Depois de atualizar a sua chave de encriptação, é-lhe requerido terminar sessão e voltar a iniciá-la em todas as aplicações Bitwarden que esteja a utilizar (tais como a aplicação móvel ou extensões de navegador). Falha ao terminar sessão e voltar a iniciar (que transfere a sua nova chave de encriptação) pode resultar em corrupção de dados. Tentaremos terminar-lhe a sessão automaticamente, todavia, pode demorar." + "message": "Depois de atualizar a sua chave de encriptação, é necessário terminar sessão e voltar a iniciar em todas as aplicações Bitwarden que está a utilizar atualmente (como a aplicação móvel ou as extensões do navegador). A falha em terminar sessão e voltar a iniciar (que descarrega a sua nova chave de encriptação) pode resultar em corrupção de dados. Tentaremos terminar a sua sessão automaticamente, no entanto, pode demorar." }, "updateEncryptionKeyExportWarning": { "message": "Any encrypted exports that you have saved will also become invalid." @@ -3456,10 +3456,10 @@ "message": "Esta funcionalidade não está disponível para organizações gratuitas. Mude para um plano pago para desbloquear mais funcionalidades." }, "createOrganizationStep1": { - "message": "Criar organização: Passo 1" + "message": "Criar organização: 1.º passo" }, "createOrganizationCreatePersonalAccount": { - "message": "Antes de criar a sua organização, primeiro tem de criar uma conta pessoal gratuita." + "message": "Antes de criar a sua organização, tem primeiro de criar uma conta pessoal gratuita." }, "refunded": { "message": "Reembolsado" @@ -3468,7 +3468,7 @@ "message": "Não selecionou nada." }, "acceptPolicies": { - "message": "Ao marcar esta caixa concorda com o seguinte:" + "message": "Ao assinalar esta caixa, concorda com o seguinte:" }, "acceptPoliciesRequired": { "message": "Os Termos de utilização e a Política de privacidade não foram aceites." @@ -3486,7 +3486,7 @@ "message": "Expiração do cofre" }, "vaultTimeoutDesc": { - "message": "Escolha quando o seu cofre irá expirar e realizar a ação selecionada." + "message": "Escolha a que altura expira o seu cofre, realizando a ação de expiração do mesmo." }, "oneMinute": { "message": "1 minuto" @@ -3507,7 +3507,7 @@ "message": "4 horas" }, "onRefresh": { - "message": "Quando reiniciar o navegador" + "message": "Ao atualizar o navegador" }, "dateUpdated": { "message": "Atualizado", @@ -3518,17 +3518,17 @@ "description": "ex. Date this item was created" }, "datePasswordUpdated": { - "message": "Palavra-passe Atualizada", + "message": "Palavra-passe atualizada", "description": "ex. Date this password was updated" }, "organizationIsDisabled": { - "message": "A organização está desativada." + "message": "Organização suspensa" }, "disabledOrganizationFilterError": { - "message": "Itens em Organizações desativadas não podem ser acedidos. Entre em contato com o proprietário da sua Organização para obter assistência." + "message": "Não é possível aceder a itens em organizações suspensas. Contacte o proprietário da organização para obter assistência." }, "licenseIsExpired": { - "message": "A licença está expirada." + "message": "A licença expirou." }, "updatedUsers": { "message": "Utilizadores atualizados" @@ -3562,10 +3562,10 @@ "message": "Palavra-passe mestra fraca" }, "weakMasterPasswordDesc": { - "message": "A palavra-passe mestra que escolheu é fraca. Deve utilizar uma palavra-passe mestra forte (ou uma frase-passe) para proteger adequadamente a sua conta Bitwarden. Tem a certeza de que pretende utilizar esta palavra-passe mestra?" + "message": "Foi identificada uma palavra-passe fraca. Utilize uma palavra-passe forte para proteger a sua conta. Tem a certeza de que pretende utilizar uma palavra-passe fraca?" }, "rotateAccountEncKey": { - "message": "Também rodar a chave de encriptação da minha conta" + "message": "Rodar também a chave de encriptação da minha conta" }, "rotateEncKeyTitle": { "message": "Rodar chave de encriptação" @@ -3577,31 +3577,31 @@ "message": "Este item tem anexos de ficheiros antigos que precisam de ser corrigidos." }, "attachmentFixDesc": { - "message": "Este é um anexo de ficheiro que precisa de ser corrigido. Clique para saber mais." + "message": "Trata-se de um anexo de ficheiro antigos que precisa de ser corrigido. Clique para saber mais." }, "fix": { "message": "Corrigir", "description": "This is a verb. ex. 'Fix The Car'" }, "oldAttachmentsNeedFixDesc": { - "message": "Existem anexos de ficheiros antigos no seu cofre que precisam de ser corrigidos antes de poder rodar a chave de encriptação da sua conta." + "message": "Existem anexos de ficheiros antigos no seu cofre que têm de ser corrigidos antes de poder rodar a chave de encriptação da sua conta." }, "yourAccountsFingerprint": { - "message": "A frase de impressão digital da sua conta", + "message": "Frase da impressão digital da sua conta", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "fingerprintEnsureIntegrityVerify": { - "message": "Para assegurar a integridade das suas chaves de encriptação, por favor verifique a frase de impressão digital do utilizador antes de continuar.", + "message": "Para garantir a integridade das suas chaves de encriptação, verifique a frase da impressão digital do utilizador antes de continuar.", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "fingerprintMatchInfo": { - "message": "Por favor, certifique-se de que o seu cofre está desbloqueado e a frase de impressão digital corresponde ao outro dispositivo." + "message": "Por favor, certifique-se de que o cofre está desbloqueado e que a frase de impressão digital corresponde à do outro dispositivo." }, "fingerprintPhraseHeader": { - "message": "Frase biométrica" + "message": "Frase de impressão digital" }, "dontAskFingerprintAgain": { - "message": "Não perguntar para verificar frase de impressão digital novamente", + "message": "Nunca solicitar a verificação de frases de impressões digitais para utilizadores convidados (não recomendado)", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "free": { @@ -3612,13 +3612,13 @@ "message": "Chave da API" }, "apiKeyDesc": { - "message": "A sua chave da API pode ser utilizada para autenticar na API pública Bitwarden." + "message": "A sua chave da API pode ser utilizada para autenticar a API pública Bitwarden." }, "apiKeyRotateDesc": { - "message": "Rodar a chave da API irá invalidar a chave anterior. Pode rodar a sua chave da API se achar que a chave atual já não é segura para uso." + "message": "A rotação da chave da API invalidará a chave anterior. Pode rodar a sua chave API se considerar que a chave atual já não é segura para utilização." }, "apiKeyWarning": { - "message": "A sua chave da API tem acesso total à organização. Esta deve ser mantida secreta." + "message": "A sua chave API tem acesso total à organização. Deve ser mantida em segredo." }, "userApiKeyDesc": { "message": "Your API key can be used to authenticate in the Bitwarden CLI." @@ -3631,58 +3631,58 @@ "description": "'OAuth 2.0' is a programming protocol. It should probably not be translated." }, "viewApiKey": { - "message": "Ver chave da API" + "message": "Ver a chave da API" }, "rotateApiKey": { - "message": "Rodar chave da API" + "message": "Rodar a chave da API" }, "selectOneCollection": { - "message": "Tem de selecionar pelo menos uma coleção." + "message": "Deve selecionar pelo menos uma coleção." }, "couldNotChargeCardPayInvoice": { - "message": "Não foi possível cobrar o seu cartão. Por favor verifique e efetue o pagamento da fatura por pagar listada abaixo." + "message": "Não foi possível concluir a transação. Por favor, verifique e efetue o pagamento da fatura por pagar indicada abaixo." }, "inAppPurchase": { - "message": "Compra na aplicação" + "message": "Compras na aplicação" }, "cannotPerformInAppPurchase": { - "message": "Não pode realizar esta ação utilizando um método de pagamento dentro da aplicação." + "message": "Não é possível executar esta ação enquanto estiver a utilizar um método de pagamento dentro da aplicação." }, "manageSubscriptionFromStore": { - "message": "Terá de gerir a sua subscrição a partir da loja onde a sua compra na aplicação foi efetuada." + "message": "Deve gerir a sua subscrição a partir da loja onde foi efetuada a compra na aplicação." }, "minLength": { "message": "Comprimento mínimo" }, "clone": { - "message": "Clonar" + "message": "Duplicar" }, "masterPassPolicyTitle": { - "message": "Requisitos de palavra-passe mestra" + "message": "Requisitos da palavra-passe mestra" }, "masterPassPolicyDesc": { - "message": "Defina os requisitos mínimos para a força da palavra-passe mestra." + "message": "Definir requisitos para a força da palavra-passe mestra." }, "twoStepLoginPolicyTitle": { - "message": "Exigir login em duas etapas" + "message": "Exigir verificação de dois passos" }, "twoStepLoginPolicyDesc": { - "message": "Requer que os utilizadores definam a autenticação de dois passos nas suas contas pessoais." + "message": "Exigir que os membros configurem a verificação de dois passos." }, "twoStepLoginPolicyWarning": { - "message": "Os membros da organização que não tenham a autenticação de dois passos ativada para sua conta pessoal, serão removidos da organização e receberão um email notificando-os acerca da alteração." + "message": "Os membros da organização que não sejam proprietários ou administradores e que não tenham configurado a verificação de dois passos para a sua conta serão removidos da organização e receberão um e-mail a notificá-los da alteração." }, "twoStepLoginPolicyUserWarning": { - "message": "É membro de uma organização que requer início de sessão em duas etapas para ser configurada na sua conta de utilizador. Se desligar todos os fornecedores de início de sessão em duas etapas, será automaticamente removido destas organizações." + "message": "É membro de uma organização que exige que a verificação de dois passos seja configurada na sua conta de utilizador. Se desativar todos os fornecedores de verificação de dois passos, será automaticamente removido destas organizações." }, "passwordGeneratorPolicyDesc": { - "message": "Defina os requisitos mínimos para configuração do gerador de palavras-passe." + "message": "Definir requisitos para o gerador de palavras-passe." }, "passwordGeneratorPolicyInEffect": { "message": "Uma ou mais políticas da organização estão a afetar as suas definições do gerador." }, "masterPasswordPolicyInEffect": { - "message": "Uma ou mais políticas da organização requerem que a sua palavra-passe mestra cumpra aos seguintes requisitos:" + "message": "Uma ou mais políticas da organização exigem que a sua palavra-passe mestra cumpra os seguintes requisitos:" }, "policyInEffectMinComplexity": { "message": "Pontuação mínima de complexidade de $SCORE$", @@ -3750,7 +3750,7 @@ "description": "Noun: A special folder for holding deleted items that have not yet been permanently deleted" }, "searchTrash": { - "message": "Pesquisar lixo" + "message": "Procurar no lixo" }, "permanentlyDelete": { "message": "Eliminar permanentemente" @@ -3762,7 +3762,7 @@ "message": "Eliminar item permanentemente" }, "permanentlyDeleteItemConfirmation": { - "message": "Tem a certeza de que pretende eliminar este item permanentemente?" + "message": "Tem a certeza de que pretende eliminar permanentemente este item?" }, "permanentlyDeletedItem": { "message": "Item eliminado permanentemente" @@ -3771,7 +3771,7 @@ "message": "Itens eliminados permanentemente" }, "permanentlyDeleteSelectedItemsDesc": { - "message": "Selecionou $COUNT$ item(s) para eliminar permanentemente. Tem a certeza de que pretende eliminar permanentemente todos estes itens?", + "message": "Selecionou $COUNT$ item(ns) para eliminar permanentemente. Tem a certeza de que pretende eliminar permanentemente todos estes itens?", "placeholders": { "count": { "content": "$1", @@ -3780,7 +3780,7 @@ } }, "permanentlyDeletedItemId": { - "message": "Item $ID$ eliminado permanentemente.", + "message": "Item $ID$ eliminado permanentemente", "placeholders": { "id": { "content": "$1", @@ -3810,7 +3810,7 @@ "message": "Restaurar itens" }, "restoreSelectedItemsDesc": { - "message": "Selecionou $COUNT$ item(s) para restaurar. Tem a certeza de que pretende restaurar todos estes itens?", + "message": "Selecionou $COUNT$ item(ns) para restaurar. Tem a certeza de que pretende restaurar estes itens?", "placeholders": { "count": { "content": "$1", @@ -3819,7 +3819,7 @@ } }, "restoredItemId": { - "message": "Item $ID$ restaurado.", + "message": "Item $ID$ restaurado", "placeholders": { "id": { "content": "$1", @@ -3828,7 +3828,7 @@ } }, "vaultTimeoutLogOutConfirmation": { - "message": "Terminar sessão irá remover todos os acessos ao seu cofre e requer autenticação online após o período de expiração. Tem a certeza de que pretende utilizar esta definição?" + "message": "Ao terminar sessão removerá todo o acesso ao seu cofre e requer autenticação online após o período de tempo limite. Tem a certeza de que pretende utilizar esta definição?" }, "vaultTimeoutLogOutConfirmationTitle": { "message": "Confirmação de expiração do cofre" @@ -3837,7 +3837,7 @@ "message": "Ocultar palavras-passe" }, "countryPostalCodeRequiredDesc": { - "message": "Requeremos esta informação para calcular imposto sobre vendas e relatórios financeiros apenas." + "message": "Estas informações são necessárias apenas para o cálculo do imposto sobre as vendas e para a elaboração de relatórios financeiros." }, "includeVAT": { "message": "Incluir informações de IVA/GST (opcional)" @@ -3861,10 +3861,10 @@ "message": "Identificador da organização" }, "ssoLogInWithOrgIdentifier": { - "message": "Inicie sessão utilizando o portal de início de sessão único da sua organização. Por favor introduza o identificador da sua organização para começar." + "message": "Inicie sessão utilizando o portal de início de sessão único da sua organização. Por favor, introduza o identificador SSO da sua organização para começar." }, "enterpriseSingleSignOn": { - "message": "Início de Sessão Único da Empresa" + "message": "Início de sessão único para empresas" }, "ssoHandOff": { "message": "Pode fechar esta aba e continuar na extensão." @@ -3936,19 +3936,19 @@ "message": "Texto" }, "createSend": { - "message": "Criar Novo Envio", + "message": "Novo Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { - "message": "Editar Envio", + "message": "Editar Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { - "message": "Envio criado", + "message": "Send criado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Envio editado", + "message": "Send editado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deletedSend": { @@ -3975,7 +3975,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { - "message": "Data de Expiração" + "message": "Data de validade" }, "expirationDateDesc": { "message": "Se definido, o acesso a este Send expirará na data e hora especificadas.", @@ -4000,27 +4000,27 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disabled": { - "message": "Desabilitado" + "message": "Desativado" }, "revoked": { "message": "Revogado" }, "sendLink": { - "message": "Enviar ligação", + "message": "Link do Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copySendLink": { - "message": "Copiar Link de Envio", + "message": "Copiar link do Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "removePassword": { "message": "Remover palavra-passe" }, "removedPassword": { - "message": "Senha removida" + "message": "Palavra-passe removida" }, "removePasswordConfirmation": { - "message": "Tem a certeza que pretende remover a senha?" + "message": "Tem a certeza de que pretende remover a palavras-passe?" }, "hideEmail": { "message": "Ocultar o meu endereço de e-mail dos destinatários." @@ -4030,7 +4030,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "allSends": { - "message": "Todos os Envios" + "message": "Todos os Sends" }, "maxAccessCountReached": { "message": "Número de acessos máximo atingido", @@ -4043,7 +4043,7 @@ "message": "Expirado" }, "searchSends": { - "message": "Pesquisar Envios", + "message": "Procurar Sends", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendProtectedPassword": { @@ -4059,7 +4059,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "downloadFile": { - "message": "Descarregar Ficheiro" + "message": "Transferir ficheiro" }, "sendAccessUnavailable": { "message": "O Envio que está tentando aceder não existe ou não está mais disponível.", @@ -4083,25 +4083,25 @@ "message": "You are an owner of one or more organizations. If you give takeover access to an emergency contact, they will be able to use all your permissions as owner after a takeover." }, "trustedEmergencyContacts": { - "message": "Contatos de emergência confiáveis" + "message": "Contactos de emergência de confiança" }, "noTrustedContacts": { "message": "You have not added any emergency contacts yet, invite a trusted contact to get started." }, "addEmergencyContact": { - "message": "Adicione um contacto de emergência" + "message": "Adicionar contacto de emergência" }, "designatedEmergencyContacts": { - "message": "Designado como contato de emergência" + "message": "Designado como contacto de emergência" }, "noGrantedAccess": { "message": "You have not been designated as an emergency contact for anyone yet." }, "inviteEmergencyContact": { - "message": "Convidar contato de emergência" + "message": "Convidar contacto de emergência" }, "editEmergencyContact": { - "message": "Editar contato de emergência" + "message": "Editar contacto de emergência" }, "inviteEmergencyContactDesc": { "message": "Invite a new emergency contact by entering their Bitwarden account email address below. If they do not have a Bitwarden account already, they will be prompted to create a new account." @@ -4289,7 +4289,7 @@ "message": "Grant customized permissions to members" }, "customDescNonEnterpriseStart": { - "message": "Os papéis personalizados são uma ", + "message": "As funções personalizadas são uma ", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Custom roles is an enterprise feature. Contact our support team to upgrade your subscription'" }, "customDescNonEnterpriseLink": { @@ -4825,13 +4825,13 @@ "message": "Atualizar palavra-passe mestra" }, "updateMasterPasswordWarning": { - "message": "A sua palavra-passe mestra foi recentemente alterada por um administrador da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra foi recentemente alterada por um administrador da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "masterPasswordInvalidWarning": { - "message": "A sua palavra-passe mestra não cumpre os requisitos da política desta organização. Para se juntar à organização, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de voltar a iniciar sessão. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra não cumpre os requisitos da política desta organização. Para se juntar à organização, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de voltar a iniciar sessão. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "updateWeakMasterPasswordWarning": { - "message": "A sua palavra-passe mestra não cumpre uma ou mais políticas da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Se prosseguir, sairá da sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." + "message": "A sua palavra-passe mestra não cumpre uma ou mais políticas da sua organização. Para aceder ao cofre, tem de atualizar a sua palavra-passe mestra agora. Ao prosseguir, terminará a sua sessão atual e terá de iniciar sessão novamente. As sessões ativas noutros dispositivos poderão continuar ativas até uma hora." }, "maximumVaultTimeout": { "message": "Expiração do cofre" @@ -5407,7 +5407,7 @@ "message": "A exportar o cofre pessoal" }, "exportingOrganizationVaultTitle": { - "message": "A exportar cofre da organização" + "message": "A exportar o cofre da organização" }, "exportingPersonalVaultDescription": { "message": "Apenas os itens do cofre pessoal associado a $EMAIL$ serão exportados. Os itens do cofre da organização não serão incluídos.", @@ -5584,7 +5584,7 @@ "message": "Verificação do dispositivo atualizada" }, "areYouSureYouWantToEnableDeviceVerificationTheVerificationCodeEmailsWillArriveAtX": { - "message": "Tem a certeza de que deseja ativar a Verificação do Dispositivo? Os e-mails com os códigos de verificação serão enviados para: $EMAIL$", + "message": "Tem a certeza de que pretende ativar a verificação do dispositivo? Os e-mails com o código de verificação serão enviados para: $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -5650,7 +5650,7 @@ "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "inputRequired": { - "message": "Entrada necessária." + "message": "Campo necessário." }, "inputEmail": { "message": "A entrada não é um endereço de e-mail." @@ -6607,7 +6607,7 @@ "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "message": "Ao prosseguir, terminará todas as sessões ativas. Terá de iniciar sessão novamente e concluir a configuração da verificação de dois passos. Recomendamos que exporte o seu cofre antes de alterar as definições de encriptação para evitar a perda de dados." }, "secretsManagerBeta": { "message": "Secrets Manager Beta" @@ -6776,7 +6776,7 @@ } }, "inputTrimValidator": { - "message": "A entrada não deve conter apenas espaços em branco.", + "message": "O campo não deve conter apenas espaços em branco.", "description": "Notification to inform the user that a form's input can't contain only whitespace." }, "dismiss": { @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "com inscrição automática será ativada quando esta opção for utilizada.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ não encontrado(a)", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recuperar conta" diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index ac98ed7c69c..1da751ac934 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 5a75badfddf..ca7cf0c6e8e 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -4493,22 +4493,22 @@ "message": "Подсказка для пароля не может совпадать с паролем." }, "enrollAccountRecovery": { - "message": "Enroll in account recovery" + "message": "Зарегистрироваться на восстановление аккаунта" }, "enrolledAccountRecovery": { - "message": "Enrolled in account recovery" + "message": "Зарегистрирован на восстановление аккаунта" }, "withdrawAccountRecovery": { - "message": "Withdraw from account recovery" + "message": "Сняться с восстановления аккаунта" }, "enrollPasswordResetSuccess": { - "message": "Записано успешно!" + "message": "Регистрация успешна!" }, "withdrawPasswordResetSuccess": { "message": "Запись успешно отменена!" }, "eventEnrollAccountRecovery": { - "message": "User $ID$ enrolled in account recovery.", + "message": "Пользователь $ID$ зарегистрирован на восстановление аккаунта.", "placeholders": { "id": { "content": "$1", @@ -4517,7 +4517,7 @@ } }, "eventWithdrawAccountRecovery": { - "message": "User $ID$ withdrew from account recovery.", + "message": "Пользователь $ID$ снялся с восстановления аккаунта.", "placeholders": { "id": { "content": "$1", @@ -4577,10 +4577,10 @@ "message": "Регистрация позволит администраторам организации изменять ваш мастер-пароль" }, "accountRecoveryPolicy": { - "message": "Account recovery administration" + "message": "Управление восстановлением аккаунта" }, "accountRecoveryPolicyDescription": { - "message": "Recover member accounts when master password or trusted devices are forgotten or lost. The recovery processes is based on the account encryption method." + "message": "Восстановление аккаунтов пользователей при утере мастер-пароля или доверенных устройств. Восстановление осуществляется на основе метода шифрования аккаунта." }, "resetPasswordPolicyWarning": { "message": "Пользователи организации должны зарегистрироваться самостоятельно или быть зарегистрированными автоматически, чтобы администраторы могли сбросить их мастер-пароль." @@ -6776,7 +6776,7 @@ } }, "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." }, "dismiss": { @@ -6818,21 +6818,30 @@ "message": "Шифрование доверенного устройства" }, "memberDecryptionTdeDescriptionStart": { - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionTdeDescriptionLink": { - "message": "account recovery administration 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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" }, "memberDecryptionTdeDescriptionEnd": { - "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration 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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ не найден", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { - "message": "Recover account" + "message": "Восстановить аккаунт" }, "updatedTempPassword": { - "message": "User updated a password issued through account recovery." + "message": "Пользователь обновил пароль, выданный через восстановление аккаунта." } } diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index 15d32a60d9a..850022fd11b 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 69679f93212..00721d3762b 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ nenájdené", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Obnoviť účet" diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 62b877e56f8..fcae99eb925 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index f516da4463a..5ed3c6b1288 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 68ddac883a9..b55d9d59a8f 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index ff2966844d0..fadf4585a5a 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index dd62b4d4a3b..7595e610b1a 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index 78d9c537809..4d2c52f734e 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 03159797e9a..10ec65016af 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "otomatik kayıtla birlikte açılacaktır.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ bulunamadı", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Hesabı kurtar" diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 7cbe9b7bdcd..ace0b4878d7 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Відновити обліковий запис" diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 0d3611f06ba..7812b80ca9c 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 127ade016ef..e0983a1cdaf 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ 未找到", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "恢复账户" diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 9e5951db064..00831af414d 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -6827,7 +6827,16 @@ }, "memberDecryptionTdeDescriptionEnd": { "message": "with automatic enrollment will turn on when this option is used.", - "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 account recovery administration policy with automatic enrollment will turn on when this option is used.'" + "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 master password reset policy with automatic enrollment will turn on when this option is used.'" + }, + "notFound": { + "message": "$RESOURCE$ not found", + "placeholders": { + "resource": { + "content": "$1", + "example": "Service Account" + } + } }, "recoverAccount": { "message": "Recover account" From ba5e890e86e1edda1600ee5231f1e60547f3255d Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 9 Jun 2023 09:50:42 +0200 Subject: [PATCH 05/29] Convert import select to the searchable CL select (#5573) --- .../tools/import-export/import.component.html | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/apps/web/src/app/tools/import-export/import.component.html b/apps/web/src/app/tools/import-export/import.component.html index 8911a63306f..447d52fefa7 100644 --- a/apps/web/src/app/tools/import-export/import.component.html +++ b/apps/web/src/app/tools/import-export/import.component.html @@ -5,27 +5,23 @@ {{ "personalOwnershipPolicyInEffectImports" | i18n }}
-
-
-
- - -
-
-
+ + 1. {{ "selectFormat" | i18n }} + + + + + + + + See detailed instructions on our help site at From d18b45a87ea07fc1daed74d3c54c3767fadc8746 Mon Sep 17 00:00:00 2001 From: titanism <101466223+titanism@users.noreply.github.com> Date: Fri, 9 Jun 2023 02:55:12 -0500 Subject: [PATCH 06/29] [PM-1060] Added new forwarder (Forward Email ) (#4809) * Added new forwarder (Forward Email ) * fix: fixed Basic authorization header * fix: fixed returned email value * feat: added verbose message for end-users (e.g. "Not Found" vs. "Domain does not exist on your account." (automatically localized with i18n for user) * fix: fixed Buffer.from to Utils.fromBufferToB64 * fix: fixed fromBufferToB64 to fromUtf8ToB64 * Remove try-catch to properly display api errors --------- Co-authored-by: Daniel James Smith --- .../popup/generator/generator.component.html | 22 +++++++++ .../src/app/tools/generator.component.html | 22 +++++++++ .../src/app/tools/generator.component.html | 22 +++++++++ apps/web/webpack.config.js | 1 + .../components/generator.component.ts | 1 + .../forward-email-forwarder.ts | 49 +++++++++++++++++++ .../email-forwarders/forwarder-options.ts | 5 ++ .../username/email-forwarders/index.ts | 1 + .../username/username-generation.service.ts | 6 +++ 9 files changed, 129 insertions(+) create mode 100644 libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts diff --git a/apps/browser/src/tools/popup/generator/generator.component.html b/apps/browser/src/tools/popup/generator/generator.component.html index 3b07c3b2cea..83b2c6dee78 100644 --- a/apps/browser/src/tools/popup/generator/generator.component.html +++ b/apps/browser/src/tools/popup/generator/generator.component.html @@ -405,6 +405,28 @@ /> + +
+ + +
+
+ + +
+
diff --git a/apps/desktop/src/app/tools/generator.component.html b/apps/desktop/src/app/tools/generator.component.html index 423b47b3f75..adbe6df3120 100644 --- a/apps/desktop/src/app/tools/generator.component.html +++ b/apps/desktop/src/app/tools/generator.component.html @@ -432,6 +432,28 @@ />
+ +
+ + +
+
+ + +
+
diff --git a/apps/web/src/app/tools/generator.component.html b/apps/web/src/app/tools/generator.component.html index 369812bc979..e2da0333e43 100644 --- a/apps/web/src/app/tools/generator.component.html +++ b/apps/web/src/app/tools/generator.component.html @@ -343,6 +343,28 @@ />
+
+
+ + +
+
+ + +
+
diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js index 54899dca7b1..0651603d56e 100644 --- a/apps/web/webpack.config.js +++ b/apps/web/webpack.config.js @@ -280,6 +280,7 @@ const devServer = https://quack.duckduckgo.com/api/email/addresses https://app.anonaddy.com/api/v1/aliases https://api.fastmail.com + https://api.forwardemail.net http://localhost:5000 ;object-src 'self' diff --git a/libs/angular/src/tools/generator/components/generator.component.ts b/libs/angular/src/tools/generator/components/generator.component.ts index af88ae24759..9ef73186583 100644 --- a/libs/angular/src/tools/generator/components/generator.component.ts +++ b/libs/angular/src/tools/generator/components/generator.component.ts @@ -242,6 +242,7 @@ export class GeneratorComponent implements OnInit { { name: "Fastmail", value: "fastmail", validForSelfHosted: true }, { name: "Firefox Relay", value: "firefoxrelay", validForSelfHosted: false }, { name: "SimpleLogin", value: "simplelogin", validForSelfHosted: true }, + { name: "Forward Email", value: "forwardemail", validForSelfHosted: true }, ]; this.usernameOptions = await this.usernameGenerationService.getOptions(); diff --git a/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts b/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts new file mode 100644 index 00000000000..a1b525f8f46 --- /dev/null +++ b/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts @@ -0,0 +1,49 @@ +import { ApiService } from "../../../../abstractions/api.service"; +import { Utils } from "../../../../misc/utils"; + +import { Forwarder } from "./forwarder"; +import { ForwarderOptions } from "./forwarder-options"; + +export class ForwardEmailForwarder implements Forwarder { + async generate(apiService: ApiService, options: ForwarderOptions): Promise { + if (options.apiKey == null || options.apiKey === "") { + throw "Invalid Forward Email API key."; + } + if (options.forwardemail?.domain == null || options.forwardemail.domain === "") { + throw "Invalid Forward Email domain."; + } + const requestInit: RequestInit = { + redirect: "manual", + cache: "no-store", + method: "POST", + headers: new Headers({ + Authorization: "Basic " + Utils.fromUtf8ToB64(options.apiKey + ":"), + "Content-Type": "application/json", + }), + }; + const url = `https://api.forwardemail.net/v1/domains/${options.forwardemail.domain}/aliases`; + requestInit.body = JSON.stringify({ + labels: options.website, + description: + (options.website != null ? "Website: " + options.website + ". " : "") + + "Generated by Bitwarden.", + }); + const request = new Request(url, requestInit); + const response = await apiService.nativeFetch(request); + if (response.status === 200 || response.status === 201) { + const json = await response.json(); + return json?.name + "@" + (json?.domain?.name || options.forwardemail.domain); + } + if (response.status === 401) { + throw "Invalid Forward Email API key."; + } + const json = await response.json(); + if (json?.message != null) { + throw "Forward Email error:\n" + json.message; + } + if (json?.error != null) { + throw "Forward Email error:\n" + json.error; + } + throw "Unknown Forward Email error occurred."; + } +} diff --git a/libs/common/src/tools/generator/username/email-forwarders/forwarder-options.ts b/libs/common/src/tools/generator/username/email-forwarders/forwarder-options.ts index ef5311f0d7d..0340eedca8f 100644 --- a/libs/common/src/tools/generator/username/email-forwarders/forwarder-options.ts +++ b/libs/common/src/tools/generator/username/email-forwarders/forwarder-options.ts @@ -3,6 +3,7 @@ export class ForwarderOptions { website: string; fastmail = new FastmailForwarderOptions(); anonaddy = new AnonAddyForwarderOptions(); + forwardemail = new ForwardEmailForwarderOptions(); } export class FastmailForwarderOptions { @@ -12,3 +13,7 @@ export class FastmailForwarderOptions { export class AnonAddyForwarderOptions { domain: string; } + +export class ForwardEmailForwarderOptions { + domain: string; +} diff --git a/libs/common/src/tools/generator/username/email-forwarders/index.ts b/libs/common/src/tools/generator/username/email-forwarders/index.ts index a9a437225ef..d102cc236ee 100644 --- a/libs/common/src/tools/generator/username/email-forwarders/index.ts +++ b/libs/common/src/tools/generator/username/email-forwarders/index.ts @@ -5,3 +5,4 @@ export { FirefoxRelayForwarder } from "./firefox-relay-forwarder"; export { Forwarder } from "./forwarder"; export { ForwarderOptions } from "./forwarder-options"; export { SimpleLoginForwarder } from "./simple-login-forwarder"; +export { ForwardEmailForwarder } from "./forward-email-forwarder"; diff --git a/libs/common/src/tools/generator/username/username-generation.service.ts b/libs/common/src/tools/generator/username/username-generation.service.ts index 6f9af5cb354..3ff9884331d 100644 --- a/libs/common/src/tools/generator/username/username-generation.service.ts +++ b/libs/common/src/tools/generator/username/username-generation.service.ts @@ -8,6 +8,7 @@ import { DuckDuckGoForwarder, FastmailForwarder, FirefoxRelayForwarder, + ForwardEmailForwarder, Forwarder, ForwarderOptions, SimpleLoginForwarder, @@ -22,6 +23,7 @@ const DefaultOptions = { catchallType: "random", forwardedService: "", forwardedAnonAddyDomain: "anonaddy.me", + forwardedForwardEmailDomain: "hideaddress.net", }; export class UsernameGenerationService implements UsernameGenerationServiceAbstraction { @@ -137,6 +139,10 @@ export class UsernameGenerationService implements UsernameGenerationServiceAbstr } else if (o.forwardedService === "duckduckgo") { forwarder = new DuckDuckGoForwarder(); forwarderOptions.apiKey = o.forwardedDuckDuckGoToken; + } else if (o.forwardedService === "forwardemail") { + forwarder = new ForwardEmailForwarder(); + forwarderOptions.apiKey = o.forwardedForwardEmailApiToken; + forwarderOptions.forwardemail.domain = o.forwardedForwardEmailDomain; } if (forwarder == null) { From ab260a3653afd68e617dc625d929756ba4b987c3 Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Fri, 9 Jun 2023 11:12:20 +0200 Subject: [PATCH 07/29] Fix broken import of misc/utils (#5586) --- .../username/email-forwarders/forward-email-forwarder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts b/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts index a1b525f8f46..98801c9e3da 100644 --- a/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts +++ b/libs/common/src/tools/generator/username/email-forwarders/forward-email-forwarder.ts @@ -1,5 +1,5 @@ import { ApiService } from "../../../../abstractions/api.service"; -import { Utils } from "../../../../misc/utils"; +import { Utils } from "../../../../platform/misc/utils"; import { Forwarder } from "./forwarder"; import { ForwarderOptions } from "./forwarder-options"; From c70d67bad3ccb9048d8dd4b55a56ede5810645d5 Mon Sep 17 00:00:00 2001 From: Thales Augusto Date: Fri, 9 Jun 2023 15:44:33 -0300 Subject: [PATCH 08/29] [PM-1823] Defining the card brand according to its number (#5204) * Defining the card brand according to its number * Moving cardBrandByPatterns function to Card View * Getting Card brand via cardBrandByPatterns function * Changing cardBrandByPatterns method to static. See: The reason being that someone wanting to use this outside of the onCardNumberChange would need to know to set the cc-number on the view-model before calling cardBrandByPatterns * Defining the card brand according to its number on Desktop * Defining the card brand according to its number on Web --- .../components/vault/add-edit.component.html | 1 + .../vault/app/vault/add-edit.component.html | 1 + .../individual-vault/add-edit.component.html | 1 + .../vault/components/add-edit.component.ts | 4 ++ .../common/src/vault/models/view/card.view.ts | 63 +++++++++++++++++++ .../importers/avast/avast-json-importer.ts | 3 +- libs/importer/src/importers/base-importer.ts | 63 ------------------- .../dashlane/dashlane-csv-importer.ts | 2 +- .../dashlane/dashlane-json-importer.ts | 2 +- .../src/importers/encryptr-csv-importer.ts | 2 +- .../importers/enpass/enpass-csv-importer.ts | 2 +- .../importers/enpass/enpass-json-importer.ts | 2 +- .../importers/fsecure/fsecure-fsk-importer.ts | 2 +- .../src/importers/lastpass-csv-importer.ts | 2 +- .../src/importers/myki-csv-importer.ts | 2 +- .../src/importers/nordpass-csv-importer.ts | 3 +- .../onepassword/onepassword-1pif-importer.ts | 2 +- .../onepassword/onepassword-1pux-importer.ts | 2 +- .../onepassword/onepassword-csv-importer.ts | 3 +- .../importers/passwordboss-json-importer.ts | 2 +- .../src/importers/remembear-csv-importer.ts | 2 +- .../src/importers/truekey-csv-importer.ts | 2 +- 22 files changed, 89 insertions(+), 79 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.html b/apps/browser/src/vault/popup/components/vault/add-edit.component.html index 9deda95d365..1373669ca17 100644 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.html +++ b/apps/browser/src/vault/popup/components/vault/add-edit.component.html @@ -163,6 +163,7 @@ class="monospaced" type="{{ showCardNumber ? 'text' : 'password' }}" name="Card.Number" + (input)="onCardNumberChange()" [(ngModel)]="cipher.card.number" appInputVerbatim [readonly]="!cipher.edit && editMode" diff --git a/apps/desktop/src/vault/app/vault/add-edit.component.html b/apps/desktop/src/vault/app/vault/add-edit.component.html index c8595c816ea..c26078394ad 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.html +++ b/apps/desktop/src/vault/app/vault/add-edit.component.html @@ -148,6 +148,7 @@ class="monospaced" type="{{ showCardNumber ? 'text' : 'password' }}" name="Card.Number" + (input)="onCardNumberChange()" [(ngModel)]="cipher.card.number" appInputVerbatim [readonly]="!cipher.edit && editMode" diff --git a/apps/web/src/app/vault/individual-vault/add-edit.component.html b/apps/web/src/app/vault/individual-vault/add-edit.component.html index f551d8e752c..a23332a2f96 100644 --- a/apps/web/src/app/vault/individual-vault/add-edit.component.html +++ b/apps/web/src/app/vault/individual-vault/add-edit.component.html @@ -440,6 +440,7 @@ class="form-control text-monospace" type="{{ showCardNumber ? 'text' : 'password' }}" name="Card.Number" + (input)="onCardNumberChange()" [(ngModel)]="cipher.card.number" appInputVerbatim autocomplete="new-password" diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts index 19896c20c14..83b8e3e0fda 100644 --- a/libs/angular/src/vault/components/add-edit.component.ts +++ b/libs/angular/src/vault/components/add-edit.component.ts @@ -368,6 +368,10 @@ export class AddEditComponent implements OnInit, OnDestroy { } } + onCardNumberChange(): void { + this.cipher.card.brand = CardView.getCardBrandByPatterns(this.cipher.card.number); + } + getCardExpMonthDisplay() { return this.cardExpMonthOptions.find((x) => x.value == this.cipher.card.expMonth)?.name; } diff --git a/libs/common/src/vault/models/view/card.view.ts b/libs/common/src/vault/models/view/card.view.ts index abeb381a7a6..25c70977076 100644 --- a/libs/common/src/vault/models/view/card.view.ts +++ b/libs/common/src/vault/models/view/card.view.ts @@ -81,4 +81,67 @@ export class CardView extends ItemView { static fromJSON(obj: Partial>): CardView { return Object.assign(new CardView(), obj); } + + // ref https://stackoverflow.com/a/5911300 + static getCardBrandByPatterns(cardNum: string): string { + if (cardNum == null || typeof cardNum !== "string" || cardNum.trim() === "") { + return null; + } + + // Visa + let re = new RegExp("^4"); + if (cardNum.match(re) != null) { + return "Visa"; + } + + // Mastercard + // Updated for Mastercard 2017 BINs expansion + if ( + /^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$/.test( + cardNum + ) + ) { + return "Mastercard"; + } + + // AMEX + re = new RegExp("^3[47]"); + if (cardNum.match(re) != null) { + return "Amex"; + } + + // Discover + re = new RegExp( + "^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)" + ); + if (cardNum.match(re) != null) { + return "Discover"; + } + + // Diners + re = new RegExp("^36"); + if (cardNum.match(re) != null) { + return "Diners Club"; + } + + // Diners - Carte Blanche + re = new RegExp("^30[0-5]"); + if (cardNum.match(re) != null) { + return "Diners Club"; + } + + // JCB + re = new RegExp("^35(2[89]|[3-8][0-9])"); + if (cardNum.match(re) != null) { + return "JCB"; + } + + // Visa Electron + re = new RegExp("^(4026|417500|4508|4844|491(3|7))"); + if (cardNum.match(re) != null) { + return "Visa"; + } + + return null; + } } diff --git a/libs/importer/src/importers/avast/avast-json-importer.ts b/libs/importer/src/importers/avast/avast-json-importer.ts index 08596032307..92d407e9455 100644 --- a/libs/importer/src/importers/avast/avast-json-importer.ts +++ b/libs/importer/src/importers/avast/avast-json-importer.ts @@ -1,5 +1,6 @@ import { SecureNoteType } from "@bitwarden/common/enums"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; +import { CardView } from "@bitwarden/common/vault/models/view/card.view"; import { ImportResult } from "../../models/import-result"; import { BaseImporter } from "../base-importer"; @@ -48,7 +49,7 @@ export class AvastJsonImporter extends BaseImporter implements Importer { cipher.card.cardholderName = this.getValueOrDefault(value.holderName); cipher.card.number = this.getValueOrDefault(value.cardNumber); cipher.card.code = this.getValueOrDefault(value.cvv); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); if (value.expirationDate != null) { if (value.expirationDate.month != null) { cipher.card.expMonth = value.expirationDate.month + ""; diff --git a/libs/importer/src/importers/base-importer.ts b/libs/importer/src/importers/base-importer.ts index d18f1d49e3c..fed35a391a1 100644 --- a/libs/importer/src/importers/base-importer.ts +++ b/libs/importer/src/importers/base-importer.ts @@ -241,69 +241,6 @@ export abstract class BaseImporter { return str.split(this.newLineRegex); } - // ref https://stackoverflow.com/a/5911300 - protected getCardBrand(cardNum: string) { - if (this.isNullOrWhitespace(cardNum)) { - return null; - } - - // Visa - let re = new RegExp("^4"); - if (cardNum.match(re) != null) { - return "Visa"; - } - - // Mastercard - // Updated for Mastercard 2017 BINs expansion - if ( - /^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$/.test( - cardNum - ) - ) { - return "Mastercard"; - } - - // AMEX - re = new RegExp("^3[47]"); - if (cardNum.match(re) != null) { - return "Amex"; - } - - // Discover - re = new RegExp( - "^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)" - ); - if (cardNum.match(re) != null) { - return "Discover"; - } - - // Diners - re = new RegExp("^36"); - if (cardNum.match(re) != null) { - return "Diners Club"; - } - - // Diners - Carte Blanche - re = new RegExp("^30[0-5]"); - if (cardNum.match(re) != null) { - return "Diners Club"; - } - - // JCB - re = new RegExp("^35(2[89]|[3-8][0-9])"); - if (cardNum.match(re) != null) { - return "JCB"; - } - - // Visa Electron - re = new RegExp("^(4026|417500|4508|4844|491(3|7))"); - if (cardNum.match(re) != null) { - return "Visa"; - } - - return null; - } - protected setCardExpiration(cipher: CipherView, expiration: string): boolean { if (this.isNullOrWhitespace(expiration)) { return false; diff --git a/libs/importer/src/importers/dashlane/dashlane-csv-importer.ts b/libs/importer/src/importers/dashlane/dashlane-csv-importer.ts index 4a16f9dc997..45aff447e30 100644 --- a/libs/importer/src/importers/dashlane/dashlane-csv-importer.ts +++ b/libs/importer/src/importers/dashlane/dashlane-csv-importer.ts @@ -136,7 +136,7 @@ export class DashlaneCsvImporter extends BaseImporter implements Importer { case "credit_card": cipher.card.cardholderName = row.account_name; cipher.card.number = row.cc_number; - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); cipher.card.code = row.code; this.setCardExpiration(cipher, `${row.expiration_month}/${row.expiration_year}`); diff --git a/libs/importer/src/importers/dashlane/dashlane-json-importer.ts b/libs/importer/src/importers/dashlane/dashlane-json-importer.ts index 1037df096b9..2cfb29f21ad 100644 --- a/libs/importer/src/importers/dashlane/dashlane-json-importer.ts +++ b/libs/importer/src/importers/dashlane/dashlane-json-importer.ts @@ -134,7 +134,7 @@ export class DashlaneJsonImporter extends BaseImporter implements Importer { cipher.type = CipherType.Card; cipher.name = this.getValueOrDefault(obj.bank); cipher.card.number = this.getValueOrDefault(obj.cardNumber); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); cipher.card.cardholderName = this.getValueOrDefault(obj.owner); if (!this.isNullOrWhitespace(cipher.card.brand)) { if (this.isNullOrWhitespace(cipher.name)) { diff --git a/libs/importer/src/importers/encryptr-csv-importer.ts b/libs/importer/src/importers/encryptr-csv-importer.ts index 73796cf1e33..a925ad24395 100644 --- a/libs/importer/src/importers/encryptr-csv-importer.ts +++ b/libs/importer/src/importers/encryptr-csv-importer.ts @@ -38,7 +38,7 @@ export class EncryptrCsvImporter extends BaseImporter implements Importer { cipher.card = new CardView(); cipher.card.cardholderName = this.getValueOrDefault(value["Name on card"]); cipher.card.number = this.getValueOrDefault(value["Card Number"]); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); cipher.card.code = this.getValueOrDefault(value.CVV); const expiry = this.getValueOrDefault(value.Expiry); if (!this.isNullOrWhitespace(expiry)) { diff --git a/libs/importer/src/importers/enpass/enpass-csv-importer.ts b/libs/importer/src/importers/enpass/enpass-csv-importer.ts index 26611b182e4..546dd33b222 100644 --- a/libs/importer/src/importers/enpass/enpass-csv-importer.ts +++ b/libs/importer/src/importers/enpass/enpass-csv-importer.ts @@ -90,7 +90,7 @@ export class EnpassCsvImporter extends BaseImporter implements Importer { continue; } else if (fieldNameLower === "number" && this.isNullOrWhitespace(cipher.card.number)) { cipher.card.number = fieldValue; - cipher.card.brand = this.getCardBrand(fieldValue); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); continue; } else if (fieldNameLower === "cvc" && this.isNullOrWhitespace(cipher.card.code)) { cipher.card.code = fieldValue; diff --git a/libs/importer/src/importers/enpass/enpass-json-importer.ts b/libs/importer/src/importers/enpass/enpass-json-importer.ts index 0af291e0ca8..76306721e54 100644 --- a/libs/importer/src/importers/enpass/enpass-json-importer.ts +++ b/libs/importer/src/importers/enpass/enpass-json-importer.ts @@ -126,7 +126,7 @@ export class EnpassJsonImporter extends BaseImporter implements Importer { cipher.card.cardholderName = field.value; } else if (field.type === "ccNumber" && this.isNullOrWhitespace(cipher.card.number)) { cipher.card.number = field.value; - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); } else if (field.type === "ccCvc" && this.isNullOrWhitespace(cipher.card.code)) { cipher.card.code = field.value; } else if (field.type === "ccExpiry" && this.isNullOrWhitespace(cipher.card.expYear)) { diff --git a/libs/importer/src/importers/fsecure/fsecure-fsk-importer.ts b/libs/importer/src/importers/fsecure/fsecure-fsk-importer.ts index ba66aa8dad1..db431a64561 100644 --- a/libs/importer/src/importers/fsecure/fsecure-fsk-importer.ts +++ b/libs/importer/src/importers/fsecure/fsecure-fsk-importer.ts @@ -66,7 +66,7 @@ export class FSecureFskImporter extends BaseImporter implements Importer { cipher.card = new CardView(); cipher.card.cardholderName = this.getValueOrDefault(entry.username); cipher.card.number = this.getValueOrDefault(entry.creditNumber); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); cipher.card.code = this.getValueOrDefault(entry.creditCvv); if (!this.isNullOrWhitespace(entry.creditExpiry)) { if (!this.setCardExpiration(cipher, entry.creditExpiry)) { diff --git a/libs/importer/src/importers/lastpass-csv-importer.ts b/libs/importer/src/importers/lastpass-csv-importer.ts index 53d46b831f3..464b1d3429d 100644 --- a/libs/importer/src/importers/lastpass-csv-importer.ts +++ b/libs/importer/src/importers/lastpass-csv-importer.ts @@ -122,7 +122,7 @@ export class LastPassCsvImporter extends BaseImporter implements Importer { card.cardholderName = this.getValueOrDefault(value.ccname); card.number = this.getValueOrDefault(value.ccnum); card.code = this.getValueOrDefault(value.cccsc); - card.brand = this.getCardBrand(value.ccnum); + card.brand = CardView.getCardBrandByPatterns(card.number); if (!this.isNullOrWhitespace(value.ccexp) && value.ccexp.indexOf("-") > -1) { const ccexpParts = (value.ccexp as string).split("-"); diff --git a/libs/importer/src/importers/myki-csv-importer.ts b/libs/importer/src/importers/myki-csv-importer.ts index 1b6fd9afdbc..c75a409376d 100644 --- a/libs/importer/src/importers/myki-csv-importer.ts +++ b/libs/importer/src/importers/myki-csv-importer.ts @@ -72,7 +72,7 @@ export class MykiCsvImporter extends BaseImporter implements Importer { cipher.type = CipherType.Card; cipher.card.cardholderName = this.getValueOrDefault(value.cardName); cipher.card.number = this.getValueOrDefault(value.cardNumber); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); cipher.card.expMonth = this.getValueOrDefault(value.exp_month); cipher.card.expYear = this.getValueOrDefault(value.exp_year); cipher.card.code = this.getValueOrDefault(value.cvv); diff --git a/libs/importer/src/importers/nordpass-csv-importer.ts b/libs/importer/src/importers/nordpass-csv-importer.ts index 7eb445335aa..d17a9fbfdd5 100644 --- a/libs/importer/src/importers/nordpass-csv-importer.ts +++ b/libs/importer/src/importers/nordpass-csv-importer.ts @@ -1,5 +1,6 @@ import { SecureNoteType } from "@bitwarden/common/enums"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; +import { CardView } from "@bitwarden/common/vault/models/view/card.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; @@ -66,7 +67,7 @@ export class NordPassCsvImporter extends BaseImporter implements Importer { cipher.card.cardholderName = this.getValueOrDefault(record.cardholdername); cipher.card.number = this.getValueOrDefault(record.cardnumber); cipher.card.code = this.getValueOrDefault(record.cvc); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); this.setCardExpiration(cipher, record.expirydate); break; diff --git a/libs/importer/src/importers/onepassword/onepassword-1pif-importer.ts b/libs/importer/src/importers/onepassword/onepassword-1pif-importer.ts index 688adf3bd7a..a4f78d203ba 100644 --- a/libs/importer/src/importers/onepassword/onepassword-1pif-importer.ts +++ b/libs/importer/src/importers/onepassword/onepassword-1pif-importer.ts @@ -198,7 +198,7 @@ export class OnePassword1PifImporter extends BaseImporter implements Importer { } else if (cipher.type === CipherType.Card) { if (this.isNullOrWhitespace(cipher.card.number) && fieldDesignation === "ccnum") { cipher.card.number = fieldValue; - cipher.card.brand = this.getCardBrand(fieldValue); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); return; } else if (this.isNullOrWhitespace(cipher.card.code) && fieldDesignation === "cvv") { cipher.card.code = fieldValue; diff --git a/libs/importer/src/importers/onepassword/onepassword-1pux-importer.ts b/libs/importer/src/importers/onepassword/onepassword-1pux-importer.ts index ebf596a72e9..b8329a5d449 100644 --- a/libs/importer/src/importers/onepassword/onepassword-1pux-importer.ts +++ b/libs/importer/src/importers/onepassword/onepassword-1pux-importer.ts @@ -407,7 +407,7 @@ export class OnePassword1PuxImporter extends BaseImporter implements Importer { private fillCreditCard(field: FieldsEntity, fieldValue: string, cipher: CipherView): boolean { if (this.isNullOrWhitespace(cipher.card.number) && field.id === "ccnum") { cipher.card.number = fieldValue; - cipher.card.brand = this.getCardBrand(fieldValue); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); return true; } diff --git a/libs/importer/src/importers/onepassword/onepassword-csv-importer.ts b/libs/importer/src/importers/onepassword/onepassword-csv-importer.ts index f756d619417..3f920a7d4f1 100644 --- a/libs/importer/src/importers/onepassword/onepassword-csv-importer.ts +++ b/libs/importer/src/importers/onepassword/onepassword-csv-importer.ts @@ -1,5 +1,6 @@ import { FieldType } from "@bitwarden/common/enums"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; +import { CardView } from "@bitwarden/common/vault/models/view/card.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { ImportResult } from "../../models/import-result"; @@ -295,7 +296,7 @@ export abstract class OnePasswordCsvImporter extends BaseImporter implements Imp context.lowerProperty.includes("number") ) { context.cipher.card.number = context.importRecord[context.property]; - context.cipher.card.brand = this.getCardBrand(context.cipher.card.number); + context.cipher.card.brand = CardView.getCardBrandByPatterns(context.cipher.card.number); return true; } return false; diff --git a/libs/importer/src/importers/passwordboss-json-importer.ts b/libs/importer/src/importers/passwordboss-json-importer.ts index f819408d22b..8c426575068 100644 --- a/libs/importer/src/importers/passwordboss-json-importer.ts +++ b/libs/importer/src/importers/passwordboss-json-importer.ts @@ -75,7 +75,7 @@ export class PasswordBossJsonImporter extends BaseImporter implements Importer { if (cipher.type === CipherType.Card) { if (property === "cardNumber") { cipher.card.number = val; - cipher.card.brand = this.getCardBrand(val); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); continue; } else if (property === "nameOnCard") { cipher.card.cardholderName = val; diff --git a/libs/importer/src/importers/remembear-csv-importer.ts b/libs/importer/src/importers/remembear-csv-importer.ts index 236245f2308..f23271892d4 100644 --- a/libs/importer/src/importers/remembear-csv-importer.ts +++ b/libs/importer/src/importers/remembear-csv-importer.ts @@ -31,7 +31,7 @@ export class RememBearCsvImporter extends BaseImporter implements Importer { cipher.card = new CardView(); cipher.card.cardholderName = this.getValueOrDefault(value.cardholder); cipher.card.number = this.getValueOrDefault(value.number); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); cipher.card.code = this.getValueOrDefault(value.verification); try { diff --git a/libs/importer/src/importers/truekey-csv-importer.ts b/libs/importer/src/importers/truekey-csv-importer.ts index f2352ac3a8b..3d52be1bd85 100644 --- a/libs/importer/src/importers/truekey-csv-importer.ts +++ b/libs/importer/src/importers/truekey-csv-importer.ts @@ -50,7 +50,7 @@ export class TrueKeyCsvImporter extends BaseImporter implements Importer { cipher.card = new CardView(); cipher.card.cardholderName = this.getValueOrDefault(value.cardholder); cipher.card.number = this.getValueOrDefault(value.number); - cipher.card.brand = this.getCardBrand(cipher.card.number); + cipher.card.brand = CardView.getCardBrandByPatterns(cipher.card.number); if (!this.isNullOrWhitespace(value.expiryDate)) { try { const expDate = new Date(value.expiryDate); From f436e97c293d2315f4026b3d05491c10fdedb865 Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Sat, 10 Jun 2023 20:08:14 -0400 Subject: [PATCH 09/29] New Feature Flag Route Guard introduced in #5465 uses a translation which is missing from Desktop & Browser. Ported over the web translation. (#5588) --- apps/browser/src/_locales/en/messages.json | 3 +++ apps/desktop/src/locales/en/messages.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 69d26333a84..27c985453e9 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2234,5 +2234,8 @@ "us": { "message": "US", "description": "United States" + }, + "accessDenied": { + "message": "Access denied. You do not have permission to view this page." } } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 2e166573fb8..9debdbc13fe 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2265,5 +2265,8 @@ }, "selfHosted": { "message": "Self-hosted" + }, + "accessDenied": { + "message": "Access denied. You do not have permission to view this page." } } From 0ab982038cc62edc8532e19b4b52613078b1327b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Mon, 12 Jun 2023 10:56:03 +0100 Subject: [PATCH 10/29] [AC-1088] Truncating collection names on Groups table (#5236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [AC-1088] Set no-wrap to 'select all' column on groups table * [AC-1088] Using EllipsisPipe on GroupsComponent to truncate group names * [AC-1088] Reverted using no-wrap on column header * [AC-1088] Removed truncateCollectionNames * [AC-1088] Added 'truncate' option to badge and badge-list components * [AC-1088] Truncating collection names on groups component * [AC-1088] Marked EllipsisPipe as deprecated * [AC-1088] Removed EllipsisPipe from GroupsComponent * [AC-1088] Added badge truncate to storybook stories * [AC-1088] Setting badge css requirements for truncate * [AC-1088] Added storybook stories for truncated badges * [AC-1088] Set badges truncate default value to true * [AC-1088] Set badges to use class tw-inline-block and tw-align-text-top * [AC-1088] Set title on each badge list item if truncated * [AC-1088] Set title on badge if truncated * [AC-1088] Removed duplicate truncate on badge-list component * [AC-1088] Swapped setting badge title from ngAfterContentInit to HostBinding * [AC-1088] Configured badge stories to have the truncate option * [AC-1088] Fixed badges tooltip to not include commas added for screen readers on badge lists * [AC-1088] Added lengthy text to single badge on storybook * [AC-1088] In badge-list moved the commas out from the badges * [AC-1088] Removed irrelevant comment and moved the text align class next to other font classes --- libs/angular/src/platform/pipes/ellipsis.pipe.ts | 3 +++ .../src/badge-list/badge-list.component.html | 8 +++++--- .../src/badge-list/badge-list.component.ts | 1 + .../src/badge-list/badge-list.stories.ts | 14 +++++++++++++- libs/components/src/badge/badge.directive.ts | 12 +++++++++--- libs/components/src/badge/badge.stories.ts | 14 +++++++++++--- 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/libs/angular/src/platform/pipes/ellipsis.pipe.ts b/libs/angular/src/platform/pipes/ellipsis.pipe.ts index 081dba11abe..dd271f94627 100644 --- a/libs/angular/src/platform/pipes/ellipsis.pipe.ts +++ b/libs/angular/src/platform/pipes/ellipsis.pipe.ts @@ -3,6 +3,9 @@ import { Pipe, PipeTransform } from "@angular/core"; @Pipe({ name: "ellipsis", }) +/** + * @deprecated Use the tailwind class 'tw-truncate' instead + */ export class EllipsisPipe implements PipeTransform { transform(value: string, limit = 25, completeWords = false, ellipsis = "...") { if (value.length <= limit) { diff --git a/libs/components/src/badge-list/badge-list.component.html b/libs/components/src/badge-list/badge-list.component.html index cd0310d889c..3e429b94301 100644 --- a/libs/components/src/badge-list/badge-list.component.html +++ b/libs/components/src/badge-list/badge-list.component.html @@ -1,8 +1,10 @@
- - {{ item }} + + + {{ item }} + , - + {{ "plusNMore" | i18n : (items.length - filteredItems.length).toString() }} diff --git a/libs/components/src/badge-list/badge-list.component.ts b/libs/components/src/badge-list/badge-list.component.ts index 09cbfb9d971..64deae21b9f 100644 --- a/libs/components/src/badge-list/badge-list.component.ts +++ b/libs/components/src/badge-list/badge-list.component.ts @@ -14,6 +14,7 @@ export class BadgeListComponent implements OnChanges { @Input() badgeType: BadgeTypes = "primary"; @Input() items: string[] = []; + @Input() truncate = true; @Input() get maxItems(): number | undefined { diff --git a/libs/components/src/badge-list/badge-list.stories.ts b/libs/components/src/badge-list/badge-list.stories.ts index 1c4536c1f99..92e9e148753 100644 --- a/libs/components/src/badge-list/badge-list.stories.ts +++ b/libs/components/src/badge-list/badge-list.stories.ts @@ -29,6 +29,7 @@ export default { ], args: { badgeType: "primary", + truncate: false, }, parameters: { design: { @@ -44,7 +45,7 @@ export const Default: Story = { render: (args) => ({ props: args, template: ` - + `, }), @@ -52,5 +53,16 @@ export const Default: Story = { badgeType: "info", maxItems: 3, items: ["Badge 1", "Badge 2", "Badge 3", "Badge 4", "Badge 5"], + truncate: false, + }, +}; + +export const Truncated: Story = { + ...Default, + args: { + badgeType: "info", + maxItems: 3, + items: ["Badge 1", "Badge 2 containing lengthy text", "Badge 3", "Badge 4", "Badge 5"], + truncate: true, }, }; diff --git a/libs/components/src/badge/badge.directive.ts b/libs/components/src/badge/badge.directive.ts index e8c771c48ca..14dc96edd53 100644 --- a/libs/components/src/badge/badge.directive.ts +++ b/libs/components/src/badge/badge.directive.ts @@ -26,11 +26,12 @@ const hoverStyles: Record = { export class BadgeDirective { @HostBinding("class") get classList() { return [ - "tw-inline", + "tw-inline-block", "tw-py-0.5", "tw-px-1.5", "tw-font-bold", "tw-text-center", + "tw-align-text-top", "!tw-text-contrast", "tw-rounded", "tw-border-none", @@ -44,14 +45,19 @@ export class BadgeDirective { "focus:tw-ring-primary-700", ] .concat(styles[this.badgeType]) - .concat(this.hasHoverEffects ? hoverStyles[this.badgeType] : []); + .concat(this.hasHoverEffects ? hoverStyles[this.badgeType] : []) + .concat(this.truncate ? ["tw-truncate", "tw-max-w-40"] : []); + } + @HostBinding("attr.title") get title() { + return this.truncate ? this.el.nativeElement.textContent.trim() : null; } @Input() badgeType: BadgeTypes = "primary"; + @Input() truncate = true; private hasHoverEffects = false; - constructor(el: ElementRef) { + constructor(private el: ElementRef) { this.hasHoverEffects = el?.nativeElement?.nodeName != "SPAN"; } } diff --git a/libs/components/src/badge/badge.stories.ts b/libs/components/src/badge/badge.stories.ts index 2efe5450d00..5912250e0e1 100644 --- a/libs/components/src/badge/badge.stories.ts +++ b/libs/components/src/badge/badge.stories.ts @@ -14,6 +14,7 @@ export default { ], args: { badgeType: "primary", + truncate: false, }, parameters: { design: { @@ -29,11 +30,11 @@ export const Primary: Story = { render: (args) => ({ props: args, template: ` - Span Badge + Span Badge containing lengthy text

- Link Badge + Link Badge

- Button + Button `, }), }; @@ -72,3 +73,10 @@ export const Info: Story = { badgeType: "info", }, }; + +export const Truncated: Story = { + ...Primary, + args: { + truncate: true, + }, +}; From cd85a4c03903c9e9aa92106d77a847e988a4fd2e Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 12 Jun 2023 20:59:59 +0200 Subject: [PATCH 11/29] Automatically load SIMD binary for argon2 (#4921) --- apps/desktop/webpack.main.js | 1 + package-lock.json | 211 ++++++++++++++++++++++++++-- package.json | 4 +- patches/argon2-browser+1.18.0.patch | 63 +++++++++ 4 files changed, 264 insertions(+), 15 deletions(-) create mode 100644 patches/argon2-browser+1.18.0.patch diff --git a/apps/desktop/webpack.main.js b/apps/desktop/webpack.main.js index 52240e84e3e..efd1de20d13 100644 --- a/apps/desktop/webpack.main.js +++ b/apps/desktop/webpack.main.js @@ -74,6 +74,7 @@ const main = { { from: "./src/images", to: "images" }, { from: "./src/locales", to: "locales" }, "../../node_modules/argon2-browser/dist/argon2.wasm", + "../../node_modules/argon2-browser/dist/argon2-simd.wasm", ], }), new EnvironmentPlugin({ diff --git a/package-lock.json b/package-lock.json index 51804298106..5a380576c99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "@bitwarden/clients", "version": "0.0.0", + "hasInstallScript": true, "license": "GPL-3.0", "workspaces": [ "apps/*", @@ -58,6 +59,7 @@ "nord": "0.2.1", "open": "8.4.2", "papaparse": "5.4.1", + "patch-package": "6.5.1", "popper.js": "1.16.1", "proper-lockfile": "4.1.2", "qrious": "4.0.2", @@ -10793,8 +10795,7 @@ "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==" }, "node_modules/@yarnpkg/parsers": { "version": "2.5.1", @@ -11869,7 +11870,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, "engines": { "node": ">= 4.0.0" } @@ -12641,7 +12641,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -17761,7 +17760,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -17920,6 +17918,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/findup-sync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", @@ -21341,7 +21347,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -21672,8 +21677,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isobject": { "version": "3.0.1", @@ -23098,7 +23102,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -23175,6 +23178,14 @@ "node": ">=0.10.0" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -25624,7 +25635,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -26331,6 +26341,11 @@ "dev": true, "optional": true }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -27650,6 +27665,178 @@ "node": ">=0.10.0" } }, + "node_modules/patch-package": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.1.tgz", + "integrity": "sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "cross-spawn": "^6.0.5", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "is-ci": "^2.0.0", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^5.6.0", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^1.10.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=10", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/patch-package/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/patch-package/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/patch-package/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/patch-package/node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/patch-package/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/patch-package/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/patch-package/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/patch-package/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-package/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -27835,7 +28022,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -33601,7 +33787,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -34441,7 +34626,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, "engines": { "node": ">= 10.0.0" } @@ -35818,7 +36002,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "engines": { "node": ">= 6" } diff --git a/package.json b/package.json index 9c298958b86..7ffeaaddc25 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "docs:json": "compodoc -p ./tsconfig.json -e json -d .", "storybook": "ng run components:storybook", "build-storybook": "ng run components:build-storybook", - "build-storybook:ci": "ng run components:build-storybook --webpack-stats-json" + "build-storybook:ci": "ng run components:build-storybook --webpack-stats-json", + "postinstall": "patch-package" }, "workspaces": [ "apps/*", @@ -189,6 +190,7 @@ "nord": "0.2.1", "open": "8.4.2", "papaparse": "5.4.1", + "patch-package": "6.5.1", "popper.js": "1.16.1", "proper-lockfile": "4.1.2", "qrious": "4.0.2", diff --git a/patches/argon2-browser+1.18.0.patch b/patches/argon2-browser+1.18.0.patch new file mode 100644 index 00000000000..7161e9aa6eb --- /dev/null +++ b/patches/argon2-browser+1.18.0.patch @@ -0,0 +1,63 @@ +diff --git a/node_modules/argon2-browser/lib/argon2.js b/node_modules/argon2-browser/lib/argon2.js +index ffa77a5..b498e2d 100644 +--- a/node_modules/argon2-browser/lib/argon2.js ++++ b/node_modules/argon2-browser/lib/argon2.js +@@ -78,16 +78,27 @@ + if (global.loadArgon2WasmBinary) { + return global.loadArgon2WasmBinary(); + } ++ ++ const simd = checkIfSIMDSupported(); ++ + if (typeof require === 'function') { +- return Promise.resolve(require('../dist/argon2.wasm')).then( +- (wasmModule) => { +- return decodeWasmBinary(wasmModule); +- } +- ); ++ if (simd) { ++ return Promise.resolve(require('../dist/argon2-simd.wasm')).then( ++ (wasmModule) => { ++ return decodeWasmBinary(wasmModule); ++ } ++ ); ++ } else { ++ return Promise.resolve(require('../dist/argon2.wasm')).then( ++ (wasmModule) => { ++ return decodeWasmBinary(wasmModule); ++ } ++ ); ++ } + } + const wasmPath = + global.argon2WasmPath || +- 'node_modules/argon2-browser/dist/argon2.wasm'; ++ 'node_modules/argon2-browser/dist/argon2' + (simd? "-simd" : "") + '.wasm'; + return fetch(wasmPath) + .then((response) => response.arrayBuffer()) + .then((ab) => new Uint8Array(ab)); +@@ -354,6 +365,24 @@ + } + } + ++ // ref: https://stackoverflow.com/a/47880734/1090359 ++ // ref: https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/simd/module.wat (translated with wat2wasm) ++ function checkIfSIMDSupported() { ++ try { ++ if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") { ++ const module = new WebAssembly.Module( ++ Uint8Array.of(0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7b, 0x03, 0x02, 0x01, 0x00, 0x0a, 0x0a, 0x01, 0x08, 0x00, 0x41, 0x00, 0xfd, 0x0f, 0xfd, 0x62, 0x0b) ++ ); ++ if (module instanceof WebAssembly.Module) { ++ return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; ++ } ++ } ++ } catch { ++ return false; ++ } ++ return false; ++ } ++ + return { + ArgonType, + hash: argon2Hash, From 22caae116c33b7ecc545170b58a29414c685df3c Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:03:32 +1000 Subject: [PATCH 12/29] Restrict angular imports (#5597) * Refactor restricted imports eslint rule, add angular deps * Move FormValidationErrorsService into libs/angular * Remove angular decorators from configService * Remove angular decorator from anonymousHubService --- .eslintrc.json | 27 +++++++++---------- .../browser/src/auth/popup/login.component.ts | 2 +- .../src/auth/popup/register.component.ts | 2 +- .../desktop/src/auth/login/login.component.ts | 2 +- apps/desktop/src/auth/register.component.ts | 2 +- .../web/src/app/auth/login/login.component.ts | 2 +- .../register-form/register-form.component.ts | 2 +- .../src/auth/components/login.component.ts | 9 ++++--- .../src/components/register.component.ts | 8 +++--- .../form-validation-errors.service.ts | 0 .../form-validation-errors.service.ts | 0 .../src/services/jslib-services.module.ts | 4 +-- .../validators/inputsFieldMatch.validator.ts | 2 +- .../services/config/config.service.ts | 14 +++------- .../src/services/anonymousHub.service.ts | 2 -- 15 files changed, 34 insertions(+), 44 deletions(-) rename libs/{common => angular}/src/platform/abstractions/form-validation-errors.service.ts (100%) rename libs/{common => angular}/src/platform/services/form-validation-errors.service.ts (100%) diff --git a/.eslintrc.json b/.eslintrc.json index 5b431ff2740..45a9d063a98 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -90,22 +90,21 @@ "error", { "zones": [ - // Do not allow angular/node code to be imported into common { + // avoid specific frameworks or large dependencies in common "target": "./libs/common/**/*", - "from": "./libs/angular/**/*" - }, - { - "target": "./libs/common/**/*", - "from": "./libs/node/**/*" - }, - { - "target": "./libs/common/**/*", - "from": "./libs/importer/**/*" - }, - { - "target": "./libs/common/**/*", - "from": "./libs/exporter/**/*" + "from": [ + // Angular + "./libs/angular/**/*", + "./node_modules/@angular*/**/*", + + // Node + "./libs/node/**/*", + + // Import/export + "./libs/importer/**/*", + "./libs/exporter/**/*" + ] } ] } diff --git a/apps/browser/src/auth/popup/login.component.ts b/apps/browser/src/auth/popup/login.component.ts index 496de2c54b5..776b792fa1d 100644 --- a/apps/browser/src/auth/popup/login.component.ts +++ b/apps/browser/src/auth/popup/login.component.ts @@ -3,13 +3,13 @@ import { FormBuilder } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component"; +import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; 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"; diff --git a/apps/browser/src/auth/popup/register.component.ts b/apps/browser/src/auth/popup/register.component.ts index b061e1faf6a..ad7a9e1cc68 100644 --- a/apps/browser/src/auth/popup/register.component.ts +++ b/apps/browser/src/auth/popup/register.component.ts @@ -3,13 +3,13 @@ import { UntypedFormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component"; +import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; 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"; diff --git a/apps/desktop/src/auth/login/login.component.ts b/apps/desktop/src/auth/login/login.component.ts index 77894b77f6f..de5ee51a7ae 100644 --- a/apps/desktop/src/auth/login/login.component.ts +++ b/apps/desktop/src/auth/login/login.component.ts @@ -5,6 +5,7 @@ import { Subject, takeUntil } from "rxjs"; import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component"; +import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; @@ -13,7 +14,6 @@ import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.ser import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; diff --git a/apps/desktop/src/auth/register.component.ts b/apps/desktop/src/auth/register.component.ts index 6cf46de7c70..f4324f12379 100644 --- a/apps/desktop/src/auth/register.component.ts +++ b/apps/desktop/src/auth/register.component.ts @@ -3,6 +3,7 @@ import { UntypedFormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component"; +import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; @@ -10,7 +11,6 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; 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"; diff --git a/apps/web/src/app/auth/login/login.component.ts b/apps/web/src/app/auth/login/login.component.ts index 430e3cfb7d9..52ee5a89bdd 100644 --- a/apps/web/src/app/auth/login/login.component.ts +++ b/apps/web/src/app/auth/login/login.component.ts @@ -5,6 +5,7 @@ import { Subject, takeUntil } from "rxjs"; import { first } from "rxjs/operators"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component"; +import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -18,7 +19,6 @@ import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; diff --git a/apps/web/src/app/auth/register-form/register-form.component.ts b/apps/web/src/app/auth/register-form/register-form.component.ts index 14071aba7c2..887f5562481 100644 --- a/apps/web/src/app/auth/register-form/register-form.component.ts +++ b/apps/web/src/app/auth/register-form/register-form.component.ts @@ -3,6 +3,7 @@ import { UntypedFormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component"; +import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; @@ -12,7 +13,6 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { ReferenceEventRequest } from "@bitwarden/common/models/request/reference-event.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; 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"; diff --git a/libs/angular/src/auth/components/login.component.ts b/libs/angular/src/auth/components/login.component.ts index cdb8f303699..f5a7a27af46 100644 --- a/libs/angular/src/auth/components/login.component.ts +++ b/libs/angular/src/auth/components/login.component.ts @@ -12,10 +12,6 @@ import { PasswordLogInCredentials } from "@bitwarden/common/auth/models/domain/l import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { - AllValidationErrors, - FormValidationErrorsService, -} from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; 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"; @@ -23,6 +19,11 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { Utils } from "@bitwarden/common/platform/misc/utils"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { + AllValidationErrors, + FormValidationErrorsService, +} from "../../platform/abstractions/form-validation-errors.service"; + import { CaptchaProtectedComponent } from "./captcha-protected.component"; @Directive() diff --git a/libs/angular/src/components/register.component.ts b/libs/angular/src/components/register.component.ts index ac28dc6803b..510da6160a6 100644 --- a/libs/angular/src/components/register.component.ts +++ b/libs/angular/src/components/register.component.ts @@ -13,10 +13,6 @@ import { ReferenceEventRequest } from "@bitwarden/common/models/request/referenc import { RegisterRequest } from "@bitwarden/common/models/request/register.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { - AllValidationErrors, - FormValidationErrorsService, -} from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; 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"; @@ -25,6 +21,10 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { CaptchaProtectedComponent } from "../auth/components/captcha-protected.component"; +import { + AllValidationErrors, + FormValidationErrorsService, +} from "../platform/abstractions/form-validation-errors.service"; import { DialogServiceAbstraction, SimpleDialogType } from "../services/dialog"; import { PasswordColorText } from "../shared/components/password-strength/password-strength.component"; import { InputsFieldMatch } from "../validators/inputsFieldMatch.validator"; diff --git a/libs/common/src/platform/abstractions/form-validation-errors.service.ts b/libs/angular/src/platform/abstractions/form-validation-errors.service.ts similarity index 100% rename from libs/common/src/platform/abstractions/form-validation-errors.service.ts rename to libs/angular/src/platform/abstractions/form-validation-errors.service.ts diff --git a/libs/common/src/platform/services/form-validation-errors.service.ts b/libs/angular/src/platform/services/form-validation-errors.service.ts similarity index 100% rename from libs/common/src/platform/services/form-validation-errors.service.ts rename to libs/angular/src/platform/services/form-validation-errors.service.ts diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 9862ca90e84..51e3cdc3fc0 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -68,7 +68,6 @@ import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/pla import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/platform/abstractions/environment.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/platform/abstractions/file-upload/file-upload.service"; -import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -90,7 +89,6 @@ import { EncryptServiceImplementation } from "@bitwarden/common/platform/service import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; import { EnvironmentService } from "@bitwarden/common/platform/services/environment.service"; import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service"; -import { FormValidationErrorsService } from "@bitwarden/common/platform/services/form-validation-errors.service"; import { StateMigrationService } from "@bitwarden/common/platform/services/state-migration.service"; import { StateService } from "@bitwarden/common/platform/services/state.service"; import { ValidationService } from "@bitwarden/common/platform/services/validation.service"; @@ -148,7 +146,9 @@ import { import { AuthGuard } from "../auth/guards/auth.guard"; import { LockGuard } from "../auth/guards/lock.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 { diff --git a/libs/angular/src/validators/inputsFieldMatch.validator.ts b/libs/angular/src/validators/inputsFieldMatch.validator.ts index 7c7c876d0db..f360b5e5ee5 100644 --- a/libs/angular/src/validators/inputsFieldMatch.validator.ts +++ b/libs/angular/src/validators/inputsFieldMatch.validator.ts @@ -1,6 +1,6 @@ import { AbstractControl, UntypedFormGroup, ValidatorFn } from "@angular/forms"; -import { FormGroupControls } from "@bitwarden/common/platform/abstractions/form-validation-errors.service"; +import { FormGroupControls } from "../platform/abstractions/form-validation-errors.service"; export class InputsFieldMatch { //check to ensure two fields do not have the same value diff --git a/libs/common/src/platform/services/config/config.service.ts b/libs/common/src/platform/services/config/config.service.ts index 5149c4e4b7e..d1258c47a23 100644 --- a/libs/common/src/platform/services/config/config.service.ts +++ b/libs/common/src/platform/services/config/config.service.ts @@ -1,5 +1,4 @@ -import { Injectable, OnDestroy } from "@angular/core"; -import { BehaviorSubject, Subject, concatMap, from, takeUntil, timer } from "rxjs"; +import { BehaviorSubject, concatMap, from, timer } from "rxjs"; import { AuthService } from "../../../auth/abstractions/auth.service"; import { AuthenticationStatus } from "../../../auth/enums/authentication-status"; @@ -11,11 +10,9 @@ import { EnvironmentService } from "../../abstractions/environment.service"; import { StateService } from "../../abstractions/state.service"; import { ServerConfigData } from "../../models/data/server-config.data"; -@Injectable() -export class ConfigService implements ConfigServiceAbstraction, OnDestroy { +export class ConfigService implements ConfigServiceAbstraction { protected _serverConfig = new BehaviorSubject(null); serverConfig$ = this._serverConfig.asObservable(); - private destroy$ = new Subject(); constructor( private stateService: StateService, @@ -30,16 +27,11 @@ export class ConfigService implements ConfigServiceAbstraction, OnDestroy { this._serverConfig.next(serverConfig); }); - this.environmentService.urls.pipe(takeUntil(this.destroy$)).subscribe(() => { + this.environmentService.urls.subscribe(() => { this.fetchServerConfig(); }); } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - async fetchServerConfig(): Promise { try { const response = await this.configApiService.get(); diff --git a/libs/common/src/services/anonymousHub.service.ts b/libs/common/src/services/anonymousHub.service.ts index 32ea272cedd..31b394ae587 100644 --- a/libs/common/src/services/anonymousHub.service.ts +++ b/libs/common/src/services/anonymousHub.service.ts @@ -1,4 +1,3 @@ -import { Injectable } from "@angular/core"; import { HttpTransportType, HubConnection, @@ -17,7 +16,6 @@ import { NotificationResponse, } from "./../models/response/notification.response"; -@Injectable() export class AnonymousHubService implements AnonymousHubServiceAbstraction { private anonHubConnection: HubConnection; private url: string; From 72a5ba455cc114c6d46602b5086c9063bc3c390e Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Tue, 13 Jun 2023 23:22:25 +0200 Subject: [PATCH 13/29] [PM-2367] [BEEEP]: Extract password strength from password-generation-service (#5502) * Extract passwordStrength from passwordGenerationService Extract passwordStrength from password-generation.service.ts Create new password-strength.service.ts Create new password-strength.service.abstraction.ts Register new password-strength service Fix usages in libs * Fix usage in web * Fix usage in desktop * Fix usage in CLI * Fix usage in browser Move password-generation-factory to tools * Fix tests * Change dependency in jslib-services.module --- .../service-factories/auth-service.factory.ts | 12 ++--- apps/browser/src/auth/popup/lock.component.ts | 6 +-- .../browser/context-menu-clicked-handler.ts | 2 +- .../browser/src/background/main.background.ts | 10 +++- .../platform/listeners/on-command-listener.ts | 8 +-- .../src/popup/services/services.module.ts | 6 +++ .../password-generation-service.factory.ts | 46 ++++++++++++++++ .../password-strength-service.factory.ts | 23 ++++++++ apps/cli/src/auth/commands/login.command.ts | 4 +- apps/cli/src/bw.ts | 9 +++- apps/cli/src/program.ts | 1 + apps/desktop/src/auth/lock.component.ts | 6 +-- .../tools/weak-passwords-report.component.ts | 6 +-- apps/web/src/app/auth/lock.component.ts | 6 +-- .../web/src/app/auth/login/login.component.ts | 4 +- .../pages/weak-passwords-report.component.ts | 6 +-- .../src/auth/components/lock.component.ts | 6 +-- .../src/services/jslib-services.module.ts | 11 +++- .../password-strength.component.ts | 6 +-- .../login-strategies/login.strategy.spec.ts | 11 ++-- .../password-login.strategy.spec.ts | 17 +++--- .../password-login.strategy.ts | 6 +-- libs/common/src/auth/services/auth.service.ts | 6 +-- ...password-generation.service.abstraction.ts | 7 --- .../password/password-generation.service.ts | 50 ----------------- .../src/tools/password-strength/index.ts | 2 + .../password-strength.service.abstraction.ts | 5 ++ .../password-strength.service.ts | 53 +++++++++++++++++++ 28 files changed, 224 insertions(+), 111 deletions(-) create mode 100644 apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts create mode 100644 apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts create mode 100644 libs/common/src/tools/password-strength/index.ts create mode 100644 libs/common/src/tools/password-strength/password-strength.service.abstraction.ts create mode 100644 libs/common/src/tools/password-strength/password-strength.service.ts diff --git a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts index eefbf8e27fb..5612cedb91c 100644 --- a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts @@ -5,10 +5,6 @@ import { policyServiceFactory, PolicyServiceInitOptions, } from "../../../admin-console/background/service-factories/policy-service.factory"; -import { - passwordGenerationServiceFactory, - PasswordGenerationServiceInitOptions, -} from "../../../background/service-factories/password-generation-service.factory"; import { apiServiceFactory, ApiServiceInitOptions, @@ -51,6 +47,10 @@ import { stateServiceFactory, StateServiceInitOptions, } from "../../../platform/background/service-factories/state-service.factory"; +import { + passwordStrengthServiceFactory, + PasswordStrengthServiceInitOptions, +} from "../../../tools/background/service_factories/password-strength-service.factory"; import { keyConnectorServiceFactory, @@ -75,7 +75,7 @@ export type AuthServiceInitOptions = AuthServiceFactoyOptions & I18nServiceInitOptions & EncryptServiceInitOptions & PolicyServiceInitOptions & - PasswordGenerationServiceInitOptions; + PasswordStrengthServiceInitOptions; export function authServiceFactory( cache: { authService?: AbstractAuthService } & CachedServices, @@ -100,7 +100,7 @@ export function authServiceFactory( await twoFactorServiceFactory(cache, opts), await i18nServiceFactory(cache, opts), await encryptServiceFactory(cache, opts), - await passwordGenerationServiceFactory(cache, opts), + await passwordStrengthServiceFactory(cache, opts), await policyServiceFactory(cache, opts) ) ); diff --git a/apps/browser/src/auth/popup/lock.component.ts b/apps/browser/src/auth/popup/lock.component.ts index d95ff79fc8f..d13609f61d4 100644 --- a/apps/browser/src/auth/popup/lock.component.ts +++ b/apps/browser/src/auth/popup/lock.component.ts @@ -18,7 +18,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors"; @@ -48,7 +48,7 @@ export class LockComponent extends BaseLockComponent { ngZone: NgZone, policyApiService: PolicyApiServiceAbstraction, policyService: InternalPolicyService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, private authService: AuthService, dialogService: DialogServiceAbstraction ) { @@ -68,7 +68,7 @@ export class LockComponent extends BaseLockComponent { ngZone, policyApiService, policyService, - passwordGenerationService, + passwordStrengthService, dialogService ); this.successRoute = "/tabs/current"; diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts index be7dee80a07..a5cf1c70655 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts @@ -16,11 +16,11 @@ import { import { totpServiceFactory } from "../../auth/background/service-factories/totp-service.factory"; import LockedVaultPendingNotificationsItem from "../../background/models/lockedVaultPendingNotificationsItem"; import { eventCollectionServiceFactory } from "../../background/service-factories/event-collection-service.factory"; -import { passwordGenerationServiceFactory } from "../../background/service-factories/password-generation-service.factory"; import { Account } from "../../models/account"; import { CachedServices } from "../../platform/background/service-factories/factory-options"; import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory"; import { BrowserApi } from "../../platform/browser/browser-api"; +import { passwordGenerationServiceFactory } from "../../tools/background/service_factories/password-generation-service.factory"; import { cipherServiceFactory, CipherServiceInitOptions, diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 1304f82de52..4091e807f97 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -75,6 +75,10 @@ import { UsernameGenerationService, UsernameGenerationServiceAbstraction, } from "@bitwarden/common/tools/generator/username"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction"; @@ -155,6 +159,7 @@ export default class MainBackground { vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction; syncService: SyncServiceAbstraction; passwordGenerationService: PasswordGenerationServiceAbstraction; + passwordStrengthService: PasswordStrengthServiceAbstraction; totpService: TotpServiceAbstraction; autofillService: AutofillServiceAbstraction; containerService: ContainerService; @@ -360,6 +365,9 @@ export default class MainBackground { this.collectionService, this.policyService ); + + this.passwordStrengthService = new PasswordStrengthService(); + this.passwordGenerationService = new PasswordGenerationService( this.cryptoService, this.policyService, @@ -391,7 +399,7 @@ export default class MainBackground { this.twoFactorService, this.i18nService, this.encryptService, - this.passwordGenerationService, + this.passwordStrengthService, this.policyService ); diff --git a/apps/browser/src/platform/listeners/on-command-listener.ts b/apps/browser/src/platform/listeners/on-command-listener.ts index 1511e937813..65af31e173c 100644 --- a/apps/browser/src/platform/listeners/on-command-listener.ts +++ b/apps/browser/src/platform/listeners/on-command-listener.ts @@ -6,12 +6,12 @@ import { authServiceFactory } from "../../auth/background/service-factories/auth import { autofillServiceFactory } from "../../autofill/background/service_factories/autofill-service.factory"; import { GeneratePasswordToClipboardCommand } from "../../autofill/clipboard"; import { AutofillTabCommand } from "../../autofill/commands/autofill-tab-command"; -import { - PasswordGenerationServiceInitOptions, - passwordGenerationServiceFactory, -} from "../../background/service-factories/password-generation-service.factory"; import { Account } from "../../models/account"; import { stateServiceFactory } from "../../platform/background/service-factories/state-service.factory"; +import { + passwordGenerationServiceFactory, + PasswordGenerationServiceInitOptions, +} from "../../tools/background/service_factories/password-generation-service.factory"; import { CachedServices } from "../background/service-factories/factory-options"; import { logServiceFactory } from "../background/service-factories/log-service.factory"; import { BrowserApi } from "../browser/browser-api"; diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 8a2a7f7a505..5a7ca533701 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -63,6 +63,7 @@ import { ContainerService } from "@bitwarden/common/platform/services/container. import { SearchService } from "@bitwarden/common/services/search.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { @@ -287,6 +288,11 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("platformUtilsService"), deps: [], }, + { + provide: PasswordStrengthServiceAbstraction, + useFactory: getBgService("passwordStrengthService"), + deps: [], + }, { provide: PasswordGenerationServiceAbstraction, useFactory: getBgService("passwordGenerationService"), diff --git a/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts b/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts new file mode 100644 index 00000000000..b5a56dc1184 --- /dev/null +++ b/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts @@ -0,0 +1,46 @@ +import { + PasswordGenerationService, + PasswordGenerationServiceAbstraction, +} from "@bitwarden/common/tools/generator/password"; + +import { + policyServiceFactory, + PolicyServiceInitOptions, +} from "../../../admin-console/background/service-factories/policy-service.factory"; +import { + CryptoServiceInitOptions, + cryptoServiceFactory, +} from "../../../platform/background/service-factories/crypto-service.factory"; +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../platform/background/service-factories/factory-options"; +import { + stateServiceFactory, + StateServiceInitOptions, +} from "../../../platform/background/service-factories/state-service.factory"; + +type PasswordGenerationServiceFactoryOptions = FactoryOptions; + +export type PasswordGenerationServiceInitOptions = PasswordGenerationServiceFactoryOptions & + CryptoServiceInitOptions & + PolicyServiceInitOptions & + StateServiceInitOptions; + +export function passwordGenerationServiceFactory( + cache: { passwordGenerationService?: PasswordGenerationServiceAbstraction } & CachedServices, + opts: PasswordGenerationServiceInitOptions +): Promise { + return factory( + cache, + "passwordGenerationService", + opts, + async () => + new PasswordGenerationService( + await cryptoServiceFactory(cache, opts), + await policyServiceFactory(cache, opts), + await stateServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts b/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts new file mode 100644 index 00000000000..3ebd4636fe3 --- /dev/null +++ b/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts @@ -0,0 +1,23 @@ +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; + +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../platform/background/service-factories/factory-options"; + +type PasswordStrengthServiceFactoryOptions = FactoryOptions; + +export type PasswordStrengthServiceInitOptions = PasswordStrengthServiceFactoryOptions; + +export function passwordStrengthServiceFactory( + cache: { + passwordStrengthService?: PasswordStrengthServiceAbstraction; + } & CachedServices, + opts: PasswordStrengthServiceInitOptions +): Promise { + return factory(cache, "passwordStrengthService", opts, async () => new PasswordStrengthService()); +} diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index b8d8d1335fd..fe9284e2e80 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -35,6 +35,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { Response } from "../../models/response"; @@ -54,6 +55,7 @@ export class LoginCommand { protected cryptoFunctionService: CryptoFunctionService, protected environmentService: EnvironmentService, protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected platformUtilsService: PlatformUtilsService, protected stateService: StateService, protected cryptoService: CryptoService, @@ -505,7 +507,7 @@ export class LoginCommand { } // Strength & Policy Validation - const strengthResult = this.passwordGenerationService.passwordStrength( + const strengthResult = this.passwordStrengthService.getPasswordStrength( masterPassword, this.email ); diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 956ae23b008..70b19612348 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -45,6 +45,10 @@ import { PasswordGenerationService, PasswordGenerationServiceAbstraction, } from "@bitwarden/common/tools/generator/password"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -103,6 +107,7 @@ export class Main { vaultTimeoutSettingsService: VaultTimeoutSettingsService; syncService: SyncService; passwordGenerationService: PasswordGenerationServiceAbstraction; + passwordStrengthService: PasswordStrengthServiceAbstraction; totpService: TotpService; containerService: ContainerService; auditService: AuditService; @@ -302,6 +307,8 @@ export class Main { this.twoFactorService = new TwoFactorService(this.i18nService, this.platformUtilsService); + this.passwordStrengthService = new PasswordStrengthService(); + this.passwordGenerationService = new PasswordGenerationService( this.cryptoService, this.policyService, @@ -322,7 +329,7 @@ export class Main { this.twoFactorService, this.i18nService, this.encryptService, - this.passwordGenerationService, + this.passwordStrengthService, this.policyService ); diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index 122b70c7b49..700a31b3c66 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -145,6 +145,7 @@ export class Program { this.main.cryptoFunctionService, this.main.environmentService, this.main.passwordGenerationService, + this.main.passwordStrengthService, this.main.platformUtilsService, this.main.stateService, this.main.cryptoService, diff --git a/apps/desktop/src/auth/lock.component.ts b/apps/desktop/src/auth/lock.component.ts index ef8dbe967df..61f7b4bfe30 100644 --- a/apps/desktop/src/auth/lock.component.ts +++ b/apps/desktop/src/auth/lock.component.ts @@ -18,7 +18,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { ElectronStateService } from "../platform/services/electron-state.service.abstraction"; import { BiometricStorageAction, BiometricMessage } from "../types/biometric-message"; @@ -49,7 +49,7 @@ export class LockComponent extends BaseLockComponent { ngZone: NgZone, policyApiService: PolicyApiServiceAbstraction, policyService: InternalPolicyService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, logService: LogService, keyConnectorService: KeyConnectorService, dialogService: DialogServiceAbstraction @@ -70,7 +70,7 @@ export class LockComponent extends BaseLockComponent { ngZone, policyApiService, policyService, - passwordGenerationService, + passwordStrengthService, dialogService ); } 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 8f545beb38f..68619b27514 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 @@ -4,7 +4,7 @@ import { ActivatedRoute } from "@angular/router"; 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 { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +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"; @@ -23,7 +23,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone constructor( cipherService: CipherService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, modalService: ModalService, messagingService: MessagingService, private route: ActivatedRoute, @@ -32,7 +32,7 @@ export class WeakPasswordsReportComponent extends BaseWeakPasswordsReportCompone ) { super( cipherService, - passwordGenerationService, + passwordStrengthService, modalService, messagingService, passwordRepromptService diff --git a/apps/web/src/app/auth/lock.component.ts b/apps/web/src/app/auth/lock.component.ts index dbb6b118ca4..789ebc16955 100644 --- a/apps/web/src/app/auth/lock.component.ts +++ b/apps/web/src/app/auth/lock.component.ts @@ -16,7 +16,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { RouterService } from "../core"; @@ -42,7 +42,7 @@ export class LockComponent extends BaseLockComponent { ngZone: NgZone, policyApiService: PolicyApiServiceAbstraction, policyService: InternalPolicyService, - passwordGenerationService: PasswordGenerationServiceAbstraction, + passwordStrengthService: PasswordStrengthServiceAbstraction, dialogService: DialogServiceAbstraction ) { super( @@ -61,7 +61,7 @@ export class LockComponent extends BaseLockComponent { ngZone, policyApiService, policyService, - passwordGenerationService, + passwordStrengthService, dialogService ); } diff --git a/apps/web/src/app/auth/login/login.component.ts b/apps/web/src/app/auth/login/login.component.ts index 52ee5a89bdd..316b353c490 100644 --- a/apps/web/src/app/auth/login/login.component.ts +++ b/apps/web/src/app/auth/login/login.component.ts @@ -24,6 +24,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { flagEnabled } from "../../../utils/flags"; import { RouterService, StateService } from "../../core"; @@ -50,6 +51,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService, passwordGenerationService: PasswordGenerationServiceAbstraction, + private passwordStrengthService: PasswordStrengthServiceAbstraction, cryptoFunctionService: CryptoFunctionService, private policyApiService: PolicyApiServiceAbstraction, private policyService: InternalPolicyService, @@ -153,7 +155,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest // Check master password against policy if (this.enforcedPasswordPolicyOptions != null) { - const strengthResult = this.passwordGenerationService.passwordStrength( + const strengthResult = this.passwordStrengthService.getPasswordStrength( masterPassword, this.formGroup.value.email ); 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 14d159deee3..ddea66a6a91 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 @@ -2,7 +2,7 @@ import { Component, OnInit } from "@angular/core"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +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"; @@ -22,7 +22,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen constructor( protected cipherService: CipherService, - protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, modalService: ModalService, messagingService: MessagingService, passwordRepromptService: PasswordRepromptService @@ -77,7 +77,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen .filter((i) => i.length >= 3); } } - const result = this.passwordGenerationService.passwordStrength( + const result = this.passwordStrengthService.getPasswordStrength( c.login.password, null, userInput.length > 0 ? userInput : null diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts index 9114539d7a8..01c083ee5a9 100644 --- a/libs/angular/src/auth/components/lock.component.ts +++ b/libs/angular/src/auth/components/lock.component.ts @@ -24,7 +24,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; import { DialogServiceAbstraction, SimpleDialogType } from "../../services/dialog"; @@ -69,7 +69,7 @@ export class LockComponent implements OnInit, OnDestroy { protected ngZone: NgZone, protected policyApiService: PolicyApiServiceAbstraction, protected policyService: InternalPolicyService, - protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected dialogService: DialogServiceAbstraction ) {} @@ -333,7 +333,7 @@ export class LockComponent implements OnInit, OnDestroy { return false; } - const passwordStrength = this.passwordGenerationService.passwordStrength( + const passwordStrength = this.passwordStrengthService.getPasswordStrength( this.masterPassword, this.email )?.score; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 51e3cdc3fc0..bf5cb5a09a1 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -118,6 +118,10 @@ import { UsernameGenerationService, UsernameGenerationServiceAbstraction, } from "@bitwarden/common/tools/generator/username"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "@bitwarden/common/tools/password-strength"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { SendService } from "@bitwarden/common/tools/send/services/send.service"; @@ -239,7 +243,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; TwoFactorServiceAbstraction, I18nServiceAbstraction, EncryptService, - PasswordGenerationServiceAbstraction, + PasswordStrengthServiceAbstraction, PolicyServiceAbstraction, ], }, @@ -359,6 +363,11 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction"; DevicesApiServiceAbstraction, ], }, + { + provide: PasswordStrengthServiceAbstraction, + useClass: PasswordStrengthService, + deps: [], + }, { provide: PasswordGenerationServiceAbstraction, useClass: PasswordGenerationService, diff --git a/libs/angular/src/shared/components/password-strength/password-strength.component.ts b/libs/angular/src/shared/components/password-strength/password-strength.component.ts index 91167ffc5c1..75dd687efe4 100644 --- a/libs/angular/src/shared/components/password-strength/password-strength.component.ts +++ b/libs/angular/src/shared/components/password-strength/password-strength.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnChanges, Output } from "@angular/core"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; export interface PasswordColorText { color: string; @@ -59,7 +59,7 @@ export class PasswordStrengthComponent implements OnChanges { constructor( private i18nService: I18nService, - private passwordGenerationService: PasswordGenerationServiceAbstraction + private passwordStrengthService: PasswordStrengthServiceAbstraction ) {} ngOnChanges(): void { @@ -96,7 +96,7 @@ export class PasswordStrengthComponent implements OnChanges { clearTimeout(this.masterPasswordStrengthTimeout); } - const strengthResult = this.passwordGenerationService.passwordStrength( + const strengthResult = this.passwordStrengthService.getPasswordStrength( masterPassword, this.email, this.name?.trim().toLowerCase().split(" ") diff --git a/libs/common/src/auth/login-strategies/login.strategy.spec.ts b/libs/common/src/auth/login-strategies/login.strategy.spec.ts index 09756fbd995..ed958af6c7d 100644 --- a/libs/common/src/auth/login-strategies/login.strategy.spec.ts +++ b/libs/common/src/auth/login-strategies/login.strategy.spec.ts @@ -11,7 +11,10 @@ import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; import { Account, AccountProfile, AccountTokens } from "../../platform/models/domain/account"; import { EncString } from "../../platform/models/domain/enc-string"; -import { PasswordGenerationService } from "../../tools/generator/password"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "../../tools/password-strength"; import { AuthService } from "../abstractions/auth.service"; import { TokenService } from "../abstractions/token.service"; import { TwoFactorService } from "../abstractions/two-factor.service"; @@ -85,7 +88,7 @@ describe("LogInStrategy", () => { let twoFactorService: MockProxy; let authService: MockProxy; let policyService: MockProxy; - let passwordGenerationService: MockProxy; + let passwordStrengthService: MockProxy; let passwordLogInStrategy: PasswordLogInStrategy; let credentials: PasswordLogInCredentials; @@ -102,7 +105,7 @@ describe("LogInStrategy", () => { twoFactorService = mock(); authService = mock(); policyService = mock(); - passwordGenerationService = mock(); + passwordStrengthService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.decodeToken.calledWith(accessToken).mockResolvedValue(decodedToken); @@ -118,7 +121,7 @@ describe("LogInStrategy", () => { logService, stateService, twoFactorService, - passwordGenerationService, + passwordStrengthService, policyService, authService ); diff --git a/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts b/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts index 0c2d1e2d575..9e3ff7da686 100644 --- a/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts +++ b/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts @@ -11,7 +11,10 @@ import { PlatformUtilsService } from "../../platform/abstractions/platform-utils import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationService } from "../../tools/generator/password"; +import { + PasswordStrengthService, + PasswordStrengthServiceAbstraction, +} from "../../tools/password-strength"; import { AuthService } from "../abstractions/auth.service"; import { TokenService } from "../abstractions/token.service"; import { TwoFactorService } from "../abstractions/two-factor.service"; @@ -51,7 +54,7 @@ describe("PasswordLogInStrategy", () => { let twoFactorService: MockProxy; let authService: MockProxy; let policyService: MockProxy; - let passwordGenerationService: MockProxy; + let passwordStrengthService: MockProxy; let passwordLogInStrategy: PasswordLogInStrategy; let credentials: PasswordLogInCredentials; @@ -68,7 +71,7 @@ describe("PasswordLogInStrategy", () => { twoFactorService = mock(); authService = mock(); policyService = mock(); - passwordGenerationService = mock(); + passwordStrengthService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.decodeToken.mockResolvedValue({}); @@ -94,7 +97,7 @@ describe("PasswordLogInStrategy", () => { logService, stateService, twoFactorService, - passwordGenerationService, + passwordStrengthService, policyService, authService ); @@ -141,7 +144,7 @@ describe("PasswordLogInStrategy", () => { }); it("does not force the user to update their master password when it meets requirements", async () => { - passwordGenerationService.passwordStrength.mockReturnValue({ score: 5 } as any); + passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 5 } as any); policyService.evaluateMasterPassword.mockReturnValue(true); const result = await passwordLogInStrategy.logIn(credentials); @@ -151,7 +154,7 @@ describe("PasswordLogInStrategy", () => { }); it("forces the user to update their master password on successful login when it does not meet master password policy requirements", async () => { - passwordGenerationService.passwordStrength.mockReturnValue({ score: 0 } as any); + passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 0 } as any); policyService.evaluateMasterPassword.mockReturnValue(false); const result = await passwordLogInStrategy.logIn(credentials); @@ -164,7 +167,7 @@ describe("PasswordLogInStrategy", () => { }); it("forces the user to update their master password on successful 2FA login when it does not meet master password policy requirements", async () => { - passwordGenerationService.passwordStrength.mockReturnValue({ score: 0 } as any); + passwordStrengthService.getPasswordStrength.mockReturnValue({ score: 0 } as any); policyService.evaluateMasterPassword.mockReturnValue(false); const token2FAResponse = new IdentityTwoFactorResponse({ diff --git a/libs/common/src/auth/login-strategies/password-login.strategy.ts b/libs/common/src/auth/login-strategies/password-login.strategy.ts index 200656a08ff..41f7c30ec7e 100644 --- a/libs/common/src/auth/login-strategies/password-login.strategy.ts +++ b/libs/common/src/auth/login-strategies/password-login.strategy.ts @@ -9,7 +9,7 @@ import { MessagingService } from "../../platform/abstractions/messaging.service" import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; import { StateService } from "../../platform/abstractions/state.service"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationServiceAbstraction } from "../../tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "../../tools/password-strength"; import { AuthService } from "../abstractions/auth.service"; import { TokenService } from "../abstractions/token.service"; import { TwoFactorService } from "../abstractions/two-factor.service"; @@ -54,7 +54,7 @@ export class PasswordLogInStrategy extends LogInStrategy { logService: LogService, protected stateService: StateService, twoFactorService: TwoFactorService, - private passwordGenerationService: PasswordGenerationServiceAbstraction, + private passwordStrengthService: PasswordStrengthServiceAbstraction, private policyService: PolicyService, private authService: AuthService ) { @@ -158,7 +158,7 @@ export class PasswordLogInStrategy extends LogInStrategy { { masterPassword, email }: PasswordLogInCredentials, options: MasterPasswordPolicyOptions ): boolean { - const passwordStrength = this.passwordGenerationService.passwordStrength( + const passwordStrength = this.passwordStrengthService.getPasswordStrength( masterPassword, email )?.score; diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index 6650ce798ea..56f601da56f 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -17,7 +17,7 @@ import { PlatformUtilsService } from "../../platform/abstractions/platform-utils import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PasswordGenerationServiceAbstraction } from "../../tools/generator/password"; +import { PasswordStrengthServiceAbstraction } from "../../tools/password-strength"; import { AuthService as AuthServiceAbstraction } from "../abstractions/auth.service"; import { KeyConnectorService } from "../abstractions/key-connector.service"; import { TokenService } from "../abstractions/token.service"; @@ -102,7 +102,7 @@ export class AuthService implements AuthServiceAbstraction { protected twoFactorService: TwoFactorService, protected i18nService: I18nService, protected encryptService: EncryptService, - protected passwordGenerationService: PasswordGenerationServiceAbstraction, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected policyService: PolicyService ) {} @@ -133,7 +133,7 @@ export class AuthService implements AuthServiceAbstraction { this.logService, this.stateService, this.twoFactorService, - this.passwordGenerationService, + this.passwordStrengthService, this.policyService, this ); diff --git a/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts b/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts index 7de8c28ed72..3f2c8424ad0 100644 --- a/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts +++ b/libs/common/src/tools/generator/password/password-generation.service.abstraction.ts @@ -1,5 +1,3 @@ -import * as zxcvbn from "zxcvbn"; - import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; import { GeneratedPasswordHistory } from "./generated-password-history"; @@ -17,11 +15,6 @@ export abstract class PasswordGenerationServiceAbstraction { getHistory: () => Promise; addHistory: (password: string) => Promise; clear: (userId?: string) => Promise; - passwordStrength: ( - password: string, - email?: string, - userInputs?: string[] - ) => zxcvbn.ZXCVBNResult; normalizeOptions: ( options: PasswordGeneratorOptions, enforcedPolicyOptions: PasswordGeneratorPolicyOptions diff --git a/libs/common/src/tools/generator/password/password-generation.service.ts b/libs/common/src/tools/generator/password/password-generation.service.ts index 8270e2d812e..079d455c46d 100644 --- a/libs/common/src/tools/generator/password/password-generation.service.ts +++ b/libs/common/src/tools/generator/password/password-generation.service.ts @@ -1,5 +1,3 @@ -import * as zxcvbn from "zxcvbn"; - import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "../../../admin-console/enums"; import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; @@ -387,33 +385,6 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr await this.stateService.setDecryptedPasswordGenerationHistory(null, { userId: userId }); } - /** - * Calculates a password strength score using zxcvbn. - * @param password The password to calculate the strength of. - * @param emailInput An unparsed email address to use as user input. - * @param userInputs An array of additional user inputs to use when calculating the strength. - */ - passwordStrength( - password: string, - emailInput: string = null, - userInputs: string[] = null - ): zxcvbn.ZXCVBNResult { - if (password == null || password.length === 0) { - return null; - } - const globalUserInputs = [ - "bitwarden", - "bit", - "warden", - ...(userInputs ?? []), - ...this.emailToUserInputs(emailInput), - ]; - // Use a hash set to get rid of any duplicate user inputs - const finalUserInputs = Array.from(new Set(globalUserInputs)); - const result = zxcvbn(password, finalUserInputs); - return result; - } - normalizeOptions( options: PasswordGeneratorOptions, enforcedPolicyOptions: PasswordGeneratorPolicyOptions @@ -476,27 +447,6 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr this.sanitizePasswordLength(options, false); } - /** - * Convert an email address into a list of user inputs for zxcvbn by - * taking the local part of the email address and splitting it into words. - * @param email - * @private - */ - private emailToUserInputs(email: string): string[] { - if (email == null || email.length === 0) { - return []; - } - const atPosition = email.indexOf("@"); - if (atPosition < 0) { - return []; - } - return email - .substring(0, atPosition) - .trim() - .toLowerCase() - .split(/[^A-Za-z0-9]/); - } - private capitalize(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); } diff --git a/libs/common/src/tools/password-strength/index.ts b/libs/common/src/tools/password-strength/index.ts new file mode 100644 index 00000000000..3e160fa8204 --- /dev/null +++ b/libs/common/src/tools/password-strength/index.ts @@ -0,0 +1,2 @@ +export { PasswordStrengthServiceAbstraction } from "./password-strength.service.abstraction"; +export { PasswordStrengthService } from "./password-strength.service"; diff --git a/libs/common/src/tools/password-strength/password-strength.service.abstraction.ts b/libs/common/src/tools/password-strength/password-strength.service.abstraction.ts new file mode 100644 index 00000000000..5708a4c7bd1 --- /dev/null +++ b/libs/common/src/tools/password-strength/password-strength.service.abstraction.ts @@ -0,0 +1,5 @@ +import { ZXCVBNResult } from "zxcvbn"; + +export abstract class PasswordStrengthServiceAbstraction { + getPasswordStrength: (password: string, email?: string, userInputs?: string[]) => ZXCVBNResult; +} diff --git a/libs/common/src/tools/password-strength/password-strength.service.ts b/libs/common/src/tools/password-strength/password-strength.service.ts new file mode 100644 index 00000000000..78a8f963991 --- /dev/null +++ b/libs/common/src/tools/password-strength/password-strength.service.ts @@ -0,0 +1,53 @@ +import * as zxcvbn from "zxcvbn"; + +import { PasswordStrengthServiceAbstraction } from "./password-strength.service.abstraction"; + +export class PasswordStrengthService implements PasswordStrengthServiceAbstraction { + /** + * Calculates a password strength score using zxcvbn. + * @param password The password to calculate the strength of. + * @param emailInput An unparsed email address to use as user input. + * @param userInputs An array of additional user inputs to use when calculating the strength. + */ + getPasswordStrength( + password: string, + emailInput: string = null, + userInputs: string[] = null + ): zxcvbn.ZXCVBNResult { + if (password == null || password.length === 0) { + return null; + } + const globalUserInputs = [ + "bitwarden", + "bit", + "warden", + ...(userInputs ?? []), + ...this.emailToUserInputs(emailInput), + ]; + // Use a hash set to get rid of any duplicate user inputs + const finalUserInputs = Array.from(new Set(globalUserInputs)); + const result = zxcvbn(password, finalUserInputs); + return result; + } + + /** + * Convert an email address into a list of user inputs for zxcvbn by + * taking the local part of the email address and splitting it into words. + * @param email + * @private + */ + private emailToUserInputs(email: string): string[] { + if (email == null || email.length === 0) { + return []; + } + const atPosition = email.indexOf("@"); + if (atPosition < 0) { + return []; + } + return email + .substring(0, atPosition) + .trim() + .toLowerCase() + .split(/[^A-Za-z0-9]/); + } +} From 3b708d93112f80db11fe8bbe999e7ff2eeff121d Mon Sep 17 00:00:00 2001 From: Daniel James Smith Date: Wed, 14 Jun 2023 11:28:32 +0200 Subject: [PATCH 14/29] Remove try-catch to display proper api-errors (#5570) --- .../email-forwarders/simple-login-forwarder.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libs/common/src/tools/generator/username/email-forwarders/simple-login-forwarder.ts b/libs/common/src/tools/generator/username/email-forwarders/simple-login-forwarder.ts index bf3eea42326..7ecd72dc59c 100644 --- a/libs/common/src/tools/generator/username/email-forwarders/simple-login-forwarder.ts +++ b/libs/common/src/tools/generator/username/email-forwarders/simple-login-forwarder.ts @@ -35,13 +35,9 @@ export class SimpleLoginForwarder implements Forwarder { if (response.status === 401) { throw "Invalid SimpleLogin API key."; } - try { - const json = await response.json(); - if (json?.error != null) { - throw "SimpleLogin error:" + json.error; - } - } catch { - // Do nothing... + const json = await response.json(); + if (json?.error != null) { + throw "SimpleLogin error:" + json.error; } throw "Unknown SimpleLogin error occurred."; } From 37010a6414400230f38944bdcc5fc0ec0bbeebc2 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Wed, 14 Jun 2023 14:10:39 +0200 Subject: [PATCH 15/29] [PM-2642] Fix feature flags not working properly when urls load from storage (#5598) * fix: feature flags not working properly Due to race conditions the api url is not set during the first fetch och server config. This causes the config to be fetched from `api.bitwarden.com`. The config is then supposed to be re-fetched when the api url is set by the environment service, but due to a missing line this is not done when the urls are set from storage. * feat: change to `Observable` --- .../src/platform/abstractions/environment.service.ts | 2 +- libs/common/src/platform/services/environment.service.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/common/src/platform/abstractions/environment.service.ts b/libs/common/src/platform/abstractions/environment.service.ts index 27e4125a29d..e4d6a550014 100644 --- a/libs/common/src/platform/abstractions/environment.service.ts +++ b/libs/common/src/platform/abstractions/environment.service.ts @@ -18,7 +18,7 @@ export type PayPalConfig = { }; export abstract class EnvironmentService { - urls: Observable; + urls: Observable; hasBaseUrl: () => boolean; getNotificationsUrl: () => string; diff --git a/libs/common/src/platform/services/environment.service.ts b/libs/common/src/platform/services/environment.service.ts index 5e228cf7327..02e0fcfab23 100644 --- a/libs/common/src/platform/services/environment.service.ts +++ b/libs/common/src/platform/services/environment.service.ts @@ -8,8 +8,8 @@ import { import { StateService } from "../abstractions/state.service"; export class EnvironmentService implements EnvironmentServiceAbstraction { - private readonly urlsSubject = new Subject(); - urls: Observable = this.urlsSubject; + private readonly urlsSubject = new Subject(); + urls: Observable = this.urlsSubject.asObservable(); protected baseUrl: string; protected webVaultUrl: string; @@ -139,6 +139,8 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { this.eventsUrl = envUrls.events = urls.events; this.keyConnectorUrl = urls.keyConnector; // scimUrl is not saved to storage + + this.urlsSubject.next(); } async setUrls(urls: Urls): Promise { @@ -176,7 +178,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { this.keyConnectorUrl = urls.keyConnector; this.scimUrl = urls.scim; - this.urlsSubject.next(urls); + this.urlsSubject.next(); return urls; } From 2b65b3f0f76e2e57080fd10b0fe15d710e386d91 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Wed, 14 Jun 2023 08:38:24 -0400 Subject: [PATCH 16/29] [AC-1383] Move collections to Vault (#5424) * Move CollectionDialog to Vault * Fix CollectionDialogModule imports * Move CollectionAdminService and View to Vault * Move CollectionService to Vault * Split GroupService into internal and public facing classes * Move collection models to vault * lint spacing fix * Move collection spec file * Fix spec import * Update apps/web/src/app/core/core.module.ts Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> * Remove CoreOrganizationModule from CollectionDialogModule --------- Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com> --- .../browser/src/background/main.background.ts | 4 +- .../vault-timeout-service.factory.ts | 8 +-- .../models/browserGroupingsComponentState.ts | 2 +- .../src/popup/services/services.module.ts | 2 +- .../collection-service.factory.ts | 4 +- .../components/vault/add-edit.component.ts | 2 +- .../components/vault/collections.component.ts | 2 +- .../popup/components/vault/share.component.ts | 2 +- .../vault/vault-filter.component.ts | 2 +- .../components/vault/vault-items.component.ts | 4 +- .../vault/services/vault-filter.service.ts | 2 +- .../organization-collection.response.ts | 5 +- apps/cli/src/bw.ts | 2 +- apps/cli/src/commands/edit.command.ts | 2 +- apps/cli/src/commands/get.command.ts | 6 +-- apps/cli/src/commands/list.command.ts | 16 +++--- apps/cli/src/utils.ts | 2 +- apps/cli/src/vault/create.command.ts | 2 +- .../models}/collection.response.ts | 4 +- apps/desktop/src/app/app.component.ts | 2 +- .../src/vault/app/vault/add-edit.component.ts | 2 +- .../vault/app/vault/collections.component.ts | 2 +- .../src/vault/app/vault/share.component.ts | 2 +- .../core/services/group/group.service.ts | 53 +++++++++++-------- .../organizations/core/services/index.ts | 1 - .../organizations/core/views/index.ts | 1 - .../manage/group-add-edit.component.ts | 10 ++-- .../organizations/manage/groups.component.ts | 18 +++---- .../member-dialog/member-dialog.component.ts | 4 +- .../organizations/members/people.component.ts | 8 +-- .../organizations/shared/index.ts | 1 - .../shared/shared-organization.module.ts | 5 +- .../import-export/org-import-export.module.ts | 2 +- apps/web/src/app/app.component.ts | 2 +- .../emergency-add-edit.component.ts | 2 +- apps/web/src/app/core/core.module.ts | 2 + apps/web/src/app/core/state/state.service.ts | 2 +- .../import-export/import-export.module.ts | 2 +- .../collection-dialog.component.html | 0 .../collection-dialog.component.ts | 21 ++++---- .../collection-dialog.module.ts | 5 +- .../components/collection-dialog/index.ts | 0 .../vault-items/vault-cipher-row.component.ts | 2 +- .../vault-collection-row.component.ts | 5 +- .../vault-items/vault-item-event.ts | 2 +- .../components/vault-items/vault-item.ts | 2 +- .../vault-items/vault-items.component.ts | 5 +- .../vault-items/vault-items.stories.ts | 2 +- .../core}/collection-admin.service.ts | 13 +++-- .../core/views/collection-admin.view.ts | 6 +-- .../individual-vault/add-edit.component.ts | 2 +- .../bulk-share-dialog.component.ts | 4 +- .../individual-vault/collections.component.ts | 4 +- .../pipes/get-collection-name.pipe.ts | 2 +- .../vault/individual-vault/share.component.ts | 4 +- .../abstractions/vault-filter.service.ts | 2 +- .../services/vault-filter.service.spec.ts | 2 +- .../services/vault-filter.service.ts | 4 +- .../shared/models/vault-filter.model.spec.ts | 2 +- .../shared/models/vault-filter.type.ts | 2 +- .../vault-header/vault-header.component.ts | 2 +- .../vault/individual-vault/vault.component.ts | 4 +- .../vault/individual-vault/vault.module.ts | 2 + .../app/vault/org-vault/add-edit.component.ts | 2 +- .../collection-name.badge.component.ts | 2 +- .../vault/org-vault/collections.component.ts | 2 +- .../vault-filter/vault-filter.service.ts | 6 +-- .../vault-header/vault-header.component.ts | 8 ++- .../app/vault/org-vault/vault.component.ts | 17 +++--- .../src/app/vault/org-vault/vault.module.ts | 2 + .../app/vault/utils/collection-utils.spec.ts | 2 +- .../src/app/vault/utils/collection-utils.ts | 8 +-- .../components/collections.component.ts | 4 +- .../angular/src/components/share.component.ts | 4 +- .../src/services/jslib-services.module.ts | 4 +- .../deprecated-vault-filter.service.ts | 2 +- .../vault/components/add-edit.component.ts | 4 +- .../components/collection-filter.component.ts | 2 +- .../components/vault-filter.component.ts | 2 +- .../services/vault-filter.service.ts | 4 +- libs/common/src/abstractions/api.service.ts | 10 ++-- .../response/organization-export.response.ts | 3 +- .../export/collection-with-id.export.ts | 4 +- .../src/models/export/collection.export.ts | 4 +- .../import-organization-ciphers.request.ts | 2 +- .../platform/abstractions/state.service.ts | 4 +- .../src/platform/models/domain/account.ts | 4 +- .../services/state-migration.service.ts | 2 +- .../src/platform/services/state.service.ts | 4 +- libs/common/src/services/api.service.ts | 10 ++-- .../vaultTimeout/vaultTimeout.service.ts | 2 +- .../abstractions/collection.service.ts | 0 .../models/data/collection.data.ts | 0 .../models/domain/collection.spec.ts | 0 .../models/domain/collection.ts | 0 .../request/collection-with-id.request.ts | 3 +- .../models/request/collection.request.ts | 3 +- .../models/response/collection.response.ts | 3 +- .../vault/models/response/sync.response.ts | 2 +- .../models/view/collection.view.ts | 0 .../services/collection.service.ts | 2 +- .../src/vault/services/sync/sync.service.ts | 6 +-- .../services/vault-export.service.ts | 8 +-- libs/importer/src/importers/base-importer.ts | 2 +- .../bitwarden/bitwarden-csv-importer.ts | 2 +- .../src/importers/padlock-csv-importer.ts | 2 +- .../src/importers/passpack-csv-importer.ts | 2 +- libs/importer/src/models/import-result.ts | 2 +- .../src/services/import.service.spec.ts | 2 +- libs/importer/src/services/import.service.ts | 4 +- 110 files changed, 229 insertions(+), 231 deletions(-) rename apps/browser/src/{admin-console/background/service-factories => vault/background/service_factories}/collection-service.factory.ts (88%) rename apps/cli/src/{admin-console/models/response => vault/models}/collection.response.ts (65%) rename apps/web/src/app/{admin-console/organizations/shared => vault}/components/collection-dialog/collection-dialog.component.html (100%) rename apps/web/src/app/{admin-console/organizations/shared => vault}/components/collection-dialog/collection-dialog.component.ts (94%) rename apps/web/src/app/{admin-console/organizations/shared => vault}/components/collection-dialog/collection-dialog.module.ts (65%) rename apps/web/src/app/{admin-console/organizations/shared => vault}/components/collection-dialog/index.ts (100%) rename apps/web/src/app/{admin-console/organizations/core/services => vault/core}/collection-admin.service.ts (91%) rename apps/web/src/app/{admin-console/organizations => vault}/core/views/collection-admin.view.ts (73%) rename libs/common/src/{admin-console => vault}/abstractions/collection.service.ts (100%) rename libs/common/src/{admin-console => vault}/models/data/collection.data.ts (100%) rename libs/common/src/{admin-console => vault}/models/domain/collection.spec.ts (100%) rename libs/common/src/{admin-console => vault}/models/domain/collection.ts (100%) rename libs/common/src/{admin-console => vault}/models/request/collection-with-id.request.ts (80%) rename libs/common/src/{admin-console => vault}/models/request/collection.request.ts (79%) rename libs/common/src/{admin-console => vault}/models/response/collection.response.ts (92%) rename libs/common/src/{admin-console => vault}/models/view/collection.view.ts (100%) rename libs/common/src/{admin-console => vault}/services/collection.service.ts (99%) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 4091e807f97..0437fa55e03 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -11,12 +11,10 @@ import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstrac import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; -import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { InternalOrganizationService as InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service"; -import { CollectionService } from "@bitwarden/common/admin-console/services/collection.service"; import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; @@ -83,6 +81,7 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/vault/abstractions/collection.service"; import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -90,6 +89,7 @@ import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarde import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/services/collection.service"; import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; diff --git a/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts b/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts index f3f97803d1e..601867ad385 100644 --- a/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts +++ b/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts @@ -1,9 +1,5 @@ import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; -import { - collectionServiceFactory, - CollectionServiceInitOptions, -} from "../../admin-console/background/service-factories/collection-service.factory"; import { authServiceFactory, AuthServiceInitOptions, @@ -38,6 +34,10 @@ import { cipherServiceFactory, CipherServiceInitOptions, } from "../../vault/background/service_factories/cipher-service.factory"; +import { + collectionServiceFactory, + CollectionServiceInitOptions, +} from "../../vault/background/service_factories/collection-service.factory"; import { folderServiceFactory, FolderServiceInitOptions, diff --git a/apps/browser/src/models/browserGroupingsComponentState.ts b/apps/browser/src/models/browserGroupingsComponentState.ts index f47a9ff6ac6..57e80216c23 100644 --- a/apps/browser/src/models/browserGroupingsComponentState.ts +++ b/apps/browser/src/models/browserGroupingsComponentState.ts @@ -1,8 +1,8 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { BrowserComponentState } from "./browserComponentState"; diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 5a7ca533701..1b3244064bf 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -18,7 +18,6 @@ import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { @@ -71,6 +70,7 @@ import { SendService, } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { CipherFileUploadService } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { diff --git a/apps/browser/src/admin-console/background/service-factories/collection-service.factory.ts b/apps/browser/src/vault/background/service_factories/collection-service.factory.ts similarity index 88% rename from apps/browser/src/admin-console/background/service-factories/collection-service.factory.ts rename to apps/browser/src/vault/background/service_factories/collection-service.factory.ts index dcf48537b37..323eebe27d1 100644 --- a/apps/browser/src/admin-console/background/service-factories/collection-service.factory.ts +++ b/apps/browser/src/vault/background/service_factories/collection-service.factory.ts @@ -1,5 +1,5 @@ -import { CollectionService as AbstractCollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { CollectionService } from "@bitwarden/common/admin-console/services/collection.service"; +import { CollectionService as AbstractCollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; +import { CollectionService } from "@bitwarden/common/vault/services/collection.service"; import { cryptoServiceFactory, 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 f6e8c1f03b6..68a63fb062d 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 @@ -7,7 +7,6 @@ import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -17,6 +16,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; diff --git a/apps/browser/src/vault/popup/components/vault/collections.component.ts b/apps/browser/src/vault/popup/components/vault/collections.component.ts index 1b7570eaf6e..d4615e165b2 100644 --- a/apps/browser/src/vault/popup/components/vault/collections.component.ts +++ b/apps/browser/src/vault/popup/components/vault/collections.component.ts @@ -4,11 +4,11 @@ import { ActivatedRoute } from "@angular/router"; import { first } from "rxjs/operators"; import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @Component({ selector: "app-vault-collections", diff --git a/apps/browser/src/vault/popup/components/vault/share.component.ts b/apps/browser/src/vault/popup/components/vault/share.component.ts index e6103b4f261..80188646baf 100644 --- a/apps/browser/src/vault/popup/components/vault/share.component.ts +++ b/apps/browser/src/vault/popup/components/vault/share.component.ts @@ -3,12 +3,12 @@ import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @Component({ selector: "app-vault-share", diff --git a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts index 1b41a9d0a1b..4be0fe89fe1 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts @@ -6,7 +6,6 @@ import { first } from "rxjs/operators"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -15,6 +14,7 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { BrowserGroupingsComponentState } from "../../../../models/browserGroupingsComponentState"; diff --git a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts index 1ce8b3ab41b..59d7ae92c28 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts @@ -6,17 +6,17 @@ import { first } from "rxjs/operators"; import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/vault/components/vault-items.component"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; 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 { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { BrowserComponentState } from "../../../../models/browserComponentState"; diff --git a/apps/browser/src/vault/services/vault-filter.service.ts b/apps/browser/src/vault/services/vault-filter.service.ts index 4b8b9de7085..1caf54fe55b 100644 --- a/apps/browser/src/vault/services/vault-filter.service.ts +++ b/apps/browser/src/vault/services/vault-filter.service.ts @@ -1,10 +1,10 @@ import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { StateService } from "@bitwarden/common/platform/abstractions/state.service"; 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 { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; diff --git a/apps/cli/src/admin-console/models/response/organization-collection.response.ts b/apps/cli/src/admin-console/models/response/organization-collection.response.ts index d58676ad4ea..ca47a4b0741 100644 --- a/apps/cli/src/admin-console/models/response/organization-collection.response.ts +++ b/apps/cli/src/admin-console/models/response/organization-collection.response.ts @@ -1,9 +1,8 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; +import { CollectionResponse } from "../../../vault/models/collection.response"; import { SelectionReadOnly } from "../selection-read-only"; -import { CollectionResponse } from "./collection.response"; - export class OrganizationCollectionResponse extends CollectionResponse { groups: SelectionReadOnly[]; diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 70b19612348..29c1443a713 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -7,7 +7,6 @@ import * as jsdom from "jsdom"; import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; -import { CollectionService } from "@bitwarden/common/admin-console/services/collection.service"; import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; @@ -53,6 +52,7 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { SendService } from "@bitwarden/common/tools/send/services/send.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/services/collection.service"; import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; diff --git a/apps/cli/src/commands/edit.command.ts b/apps/cli/src/commands/edit.command.ts index e0b81e914ec..960b0999146 100644 --- a/apps/cli/src/commands/edit.command.ts +++ b/apps/cli/src/commands/edit.command.ts @@ -1,5 +1,4 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionRequest } from "@bitwarden/common/admin-console/models/request/collection.request"; import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; import { CipherExport } from "@bitwarden/common/models/export/cipher.export"; import { CollectionExport } from "@bitwarden/common/models/export/collection.export"; @@ -9,6 +8,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { CollectionRequest } from "@bitwarden/common/vault/models/request/collection.request"; import { OrganizationCollectionRequest } from "../admin-console/models/request/organization-collection.request"; import { OrganizationCollectionResponse } from "../admin-console/models/response/organization-collection.response"; diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 5ef7e1e17db..44a94fb430d 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -2,10 +2,8 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { CardExport } from "@bitwarden/common/models/export/card.export"; import { CipherExport } from "@bitwarden/common/models/export/cipher.export"; import { CollectionExport } from "@bitwarden/common/models/export/collection.export"; @@ -22,13 +20,14 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; 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 { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { OrganizationCollectionRequest } from "../admin-console/models/request/organization-collection.request"; -import { CollectionResponse } from "../admin-console/models/response/collection.response"; import { OrganizationCollectionResponse } from "../admin-console/models/response/organization-collection.response"; import { OrganizationResponse } from "../admin-console/models/response/organization.response"; import { SelectionReadOnly } from "../admin-console/models/selection-read-only"; @@ -38,6 +37,7 @@ import { TemplateResponse } from "../models/response/template.response"; import { SendResponse } from "../tools/send/models/send.response"; import { CliUtils } from "../utils"; import { CipherResponse } from "../vault/models/cipher.response"; +import { CollectionResponse } from "../vault/models/collection.response"; import { FolderResponse } from "../vault/models/folder.response"; import { DownloadCommand } from "./download.command"; diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index 59c2b92e74f..8b94eb59822 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -1,27 +1,27 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; -import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; -import { - CollectionDetailsResponse as ApiCollectionDetailsResponse, - CollectionResponse as ApiCollectionResponse, -} from "@bitwarden/common/admin-console/models/response/collection.response"; import { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response"; 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 { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; +import { Collection } from "@bitwarden/common/vault/models/domain/collection"; +import { + CollectionDetailsResponse as ApiCollectionDetailsResponse, + CollectionResponse as ApiCollectionResponse, +} from "@bitwarden/common/vault/models/response/collection.response"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { CollectionResponse } from "../admin-console/models/response/collection.response"; import { OrganizationUserResponse } from "../admin-console/models/response/organization-user.response"; import { OrganizationResponse } from "../admin-console/models/response/organization.response"; import { Response } from "../models/response"; import { ListResponse } from "../models/response/list.response"; import { CliUtils } from "../utils"; import { CipherResponse } from "../vault/models/cipher.response"; +import { CollectionResponse } from "../vault/models/collection.response"; import { FolderResponse } from "../vault/models/folder.response"; export class ListCommand { diff --git a/apps/cli/src/utils.ts b/apps/cli/src/utils.ts index 42f1482b694..d5e442ded19 100644 --- a/apps/cli/src/utils.ts +++ b/apps/cli/src/utils.ts @@ -5,10 +5,10 @@ import * as inquirer from "inquirer"; import * as JSZip from "jszip"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { NodeUtils } from "@bitwarden/common/misc/nodeUtils"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { Response } from "./models/response"; diff --git a/apps/cli/src/vault/create.command.ts b/apps/cli/src/vault/create.command.ts index d98221dc39c..49a61e6e59d 100644 --- a/apps/cli/src/vault/create.command.ts +++ b/apps/cli/src/vault/create.command.ts @@ -2,7 +2,6 @@ import * as fs from "fs"; import * as path from "path"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionRequest } from "@bitwarden/common/admin-console/models/request/collection.request"; import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; import { CipherExport } from "@bitwarden/common/models/export/cipher.export"; import { CollectionExport } from "@bitwarden/common/models/export/collection.export"; @@ -13,6 +12,7 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { CollectionRequest } from "@bitwarden/common/vault/models/request/collection.request"; import { OrganizationCollectionRequest } from "../admin-console/models/request/organization-collection.request"; import { OrganizationCollectionResponse } from "../admin-console/models/response/organization-collection.response"; diff --git a/apps/cli/src/admin-console/models/response/collection.response.ts b/apps/cli/src/vault/models/collection.response.ts similarity index 65% rename from apps/cli/src/admin-console/models/response/collection.response.ts rename to apps/cli/src/vault/models/collection.response.ts index 317249829fd..4cdb4bb59e6 100644 --- a/apps/cli/src/admin-console/models/response/collection.response.ts +++ b/apps/cli/src/vault/models/collection.response.ts @@ -1,7 +1,7 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { CollectionWithIdExport } from "@bitwarden/common/models/export/collection-with-id.export"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; -import { BaseResponse } from "../../../models/response/base.response"; +import { BaseResponse } from "../../models/response/base.response"; export class CollectionResponse extends CollectionWithIdExport implements BaseResponse { object: string; diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 3ffd2277c4b..d3829d4e638 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -22,7 +22,6 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; @@ -39,6 +38,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { SystemService } from "@bitwarden/common/platform/abstractions/system.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; 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 d06f37dc08d..aa7eba32838 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.ts +++ b/apps/desktop/src/vault/app/vault/add-edit.component.ts @@ -5,7 +5,6 @@ import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -16,6 +15,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; diff --git a/apps/desktop/src/vault/app/vault/collections.component.ts b/apps/desktop/src/vault/app/vault/collections.component.ts index 1b596c9c6a8..b9ad3ecfcf2 100644 --- a/apps/desktop/src/vault/app/vault/collections.component.ts +++ b/apps/desktop/src/vault/app/vault/collections.component.ts @@ -1,11 +1,11 @@ import { Component } from "@angular/core"; import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @Component({ selector: "app-vault-collections", diff --git a/apps/desktop/src/vault/app/vault/share.component.ts b/apps/desktop/src/vault/app/vault/share.component.ts index e07a100d882..99d81f44a15 100644 --- a/apps/desktop/src/vault/app/vault/share.component.ts +++ b/apps/desktop/src/vault/app/vault/share.component.ts @@ -2,12 +2,12 @@ import { Component } from "@angular/core"; import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @Component({ selector: "app-vault-share", diff --git a/apps/web/src/app/admin-console/organizations/core/services/group/group.service.ts b/apps/web/src/app/admin-console/organizations/core/services/group/group.service.ts index 772fbd3cf48..680c358b1fb 100644 --- a/apps/web/src/app/admin-console/organizations/core/services/group/group.service.ts +++ b/apps/web/src/app/admin-console/organizations/core/services/group/group.service.ts @@ -11,29 +11,11 @@ import { GroupRequest } from "./requests/group.request"; import { OrganizationGroupBulkRequest } from "./requests/organization-group-bulk.request"; import { GroupDetailsResponse, GroupResponse } from "./responses/group.response"; -@Injectable({ providedIn: CoreOrganizationModule }) +@Injectable({ + providedIn: "root", +}) export class GroupService { - constructor(private apiService: ApiService) {} - - async delete(orgId: string, groupId: string): Promise { - await this.apiService.send( - "DELETE", - "/organizations/" + orgId + "/groups/" + groupId, - null, - true, - false - ); - } - - async deleteMany(orgId: string, groupIds: string[]): Promise { - await this.apiService.send( - "DELETE", - "/organizations/" + orgId + "/groups", - new OrganizationGroupBulkRequest(groupIds), - true, - true - ); - } + constructor(protected apiService: ApiService) {} async get(orgId: string, groupId: string): Promise { const r = await this.apiService.send( @@ -60,6 +42,33 @@ export class GroupService { return listResponse.data?.map((gr) => GroupView.fromResponse(gr)) ?? []; } +} + +@Injectable({ providedIn: CoreOrganizationModule }) +export class InternalGroupService extends GroupService { + constructor(protected apiService: ApiService) { + super(apiService); + } + + async delete(orgId: string, groupId: string): Promise { + await this.apiService.send( + "DELETE", + "/organizations/" + orgId + "/groups/" + groupId, + null, + true, + false + ); + } + + async deleteMany(orgId: string, groupIds: string[]): Promise { + await this.apiService.send( + "DELETE", + "/organizations/" + orgId + "/groups", + new OrganizationGroupBulkRequest(groupIds), + true, + true + ); + } async save(group: GroupView): Promise { const request = new GroupRequest(); diff --git a/apps/web/src/app/admin-console/organizations/core/services/index.ts b/apps/web/src/app/admin-console/organizations/core/services/index.ts index 1e670faccd6..627cb2416ae 100644 --- a/apps/web/src/app/admin-console/organizations/core/services/index.ts +++ b/apps/web/src/app/admin-console/organizations/core/services/index.ts @@ -1,3 +1,2 @@ export * from "./group/group.service"; -export * from "./collection-admin.service"; export * from "./user-admin.service"; diff --git a/apps/web/src/app/admin-console/organizations/core/views/index.ts b/apps/web/src/app/admin-console/organizations/core/views/index.ts index e7ba6859901..ef14753c48a 100644 --- a/apps/web/src/app/admin-console/organizations/core/views/index.ts +++ b/apps/web/src/app/admin-console/organizations/core/views/index.ts @@ -1,5 +1,4 @@ export * from "./collection-access-selection.view"; -export * from "./collection-admin.view"; export * from "./group.view"; export * from "./organization-user.view"; export * from "./organization-user-admin-view"; diff --git a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts index 433c6049f6a..11b32f430be 100644 --- a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts +++ b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.ts @@ -6,16 +6,16 @@ import { catchError, combineLatest, from, map, of, Subject, switchMap, takeUntil import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/services/dialog"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; -import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; -import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/models/response/collection.response"; 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 { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; +import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; +import { Collection } from "@bitwarden/common/vault/models/domain/collection"; +import { CollectionDetailsResponse } from "@bitwarden/common/vault/models/response/collection.response"; -import { GroupService, GroupView } from "../core"; +import { InternalGroupService as GroupService, GroupView } from "../core"; import { AccessItemType, AccessItemValue, diff --git a/apps/web/src/app/admin-console/organizations/manage/groups.component.ts b/apps/web/src/app/admin-console/organizations/manage/groups.component.ts index 24eb9305858..82e5acba213 100644 --- a/apps/web/src/app/admin-console/organizations/manage/groups.component.ts +++ b/apps/web/src/app/admin-console/organizations/manage/groups.component.ts @@ -19,21 +19,21 @@ import { DialogServiceAbstraction, SimpleDialogType } from "@bitwarden/angular/s import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; -import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; -import { - CollectionDetailsResponse, - CollectionResponse, -} from "@bitwarden/common/admin-console/models/response/collection.response"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { ListResponse } from "@bitwarden/common/models/response/list.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 { Utils } from "@bitwarden/common/platform/misc/utils"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; +import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; +import { Collection } from "@bitwarden/common/vault/models/domain/collection"; +import { + CollectionDetailsResponse, + CollectionResponse, +} from "@bitwarden/common/vault/models/response/collection.response"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; -import { GroupService, GroupView } from "../core"; +import { InternalGroupService as GroupService, GroupView } from "../core"; import { GroupAddEditDialogResultType, diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts index 72833a09719..5a707b795f5 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts @@ -12,14 +12,14 @@ import { } from "@bitwarden/common/admin-console/enums"; import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permissions.api"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { flagEnabled } from "../../../../../../utils/flags"; +import { CollectionAdminService } from "../../../../../vault/core/collection-admin.service"; import { CollectionAccessSelectionView, - CollectionAdminService, GroupService, GroupView, OrganizationUserAdminView, diff --git a/apps/web/src/app/admin-console/organizations/members/people.component.ts b/apps/web/src/app/admin-console/organizations/members/people.component.ts index 33241604976..e86b5a27ec4 100644 --- a/apps/web/src/app/admin-console/organizations/members/people.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/people.component.ts @@ -30,7 +30,6 @@ import { OrganizationUserUserDetailsResponse, } from "@bitwarden/common/abstractions/organization-user/responses"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction as PolicyApiService } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; @@ -40,11 +39,8 @@ import { OrganizationUserType, PolicyType, } from "@bitwarden/common/admin-console/enums"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; -import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request"; -import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/models/response/collection.response"; import { ProductType } from "@bitwarden/common/enums"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -53,7 +49,11 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; +import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; +import { Collection } from "@bitwarden/common/vault/models/domain/collection"; +import { CollectionDetailsResponse } from "@bitwarden/common/vault/models/response/collection.response"; import { EntityEventsComponent } from "../../../admin-console/organizations/manage/entity-events.component"; import { BasePeopleComponent } from "../../../common/base.people.component"; diff --git a/apps/web/src/app/admin-console/organizations/shared/index.ts b/apps/web/src/app/admin-console/organizations/shared/index.ts index 24a7c9176b1..941a5ddd635 100644 --- a/apps/web/src/app/admin-console/organizations/shared/index.ts +++ b/apps/web/src/app/admin-console/organizations/shared/index.ts @@ -1,2 +1 @@ export * from "./shared-organization.module"; -export * from "./components/collection-dialog"; diff --git a/apps/web/src/app/admin-console/organizations/shared/shared-organization.module.ts b/apps/web/src/app/admin-console/organizations/shared/shared-organization.module.ts index 094a059099d..b749bdea499 100644 --- a/apps/web/src/app/admin-console/organizations/shared/shared-organization.module.ts +++ b/apps/web/src/app/admin-console/organizations/shared/shared-organization.module.ts @@ -5,11 +5,10 @@ import { SearchModule } from "@bitwarden/components"; import { SharedModule } from "../../../shared/shared.module"; import { AccessSelectorModule } from "./components/access-selector/access-selector.module"; -import { CollectionDialogModule } from "./components/collection-dialog"; @NgModule({ - imports: [SharedModule, CollectionDialogModule, AccessSelectorModule, SearchModule], + imports: [SharedModule, AccessSelectorModule, SearchModule], declarations: [], - exports: [SharedModule, CollectionDialogModule, AccessSelectorModule, SearchModule], + exports: [SharedModule, AccessSelectorModule, SearchModule], }) export class SharedOrganizationModule {} 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-export/org-import-export.module.ts index 106b524caf6..e40e961ac98 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-export/org-import-export.module.ts @@ -1,10 +1,10 @@ import { NgModule } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { ImportService, diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index d7447c7a864..9a22ea20b41 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -13,7 +13,6 @@ import { NotificationsService } from "@bitwarden/common/abstractions/notificatio import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; @@ -25,6 +24,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; 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 e04175b890d..8c3269fbdb5 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 @@ -4,7 +4,6 @@ import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -15,6 +14,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password/"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 69d08169f74..03f20ad2955 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -28,6 +28,7 @@ import { PolicyListService } from "../admin-console/core/policy-list.service"; import { HtmlStorageService } from "../core/html-storage.service"; import { I18nService } from "../core/i18n.service"; import { StateMigrationService } from "../core/state-migration.service"; +import { CollectionAdminService } from "../vault/core/collection-admin.service"; import { PasswordRepromptService } from "../vault/core/password-reprompt.service"; import { BroadcasterMessagingService } from "./broadcaster-messaging.service"; @@ -106,6 +107,7 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service"; useClass: LoginService, deps: [StateService], }, + CollectionAdminService, ], }) export class CoreModule { diff --git a/apps/web/src/app/core/state/state.service.ts b/apps/web/src/app/core/state/state.service.ts index ca5d00a5e58..60f09ceae36 100644 --- a/apps/web/src/app/core/state/state.service.ts +++ b/apps/web/src/app/core/state/state.service.ts @@ -6,7 +6,6 @@ import { STATE_FACTORY, STATE_SERVICE_USE_CACHE, } from "@bitwarden/angular/services/injection-tokens"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { StateMigrationService } from "@bitwarden/common/platform/abstractions/state-migration.service"; import { @@ -18,6 +17,7 @@ import { StorageOptions } from "@bitwarden/common/platform/models/domain/storage import { StateService as BaseStateService } from "@bitwarden/common/platform/services/state.service"; import { SendData } from "@bitwarden/common/tools/send/models/data/send.data"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; +import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; import { FolderData } from "@bitwarden/common/vault/models/data/folder.data"; import { Account } from "./account"; diff --git a/apps/web/src/app/tools/import-export/import-export.module.ts b/apps/web/src/app/tools/import-export/import-export.module.ts index 68338c23040..4d59f412367 100644 --- a/apps/web/src/app/tools/import-export/import-export.module.ts +++ b/apps/web/src/app/tools/import-export/import-export.module.ts @@ -1,10 +1,10 @@ import { NgModule } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { ImportService, diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.html b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.html similarity index 100% rename from apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.html rename to apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.html diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts similarity index 94% rename from apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts rename to apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts index 2ac91bf0abd..ac3c62a5b80 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.ts @@ -8,25 +8,22 @@ import { OrganizationUserService } from "@bitwarden/common/abstractions/organiza import { OrganizationUserUserDetailsResponse } from "@bitwarden/common/abstractions/organization-user/responses"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { BitValidators } from "@bitwarden/components"; +import { GroupService, GroupView } from "../../../admin-console/organizations/core"; +import { PermissionMode } from "../../../admin-console/organizations/shared/components/access-selector/access-selector.component"; import { - CollectionAdminService, - CollectionAdminView, - GroupService, - GroupView, -} from "../../../core"; -import { - AccessItemType, - AccessItemValue, AccessItemView, - convertToPermission, + AccessItemValue, + AccessItemType, convertToSelectionView, - PermissionMode, -} from "../access-selector"; + convertToPermission, +} from "../../../admin-console/organizations/shared/components/access-selector/access-selector.models"; +import { CollectionAdminService } from "../../core/collection-admin.service"; +import { CollectionAdminView } from "../../core/views/collection-admin.view"; export enum CollectionDialogTabType { Info = 0, diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.module.ts b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.module.ts similarity index 65% rename from apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.module.ts rename to apps/web/src/app/vault/components/collection-dialog/collection-dialog.module.ts index 4f9b19e62ae..a8f284fb485 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.module.ts +++ b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.module.ts @@ -2,11 +2,10 @@ import { NgModule } from "@angular/core"; import { SelectModule } from "@bitwarden/components"; -import { AccessSelectorModule } from "../../../../../admin-console/organizations/shared/components/access-selector/access-selector.module"; -import { SharedModule } from "../../../../../shared"; +import { AccessSelectorModule } from "../../../admin-console/organizations/shared/components/access-selector/access-selector.module"; +import { SharedModule } from "../../../shared"; import { CollectionDialogComponent } from "./collection-dialog.component"; - @NgModule({ imports: [SharedModule, AccessSelectorModule, SelectModule], declarations: [CollectionDialogComponent], diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/index.ts b/apps/web/src/app/vault/components/collection-dialog/index.ts similarity index 100% rename from apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/index.ts rename to apps/web/src/app/vault/components/collection-dialog/index.ts 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 abed3b320be..7bd9677c759 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 @@ -2,9 +2,9 @@ import { Component, EventEmitter, HostBinding, HostListener, Input, Output } fro import { ActivatedRoute, Router } from "@angular/router"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { VaultItemEvent } from "./vault-item-event"; import { RowHeightClass } from "./vault-items.component"; diff --git a/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.ts b/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.ts index 085d4653503..faee4e030b9 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.ts @@ -2,9 +2,10 @@ import { Component, EventEmitter, HostBinding, HostListener, Input, Output } fro import { ActivatedRoute, Router } from "@angular/router"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; -import { CollectionAdminView, GroupView } from "../../../admin-console/organizations/core"; +import { GroupView } from "../../../admin-console/organizations/core"; +import { CollectionAdminView } from "../../core/views/collection-admin.view"; import { VaultItemEvent } from "./vault-item-event"; import { RowHeightClass } from "./vault-items.component"; diff --git a/apps/web/src/app/vault/components/vault-items/vault-item-event.ts b/apps/web/src/app/vault/components/vault-items/vault-item-event.ts index 2643fcd7b13..cacd13829fb 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-item-event.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-item-event.ts @@ -1,4 +1,4 @@ -import { CollectionView } from "@bitwarden/common/src/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/src/vault/models/view/collection.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { VaultItem } from "./vault-item"; diff --git a/apps/web/src/app/vault/components/vault-items/vault-item.ts b/apps/web/src/app/vault/components/vault-items/vault-item.ts index c8c91becdbe..642c707122a 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-item.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-item.ts @@ -1,5 +1,5 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; export interface VaultItem { collection?: CollectionView; diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.component.ts b/apps/web/src/app/vault/components/vault-items/vault-items.component.ts index 4fcf0439920..8c9ad1ac065 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.component.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.component.ts @@ -2,11 +2,12 @@ import { SelectionModel } from "@angular/cdk/collections"; import { Component, EventEmitter, Input, Output } from "@angular/core"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { TableDataSource } from "@bitwarden/components"; -import { CollectionAdminView, GroupView } from "../../../admin-console/organizations/core"; +import { GroupView } from "../../../admin-console/organizations/core"; +import { CollectionAdminView } from "../../core/views/collection-admin.view"; import { Unassigned } from "../../individual-vault/vault-filter/shared/models/routed-vault-filter.model"; import { VaultItem } from "./vault-item"; diff --git a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts index 99799436151..cfe5e41719a 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts +++ b/apps/web/src/app/vault/components/vault-items/vault-items.stories.ts @@ -19,10 +19,10 @@ import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { CollectionAccessSelectionView, - CollectionAdminView, GroupView, } from "../../../admin-console/organizations/core"; import { PreloadedEnglishI18nModule } from "../../../core/tests"; +import { CollectionAdminView } from "../../core/views/collection-admin.view"; import { Unassigned } from "../../individual-vault/vault-filter/shared/models/routed-vault-filter.model"; import { VaultItemsComponent } from "./vault-items.component"; diff --git a/apps/web/src/app/admin-console/organizations/core/services/collection-admin.service.ts b/apps/web/src/app/vault/core/collection-admin.service.ts similarity index 91% rename from apps/web/src/app/admin-console/organizations/core/services/collection-admin.service.ts rename to apps/web/src/app/vault/core/collection-admin.service.ts index 85f3d9423f1..efeb3817eab 100644 --- a/apps/web/src/app/admin-console/organizations/core/services/collection-admin.service.ts +++ b/apps/web/src/app/vault/core/collection-admin.service.ts @@ -1,19 +1,18 @@ import { Injectable } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionRequest } from "@bitwarden/common/admin-console/models/request/collection.request"; import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { CollectionRequest } from "@bitwarden/common/vault/models/request/collection.request"; import { CollectionAccessDetailsResponse, CollectionResponse, -} from "@bitwarden/common/admin-console/models/response/collection.response"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +} from "@bitwarden/common/vault/models/response/collection.response"; -import { CoreOrganizationModule } from "../core-organization.module"; -import { CollectionAdminView } from "../views/collection-admin.view"; +import { CollectionAdminView } from "./views/collection-admin.view"; -@Injectable({ providedIn: CoreOrganizationModule }) +@Injectable() export class CollectionAdminService { constructor(private apiService: ApiService, private cryptoService: CryptoService) {} diff --git a/apps/web/src/app/admin-console/organizations/core/views/collection-admin.view.ts b/apps/web/src/app/vault/core/views/collection-admin.view.ts similarity index 73% rename from apps/web/src/app/admin-console/organizations/core/views/collection-admin.view.ts rename to apps/web/src/app/vault/core/views/collection-admin.view.ts index be38798379d..c97dab8422e 100644 --- a/apps/web/src/app/admin-console/organizations/core/views/collection-admin.view.ts +++ b/apps/web/src/app/vault/core/views/collection-admin.view.ts @@ -1,7 +1,7 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; -import { CollectionAccessDetailsResponse } from "@bitwarden/common/src/admin-console/models/response/collection.response"; +import { CollectionAccessDetailsResponse } from "@bitwarden/common/src/vault/models/response/collection.response"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; -import { CollectionAccessSelectionView } from "./collection-access-selection.view"; +import { CollectionAccessSelectionView } from "../../../admin-console/organizations/core/views/collection-access-selection.view"; export class CollectionAdminView extends CollectionView { groups: CollectionAccessSelectionView[] = []; 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 548bddcd332..460942c3046 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 @@ -5,7 +5,6 @@ import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vau import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { EventType, ProductType } from "@bitwarden/common/enums"; @@ -17,6 +16,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts index 742f2bbef78..057ef71b338 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-share-dialog/bulk-share-dialog.component.ts @@ -2,16 +2,16 @@ import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog"; import { Component, Inject, OnInit } from "@angular/core"; import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; 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 { Checkable, isChecked } from "@bitwarden/common/types/checkable"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; export interface BulkShareDialogParams { ciphers: CipherView[]; diff --git a/apps/web/src/app/vault/individual-vault/collections.component.ts b/apps/web/src/app/vault/individual-vault/collections.component.ts index 509833c7067..396e8760ec4 100644 --- a/apps/web/src/app/vault/individual-vault/collections.component.ts +++ b/apps/web/src/app/vault/individual-vault/collections.component.ts @@ -1,12 +1,12 @@ import { Component, OnDestroy } from "@angular/core"; import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; @Component({ selector: "app-vault-collections", diff --git a/apps/web/src/app/vault/individual-vault/pipes/get-collection-name.pipe.ts b/apps/web/src/app/vault/individual-vault/pipes/get-collection-name.pipe.ts index 45cadb4b039..e7e245a5340 100644 --- a/apps/web/src/app/vault/individual-vault/pipes/get-collection-name.pipe.ts +++ b/apps/web/src/app/vault/individual-vault/pipes/get-collection-name.pipe.ts @@ -1,6 +1,6 @@ import { Pipe, PipeTransform } from "@angular/core"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; @Pipe({ name: "collectionNameFromId", diff --git a/apps/web/src/app/vault/individual-vault/share.component.ts b/apps/web/src/app/vault/individual-vault/share.component.ts index f5c62644ff4..a85dd6cf4c1 100644 --- a/apps/web/src/app/vault/individual-vault/share.component.ts +++ b/apps/web/src/app/vault/individual-vault/share.component.ts @@ -1,13 +1,13 @@ import { Component, OnDestroy } from "@angular/core"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; @Component({ selector: "app-vault-share", diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts index 3a03a338e3a..0c8ced7df3a 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/abstractions/vault-filter.service.ts @@ -1,8 +1,8 @@ import { Observable } from "rxjs"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/src/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/src/models/domain/tree-node"; +import { CollectionView } from "@bitwarden/common/src/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/src/vault/models/view/folder.view"; import { diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts index 42743f37f90..88f004262e5 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.spec.ts @@ -5,12 +5,12 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { VaultFilterService } from "./vault-filter.service"; diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts index ddc2df61099..f7663ebc42c 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts @@ -18,7 +18,6 @@ import { import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { ServiceUtils } from "@bitwarden/common/misc/serviceUtils"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -26,9 +25,10 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { CollectionAdminView } from "../../../../admin-console/organizations/core"; +import { CollectionAdminView } from "../../../core/views/collection-admin.view"; import { CipherTypeFilter, CollectionFilter, diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.model.spec.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.model.spec.ts index 332b197669e..a754f0151bb 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.model.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.model.spec.ts @@ -1,8 +1,8 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { VaultFilter } from "./vault-filter.model"; diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts index ce3959fe059..8f459f8c8c2 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/vault-filter.type.ts @@ -3,7 +3,7 @@ import { ITreeNodeObject } from "@bitwarden/common/src/models/domain/tree-node"; import { FolderView } from "@bitwarden/common/src/vault/models/view/folder.view"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; -import { CollectionAdminView } from "../../../../../admin-console/organizations/core"; +import { CollectionAdminView } from "../../../../core/views/collection-admin.view"; export type CipherStatus = "all" | "favorites" | "trash" | CipherType; diff --git a/apps/web/src/app/vault/individual-vault/vault-header/vault-header.component.ts b/apps/web/src/app/vault/individual-vault/vault-header/vault-header.component.ts index f2a7b855321..092f9e76cd0 100644 --- a/apps/web/src/app/vault/individual-vault/vault-header/vault-header.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-header/vault-header.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from "@angular/core"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { All, 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 168fb912147..176fb3fcb36 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -34,10 +34,8 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { DEFAULT_PBKDF2_ITERATIONS, EventType, KdfType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -53,10 +51,12 @@ 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 { 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 { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { Icons } from "@bitwarden/components"; import { UpdateKeyComponent } from "../../settings/update-key.component"; diff --git a/apps/web/src/app/vault/individual-vault/vault.module.ts b/apps/web/src/app/vault/individual-vault/vault.module.ts index 5e3cc67bc06..e584cae701f 100644 --- a/apps/web/src/app/vault/individual-vault/vault.module.ts +++ b/apps/web/src/app/vault/individual-vault/vault.module.ts @@ -3,6 +3,7 @@ import { NgModule } from "@angular/core"; import { BreadcrumbsModule } from "@bitwarden/components"; import { LooseComponentsModule, SharedModule } from "../../shared"; +import { CollectionDialogModule } from "../components/collection-dialog"; import { VaultItemsModule } from "../components/vault-items/vault-items.module"; import { CollectionBadgeModule } from "../org-vault/collection-badge/collection-badge.module"; import { GroupBadgeModule } from "../org-vault/group-badge/group-badge.module"; @@ -28,6 +29,7 @@ import { VaultComponent } from "./vault.component"; BulkDialogsModule, BreadcrumbsModule, VaultItemsModule, + CollectionDialogModule, ], declarations: [VaultComponent, VaultHeaderComponent], exports: [VaultComponent], 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 88d1ef7018d..53dc3b48df0 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 @@ -5,7 +5,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -16,6 +15,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; diff --git a/apps/web/src/app/vault/org-vault/collection-badge/collection-name.badge.component.ts b/apps/web/src/app/vault/org-vault/collection-badge/collection-name.badge.component.ts index fa4056983a3..4f4e9e269d5 100644 --- a/apps/web/src/app/vault/org-vault/collection-badge/collection-name.badge.component.ts +++ b/apps/web/src/app/vault/org-vault/collection-badge/collection-name.badge.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from "@angular/core"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; @Component({ selector: "app-collection-badge", diff --git a/apps/web/src/app/vault/org-vault/collections.component.ts b/apps/web/src/app/vault/org-vault/collections.component.ts index e31ae408173..ea528401600 100644 --- a/apps/web/src/app/vault/org-vault/collections.component.ts +++ b/apps/web/src/app/vault/org-vault/collections.component.ts @@ -1,12 +1,12 @@ import { Component } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherCollectionsRequest } from "@bitwarden/common/vault/models/request/cipher-collections.request"; diff --git a/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.service.ts b/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.service.ts index 222537c4b1c..e38d66a5815 100644 --- a/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.service.ts +++ b/apps/web/src/app/vault/org-vault/vault-filter/vault-filter.service.ts @@ -8,11 +8,9 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { - CollectionAdminService, - CollectionAdminView, -} from "../../../admin-console/organizations/core"; import { StateService } from "../../../core"; +import { CollectionAdminView } from "../../../vault/core/views/collection-admin.view"; +import { CollectionAdminService } from "../../core/collection-admin.service"; import { VaultFilterService as BaseVaultFilterService } from "../../individual-vault/vault-filter/services/vault-filter.service"; import { CollectionFilter } from "../../individual-vault/vault-filter/shared/models/vault-filter.type"; diff --git a/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.ts b/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.ts index 6c614d229b4..49055e487d3 100644 --- a/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.ts +++ b/apps/web/src/app/vault/org-vault/vault-header/vault-header.component.ts @@ -14,11 +14,9 @@ import { ProductType } from "@bitwarden/common/enums"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { - CollectionAdminService, - CollectionAdminView, -} from "../../../admin-console/organizations/core"; -import { CollectionDialogTabType } from "../../../admin-console/organizations/shared"; +import { CollectionAdminView } from "../../../vault/core/views/collection-admin.view"; +import { CollectionDialogTabType } from "../../components/collection-dialog"; +import { CollectionAdminService } from "../../core/collection-admin.service"; import { All, RoutedVaultFilterModel, 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 2cb7a8f14cf..8048ade1c70 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.ts +++ b/apps/web/src/app/vault/org-vault/vault.component.ts @@ -38,7 +38,6 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { EventType } from "@bitwarden/common/enums"; import { ServiceUtils } from "@bitwarden/common/misc/serviceUtils"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; @@ -53,23 +52,21 @@ import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/pa 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 { Icons } from "@bitwarden/components"; -import { - CollectionAdminService, - CollectionAdminView, - GroupService, - GroupView, -} from "../../admin-console/organizations/core"; +import { GroupService, GroupView } from "../../admin-console/organizations/core"; import { EntityEventsComponent } from "../../admin-console/organizations/manage/entity-events.component"; +import { VaultFilterService } from "../../vault/individual-vault/vault-filter/services/abstractions/vault-filter.service"; +import { VaultFilter } from "../../vault/individual-vault/vault-filter/shared/models/vault-filter.model"; import { CollectionDialogResult, CollectionDialogTabType, openCollectionDialog, -} from "../../admin-console/organizations/shared"; -import { VaultFilterService } from "../../vault/individual-vault/vault-filter/services/abstractions/vault-filter.service"; -import { VaultFilter } from "../../vault/individual-vault/vault-filter/shared/models/vault-filter.model"; +} from "../components/collection-dialog"; import { VaultItemEvent } from "../components/vault-items/vault-item-event"; +import { CollectionAdminService } from "../core/collection-admin.service"; +import { CollectionAdminView } from "../core/views/collection-admin.view"; import { BulkDeleteDialogResult, openBulkDeleteDialog, diff --git a/apps/web/src/app/vault/org-vault/vault.module.ts b/apps/web/src/app/vault/org-vault/vault.module.ts index 070898b06c1..1693f0cd3e4 100644 --- a/apps/web/src/app/vault/org-vault/vault.module.ts +++ b/apps/web/src/app/vault/org-vault/vault.module.ts @@ -6,6 +6,7 @@ import { LooseComponentsModule } from "../../shared/loose-components.module"; import { SharedModule } from "../../shared/shared.module"; import { OrganizationBadgeModule } from "../../vault/individual-vault/organization-badge/organization-badge.module"; import { PipesModule } from "../../vault/individual-vault/pipes/pipes.module"; +import { CollectionDialogModule } from "../components/collection-dialog"; import { VaultItemsModule } from "../components/vault-items/vault-items.module"; import { CollectionBadgeModule } from "./collection-badge/collection-badge.module"; @@ -27,6 +28,7 @@ import { VaultComponent } from "./vault.component"; PipesModule, BreadcrumbsModule, VaultItemsModule, + CollectionDialogModule, ], declarations: [VaultComponent, VaultHeaderComponent], exports: [VaultComponent], diff --git a/apps/web/src/app/vault/utils/collection-utils.spec.ts b/apps/web/src/app/vault/utils/collection-utils.spec.ts index 17c213e151e..bf84b3155b5 100644 --- a/apps/web/src/app/vault/utils/collection-utils.spec.ts +++ b/apps/web/src/app/vault/utils/collection-utils.spec.ts @@ -1,4 +1,4 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { getNestedCollectionTree } from "./collection-utils"; diff --git a/apps/web/src/app/vault/utils/collection-utils.ts b/apps/web/src/app/vault/utils/collection-utils.ts index bf018b52fc4..c25e5a37383 100644 --- a/apps/web/src/app/vault/utils/collection-utils.ts +++ b/apps/web/src/app/vault/utils/collection-utils.ts @@ -1,11 +1,11 @@ +import { ServiceUtils } from "@bitwarden/common/misc/serviceUtils"; +import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { CollectionView, NestingDelimiter, -} from "@bitwarden/common/admin-console/models/view/collection.view"; -import { ServiceUtils } from "@bitwarden/common/misc/serviceUtils"; -import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; +} from "@bitwarden/common/vault/models/view/collection.view"; -import { CollectionAdminView } from "../../admin-console/organizations/core"; +import { CollectionAdminView } from "../../vault/core/views/collection-admin.view"; export function getNestedCollectionTree( collections: CollectionAdminView[] diff --git a/libs/angular/src/admin-console/components/collections.component.ts b/libs/angular/src/admin-console/components/collections.component.ts index d56d111e071..2fa5b5d3d3a 100644 --- a/libs/angular/src/admin-console/components/collections.component.ts +++ b/libs/angular/src/admin-console/components/collections.component.ts @@ -1,13 +1,13 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; 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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; @Directive() export class CollectionsComponent implements OnInit { diff --git a/libs/angular/src/components/share.component.ts b/libs/angular/src/components/share.component.ts index 5c8224eaddc..73792f91fef 100644 --- a/libs/angular/src/components/share.component.ts +++ b/libs/angular/src/components/share.component.ts @@ -1,18 +1,18 @@ import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core"; import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; 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 { Utils } from "@bitwarden/common/platform/misc/utils"; import { Checkable, isChecked } from "@bitwarden/common/types/checkable"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; @Directive() export class ShareComponent implements OnInit, OnDestroy { diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index bf5cb5a09a1..234359a5236 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -22,7 +22,6 @@ import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstrac import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; -import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { InternalOrganizationService, @@ -34,7 +33,6 @@ import { PolicyService as PolicyServiceAbstraction, } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service"; -import { CollectionService } from "@bitwarden/common/admin-console/services/collection.service"; import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; @@ -127,6 +125,7 @@ import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/t import { SendService } from "@bitwarden/common/tools/send/services/send.service"; import { SendService as SendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/vault/abstractions/collection.service"; import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { @@ -137,6 +136,7 @@ import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@ 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"; +import { CollectionService } from "@bitwarden/common/vault/services/collection.service"; import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; diff --git a/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts b/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts index 74e34921259..6672c45138a 100644 --- a/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts +++ b/libs/angular/src/vault/abstractions/deprecated-vault-filter.service.ts @@ -1,7 +1,7 @@ import { Observable } from "rxjs"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { DynamicTreeNode } from "../vault-filter/models/dynamic-tree-node.model"; diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts index 83b8e3e0fda..08d6a23076b 100644 --- a/libs/angular/src/vault/components/add-edit.component.ts +++ b/libs/angular/src/vault/components/add-edit.component.ts @@ -3,7 +3,6 @@ import { Observable, Subject, takeUntil, concatMap } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { isMember, OrganizationService, @@ -11,7 +10,6 @@ import { import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { EventType, SecureNoteType, UriMatchType } from "@bitwarden/common/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -21,6 +19,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; 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"; @@ -28,6 +27,7 @@ import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CardView } from "@bitwarden/common/vault/models/view/card.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { IdentityView } from "@bitwarden/common/vault/models/view/identity.view"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; diff --git a/libs/angular/src/vault/vault-filter/components/collection-filter.component.ts b/libs/angular/src/vault/vault-filter/components/collection-filter.component.ts index 1d90f43ba2d..f752f9a9a9a 100644 --- a/libs/angular/src/vault/vault-filter/components/collection-filter.component.ts +++ b/libs/angular/src/vault/vault-filter/components/collection-filter.component.ts @@ -1,7 +1,7 @@ import { Directive, EventEmitter, Input, Output } from "@angular/core"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { ITreeNodeObject } from "@bitwarden/common/models/domain/tree-node"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { DynamicTreeNode } from "../models/dynamic-tree-node.model"; import { TopLevelTreeNode } from "../models/top-level-tree-node.model"; diff --git a/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts b/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts index 1d4b5cf8bbb..7c37436492a 100644 --- a/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts +++ b/libs/angular/src/vault/vault-filter/components/vault-filter.component.ts @@ -2,8 +2,8 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { firstValueFrom, Observable } from "rxjs"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { ITreeNodeObject } from "@bitwarden/common/models/domain/tree-node"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { DeprecatedVaultFilterService } from "../../abstractions/deprecated-vault-filter.service"; diff --git a/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts b/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts index 6464254e458..b4fb8f62e0e 100644 --- a/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts +++ b/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts @@ -1,7 +1,6 @@ import { Injectable } from "@angular/core"; import { firstValueFrom, from, mergeMap, Observable } from "rxjs"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { isMember, OrganizationService, @@ -9,12 +8,13 @@ import { import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { ServiceUtils } from "@bitwarden/common/misc/serviceUtils"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; 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 { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { DeprecatedVaultFilterService as DeprecatedVaultFilterServiceAbstraction } from "../../abstractions/deprecated-vault-filter.service"; diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index 2273b290191..d21de917186 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -1,5 +1,4 @@ import { OrganizationConnectionType } from "../admin-console/enums"; -import { CollectionRequest } from "../admin-console/models/request/collection.request"; import { OrganizationSponsorshipCreateRequest } from "../admin-console/models/request/organization/organization-sponsorship-create.request"; import { OrganizationSponsorshipRedeemRequest } from "../admin-console/models/request/organization/organization-sponsorship-redeem.request"; import { OrganizationConnectionRequest } from "../admin-console/models/request/organization-connection.request"; @@ -14,10 +13,6 @@ import { ProviderUserConfirmRequest } from "../admin-console/models/request/prov import { ProviderUserInviteRequest } from "../admin-console/models/request/provider/provider-user-invite.request"; import { ProviderUserUpdateRequest } from "../admin-console/models/request/provider/provider-user-update.request"; import { SelectionReadOnlyRequest } from "../admin-console/models/request/selection-read-only.request"; -import { - CollectionAccessDetailsResponse, - CollectionResponse, -} from "../admin-console/models/response/collection.response"; import { OrganizationConnectionConfigApis, OrganizationConnectionResponse, @@ -135,9 +130,14 @@ import { CipherCreateRequest } from "../vault/models/request/cipher-create.reque import { CipherPartialRequest } from "../vault/models/request/cipher-partial.request"; import { CipherShareRequest } from "../vault/models/request/cipher-share.request"; import { CipherRequest } from "../vault/models/request/cipher.request"; +import { CollectionRequest } from "../vault/models/request/collection.request"; import { AttachmentUploadDataResponse } from "../vault/models/response/attachment-upload-data.response"; import { AttachmentResponse } from "../vault/models/response/attachment.response"; import { CipherResponse } from "../vault/models/response/cipher.response"; +import { + CollectionAccessDetailsResponse, + CollectionResponse, +} from "../vault/models/response/collection.response"; import { SyncResponse } from "../vault/models/response/sync.response"; /** diff --git a/libs/common/src/admin-console/models/response/organization-export.response.ts b/libs/common/src/admin-console/models/response/organization-export.response.ts index 9be06074730..b25b3cbaaea 100644 --- a/libs/common/src/admin-console/models/response/organization-export.response.ts +++ b/libs/common/src/admin-console/models/response/organization-export.response.ts @@ -1,7 +1,6 @@ import { BaseResponse } from "../../../models/response/base.response"; import { CipherResponse } from "../../../vault/models/response/cipher.response"; - -import { CollectionResponse } from "./collection.response"; +import { CollectionResponse } from "../../../vault/models/response/collection.response"; export class OrganizationExportResponse extends BaseResponse { collections: CollectionResponse[]; diff --git a/libs/common/src/models/export/collection-with-id.export.ts b/libs/common/src/models/export/collection-with-id.export.ts index b97c8b7900e..be25eaa7ef6 100644 --- a/libs/common/src/models/export/collection-with-id.export.ts +++ b/libs/common/src/models/export/collection-with-id.export.ts @@ -1,5 +1,5 @@ -import { Collection as CollectionDomain } from "../../admin-console/models/domain/collection"; -import { CollectionView } from "../../admin-console/models/view/collection.view"; +import { Collection as CollectionDomain } from "../../vault/models/domain/collection"; +import { CollectionView } from "../../vault/models/view/collection.view"; import { CollectionExport } from "./collection.export"; diff --git a/libs/common/src/models/export/collection.export.ts b/libs/common/src/models/export/collection.export.ts index 1d454323a9c..48251d581f9 100644 --- a/libs/common/src/models/export/collection.export.ts +++ b/libs/common/src/models/export/collection.export.ts @@ -1,6 +1,6 @@ -import { Collection as CollectionDomain } from "../../admin-console/models/domain/collection"; -import { CollectionView } from "../../admin-console/models/view/collection.view"; import { EncString } from "../../platform/models/domain/enc-string"; +import { Collection as CollectionDomain } from "../../vault/models/domain/collection"; +import { CollectionView } from "../../vault/models/view/collection.view"; export class CollectionExport { static template(): CollectionExport { diff --git a/libs/common/src/models/request/import-organization-ciphers.request.ts b/libs/common/src/models/request/import-organization-ciphers.request.ts index 5f1a4ee4c37..0689762de32 100644 --- a/libs/common/src/models/request/import-organization-ciphers.request.ts +++ b/libs/common/src/models/request/import-organization-ciphers.request.ts @@ -1,5 +1,5 @@ -import { CollectionWithIdRequest } from "../../admin-console/models/request/collection-with-id.request"; import { CipherRequest } from "../../vault/models/request/cipher.request"; +import { CollectionWithIdRequest } from "../../vault/models/request/collection-with-id.request"; import { KvpRequest } from "./kvp.request"; diff --git a/libs/common/src/platform/abstractions/state.service.ts b/libs/common/src/platform/abstractions/state.service.ts index fffeb07909a..a36176395de 100644 --- a/libs/common/src/platform/abstractions/state.service.ts +++ b/libs/common/src/platform/abstractions/state.service.ts @@ -1,12 +1,10 @@ import { Observable } from "rxjs"; -import { CollectionData } from "../../admin-console/models/data/collection.data"; import { EncryptedOrganizationKeyData } from "../../admin-console/models/data/encrypted-organization-key.data"; import { OrganizationData } from "../../admin-console/models/data/organization.data"; import { PolicyData } from "../../admin-console/models/data/policy.data"; import { ProviderData } from "../../admin-console/models/data/provider.data"; import { Policy } from "../../admin-console/models/domain/policy"; -import { CollectionView } from "../../admin-console/models/view/collection.view"; import { EnvironmentUrls } from "../../auth/models/domain/environment-urls"; import { ForceResetPasswordReason } from "../../auth/models/domain/force-reset-password-reason"; import { KdfConfig } from "../../auth/models/domain/kdf-config"; @@ -18,9 +16,11 @@ import { GeneratedPasswordHistory } from "../../tools/generator/password"; import { SendData } from "../../tools/send/models/data/send.data"; import { SendView } from "../../tools/send/models/view/send.view"; import { CipherData } from "../../vault/models/data/cipher.data"; +import { CollectionData } from "../../vault/models/data/collection.data"; import { FolderData } from "../../vault/models/data/folder.data"; import { LocalData } from "../../vault/models/data/local.data"; import { CipherView } from "../../vault/models/view/cipher.view"; +import { CollectionView } from "../../vault/models/view/collection.view"; import { AddEditCipherInfo } from "../../vault/types/add-edit-cipher-info"; import { ServerConfigData } from "../models/data/server-config.data"; import { Account, AccountSettingsSettings } from "../models/domain/account"; diff --git a/libs/common/src/platform/models/domain/account.ts b/libs/common/src/platform/models/domain/account.ts index 39461d19851..4295ba91331 100644 --- a/libs/common/src/platform/models/domain/account.ts +++ b/libs/common/src/platform/models/domain/account.ts @@ -1,12 +1,10 @@ import { Jsonify } from "type-fest"; -import { CollectionData } from "../../../admin-console/models/data/collection.data"; import { EncryptedOrganizationKeyData } from "../../../admin-console/models/data/encrypted-organization-key.data"; import { OrganizationData } from "../../../admin-console/models/data/organization.data"; import { PolicyData } from "../../../admin-console/models/data/policy.data"; import { ProviderData } from "../../../admin-console/models/data/provider.data"; import { Policy } from "../../../admin-console/models/domain/policy"; -import { CollectionView } from "../../../admin-console/models/view/collection.view"; import { AuthenticationStatus } from "../../../auth/enums/authentication-status"; import { EnvironmentUrls } from "../../../auth/models/domain/environment-urls"; import { ForceResetPasswordReason } from "../../../auth/models/domain/force-reset-password-reason"; @@ -17,8 +15,10 @@ import { SendData } from "../../../tools/send/models/data/send.data"; import { SendView } from "../../../tools/send/models/view/send.view"; import { DeepJsonify } from "../../../types/deep-jsonify"; import { CipherData } from "../../../vault/models/data/cipher.data"; +import { CollectionData } from "../../../vault/models/data/collection.data"; import { FolderData } from "../../../vault/models/data/folder.data"; import { CipherView } from "../../../vault/models/view/cipher.view"; +import { CollectionView } from "../../../vault/models/view/collection.view"; import { Utils } from "../../misc/utils"; import { ServerConfigData } from "../../models/data/server-config.data"; diff --git a/libs/common/src/platform/services/state-migration.service.ts b/libs/common/src/platform/services/state-migration.service.ts index c6feb0aa64f..234d1b2bff8 100644 --- a/libs/common/src/platform/services/state-migration.service.ts +++ b/libs/common/src/platform/services/state-migration.service.ts @@ -1,4 +1,3 @@ -import { CollectionData } from "../../admin-console/models/data/collection.data"; import { OrganizationData } from "../../admin-console/models/data/organization.data"; import { PolicyData } from "../../admin-console/models/data/policy.data"; import { ProviderData } from "../../admin-console/models/data/provider.data"; @@ -9,6 +8,7 @@ import { EventData } from "../../models/data/event.data"; import { GeneratedPasswordHistory } from "../../tools/generator/password"; import { SendData } from "../../tools/send/models/data/send.data"; import { CipherData } from "../../vault/models/data/cipher.data"; +import { CollectionData } from "../../vault/models/data/collection.data"; import { FolderData } from "../../vault/models/data/folder.data"; import { AbstractStorageService } from "../abstractions/storage.service"; import { StateFactory } from "../factories/state-factory"; diff --git a/libs/common/src/platform/services/state.service.ts b/libs/common/src/platform/services/state.service.ts index b701ca40238..899bff14ba4 100644 --- a/libs/common/src/platform/services/state.service.ts +++ b/libs/common/src/platform/services/state.service.ts @@ -1,13 +1,11 @@ import { BehaviorSubject, concatMap } from "rxjs"; import { Jsonify, JsonValue } from "type-fest"; -import { CollectionData } from "../../admin-console/models/data/collection.data"; import { EncryptedOrganizationKeyData } from "../../admin-console/models/data/encrypted-organization-key.data"; import { OrganizationData } from "../../admin-console/models/data/organization.data"; import { PolicyData } from "../../admin-console/models/data/policy.data"; import { ProviderData } from "../../admin-console/models/data/provider.data"; import { Policy } from "../../admin-console/models/domain/policy"; -import { CollectionView } from "../../admin-console/models/view/collection.view"; import { EnvironmentUrls } from "../../auth/models/domain/environment-urls"; import { ForceResetPasswordReason } from "../../auth/models/domain/force-reset-password-reason"; import { KdfConfig } from "../../auth/models/domain/kdf-config"; @@ -26,9 +24,11 @@ import { GeneratedPasswordHistory } from "../../tools/generator/password"; import { SendData } from "../../tools/send/models/data/send.data"; import { SendView } from "../../tools/send/models/view/send.view"; import { CipherData } from "../../vault/models/data/cipher.data"; +import { CollectionData } from "../../vault/models/data/collection.data"; import { FolderData } from "../../vault/models/data/folder.data"; import { LocalData } from "../../vault/models/data/local.data"; import { CipherView } from "../../vault/models/view/cipher.view"; +import { CollectionView } from "../../vault/models/view/collection.view"; import { AddEditCipherInfo } from "../../vault/types/add-edit-cipher-info"; import { LogService } from "../abstractions/log.service"; import { StateMigrationService } from "../abstractions/state-migration.service"; diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 4df9b2cc603..ad7c1348896 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -1,6 +1,5 @@ import { ApiService as ApiServiceAbstraction } from "../abstractions/api.service"; import { OrganizationConnectionType } from "../admin-console/enums"; -import { CollectionRequest } from "../admin-console/models/request/collection.request"; import { OrganizationSponsorshipCreateRequest } from "../admin-console/models/request/organization/organization-sponsorship-create.request"; import { OrganizationSponsorshipRedeemRequest } from "../admin-console/models/request/organization/organization-sponsorship-redeem.request"; import { OrganizationConnectionRequest } from "../admin-console/models/request/organization-connection.request"; @@ -15,10 +14,6 @@ import { ProviderUserConfirmRequest } from "../admin-console/models/request/prov import { ProviderUserInviteRequest } from "../admin-console/models/request/provider/provider-user-invite.request"; import { ProviderUserUpdateRequest } from "../admin-console/models/request/provider/provider-user-update.request"; import { SelectionReadOnlyRequest } from "../admin-console/models/request/selection-read-only.request"; -import { - CollectionAccessDetailsResponse, - CollectionResponse, -} from "../admin-console/models/response/collection.response"; import { OrganizationConnectionConfigApis, OrganizationConnectionResponse, @@ -144,9 +139,14 @@ import { CipherCreateRequest } from "../vault/models/request/cipher-create.reque import { CipherPartialRequest } from "../vault/models/request/cipher-partial.request"; import { CipherShareRequest } from "../vault/models/request/cipher-share.request"; import { CipherRequest } from "../vault/models/request/cipher.request"; +import { CollectionRequest } from "../vault/models/request/collection.request"; import { AttachmentUploadDataResponse } from "../vault/models/response/attachment-upload-data.response"; import { AttachmentResponse } from "../vault/models/response/attachment.response"; import { CipherResponse } from "../vault/models/response/cipher.response"; +import { + CollectionAccessDetailsResponse, + CollectionResponse, +} from "../vault/models/response/collection.response"; import { SyncResponse } from "../vault/models/response/sync.response"; /** diff --git a/libs/common/src/services/vaultTimeout/vaultTimeout.service.ts b/libs/common/src/services/vaultTimeout/vaultTimeout.service.ts index c46c8e52d04..169273bdfdb 100644 --- a/libs/common/src/services/vaultTimeout/vaultTimeout.service.ts +++ b/libs/common/src/services/vaultTimeout/vaultTimeout.service.ts @@ -3,7 +3,6 @@ import { firstValueFrom } from "rxjs"; import { SearchService } from "../../abstractions/search.service"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../../abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService } from "../../abstractions/vaultTimeout/vaultTimeoutSettings.service"; -import { CollectionService } from "../../admin-console/abstractions/collection.service"; import { AuthService } from "../../auth/abstractions/auth.service"; import { KeyConnectorService } from "../../auth/abstractions/key-connector.service"; import { AuthenticationStatus } from "../../auth/enums/authentication-status"; @@ -13,6 +12,7 @@ import { MessagingService } from "../../platform/abstractions/messaging.service" import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; import { StateService } from "../../platform/abstractions/state.service"; import { CipherService } from "../../vault/abstractions/cipher.service"; +import { CollectionService } from "../../vault/abstractions/collection.service"; import { FolderService } from "../../vault/abstractions/folder/folder.service.abstraction"; export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { diff --git a/libs/common/src/admin-console/abstractions/collection.service.ts b/libs/common/src/vault/abstractions/collection.service.ts similarity index 100% rename from libs/common/src/admin-console/abstractions/collection.service.ts rename to libs/common/src/vault/abstractions/collection.service.ts diff --git a/libs/common/src/admin-console/models/data/collection.data.ts b/libs/common/src/vault/models/data/collection.data.ts similarity index 100% rename from libs/common/src/admin-console/models/data/collection.data.ts rename to libs/common/src/vault/models/data/collection.data.ts diff --git a/libs/common/src/admin-console/models/domain/collection.spec.ts b/libs/common/src/vault/models/domain/collection.spec.ts similarity index 100% rename from libs/common/src/admin-console/models/domain/collection.spec.ts rename to libs/common/src/vault/models/domain/collection.spec.ts diff --git a/libs/common/src/admin-console/models/domain/collection.ts b/libs/common/src/vault/models/domain/collection.ts similarity index 100% rename from libs/common/src/admin-console/models/domain/collection.ts rename to libs/common/src/vault/models/domain/collection.ts diff --git a/libs/common/src/admin-console/models/request/collection-with-id.request.ts b/libs/common/src/vault/models/request/collection-with-id.request.ts similarity index 80% rename from libs/common/src/admin-console/models/request/collection-with-id.request.ts rename to libs/common/src/vault/models/request/collection-with-id.request.ts index ae48395a49d..4ff050b3919 100644 --- a/libs/common/src/admin-console/models/request/collection-with-id.request.ts +++ b/libs/common/src/vault/models/request/collection-with-id.request.ts @@ -1,5 +1,6 @@ import { Collection } from "../domain/collection"; -import { CollectionRequest } from "../request/collection.request"; + +import { CollectionRequest } from "./collection.request"; export class CollectionWithIdRequest extends CollectionRequest { id: string; diff --git a/libs/common/src/admin-console/models/request/collection.request.ts b/libs/common/src/vault/models/request/collection.request.ts similarity index 79% rename from libs/common/src/admin-console/models/request/collection.request.ts rename to libs/common/src/vault/models/request/collection.request.ts index d28a7d06fe6..173bb3c18c3 100644 --- a/libs/common/src/admin-console/models/request/collection.request.ts +++ b/libs/common/src/vault/models/request/collection.request.ts @@ -1,7 +1,6 @@ +import { SelectionReadOnlyRequest } from "../../../admin-console/models/request/selection-read-only.request"; import { Collection } from "../domain/collection"; -import { SelectionReadOnlyRequest } from "./selection-read-only.request"; - export class CollectionRequest { name: string; externalId: string; diff --git a/libs/common/src/admin-console/models/response/collection.response.ts b/libs/common/src/vault/models/response/collection.response.ts similarity index 92% rename from libs/common/src/admin-console/models/response/collection.response.ts rename to libs/common/src/vault/models/response/collection.response.ts index 5efc3b90ae1..ad01da2865d 100644 --- a/libs/common/src/admin-console/models/response/collection.response.ts +++ b/libs/common/src/vault/models/response/collection.response.ts @@ -1,7 +1,6 @@ +import { SelectionReadOnlyResponse } from "../../../admin-console/models/response/selection-read-only.response"; import { BaseResponse } from "../../../models/response/base.response"; -import { SelectionReadOnlyResponse } from "./selection-read-only.response"; - export class CollectionResponse extends BaseResponse { id: string; organizationId: string; diff --git a/libs/common/src/vault/models/response/sync.response.ts b/libs/common/src/vault/models/response/sync.response.ts index d042c4b5a76..42778a8cef9 100644 --- a/libs/common/src/vault/models/response/sync.response.ts +++ b/libs/common/src/vault/models/response/sync.response.ts @@ -1,4 +1,3 @@ -import { CollectionDetailsResponse } from "../../../admin-console/models/response/collection.response"; import { PolicyResponse } from "../../../admin-console/models/response/policy.response"; import { BaseResponse } from "../../../models/response/base.response"; import { DomainsResponse } from "../../../models/response/domains.response"; @@ -6,6 +5,7 @@ import { ProfileResponse } from "../../../models/response/profile.response"; import { SendResponse } from "../../../tools/send/models/response/send.response"; import { CipherResponse } from "./cipher.response"; +import { CollectionDetailsResponse } from "./collection.response"; import { FolderResponse } from "./folder.response"; export class SyncResponse extends BaseResponse { diff --git a/libs/common/src/admin-console/models/view/collection.view.ts b/libs/common/src/vault/models/view/collection.view.ts similarity index 100% rename from libs/common/src/admin-console/models/view/collection.view.ts rename to libs/common/src/vault/models/view/collection.view.ts diff --git a/libs/common/src/admin-console/services/collection.service.ts b/libs/common/src/vault/services/collection.service.ts similarity index 99% rename from libs/common/src/admin-console/services/collection.service.ts rename to libs/common/src/vault/services/collection.service.ts index 3c90fc50996..c0148bddd75 100644 --- a/libs/common/src/admin-console/services/collection.service.ts +++ b/libs/common/src/vault/services/collection.service.ts @@ -4,7 +4,7 @@ import { CryptoService } from "../../platform/abstractions/crypto.service"; import { I18nService } from "../../platform/abstractions/i18n.service"; import { StateService } from "../../platform/abstractions/state.service"; import { Utils } from "../../platform/misc/utils"; -import { CollectionService as CollectionServiceAbstraction } from "../abstractions/collection.service"; +import { CollectionService as CollectionServiceAbstraction } from "../../vault/abstractions/collection.service"; import { CollectionData } from "../models/data/collection.data"; import { Collection } from "../models/domain/collection"; import { CollectionView } from "../models/view/collection.view"; diff --git a/libs/common/src/vault/services/sync/sync.service.ts b/libs/common/src/vault/services/sync/sync.service.ts index ae4f50a39e7..a919f38020c 100644 --- a/libs/common/src/vault/services/sync/sync.service.ts +++ b/libs/common/src/vault/services/sync/sync.service.ts @@ -1,14 +1,11 @@ import { ApiService } from "../../../abstractions/api.service"; import { SettingsService } from "../../../abstractions/settings.service"; -import { CollectionService } from "../../../admin-console/abstractions/collection.service"; import { InternalOrganizationService } from "../../../admin-console/abstractions/organization/organization.service.abstraction"; import { InternalPolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction"; import { ProviderService } from "../../../admin-console/abstractions/provider.service"; -import { CollectionData } from "../../../admin-console/models/data/collection.data"; import { OrganizationData } from "../../../admin-console/models/data/organization.data"; import { PolicyData } from "../../../admin-console/models/data/policy.data"; import { ProviderData } from "../../../admin-console/models/data/provider.data"; -import { CollectionDetailsResponse } from "../../../admin-console/models/response/collection.response"; import { PolicyResponse } from "../../../admin-console/models/response/policy.response"; import { KeyConnectorService } from "../../../auth/abstractions/key-connector.service"; import { ForceResetPasswordReason } from "../../../auth/models/domain/force-reset-password-reason"; @@ -36,6 +33,9 @@ import { CipherData } from "../../../vault/models/data/cipher.data"; import { FolderData } from "../../../vault/models/data/folder.data"; import { CipherResponse } from "../../../vault/models/response/cipher.response"; import { FolderResponse } from "../../../vault/models/response/folder.response"; +import { CollectionService } from "../../abstractions/collection.service"; +import { CollectionData } from "../../models/data/collection.data"; +import { CollectionDetailsResponse } from "../../models/response/collection.response"; export class SyncService implements SyncServiceAbstraction { syncInProgress = false; diff --git a/libs/exporter/src/vault-export/services/vault-export.service.ts b/libs/exporter/src/vault-export/services/vault-export.service.ts index 009e95e7a57..06a8b45f58a 100644 --- a/libs/exporter/src/vault-export/services/vault-export.service.ts +++ b/libs/exporter/src/vault-export/services/vault-export.service.ts @@ -1,10 +1,6 @@ import * as papa from "papaparse"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { CollectionData } from "@bitwarden/common/admin-console/models/data/collection.data"; -import { Collection } from "@bitwarden/common/admin-console/models/domain/collection"; -import { CollectionDetailsResponse } from "@bitwarden/common/admin-console/models/response/collection.response"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; import { KdfType } from "@bitwarden/common/enums"; import { @@ -20,9 +16,13 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data"; +import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; +import { Collection } from "@bitwarden/common/vault/models/domain/collection"; import { Folder } from "@bitwarden/common/vault/models/domain/folder"; +import { CollectionDetailsResponse } from "@bitwarden/common/vault/models/response/collection.response"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { ExportHelper } from "../../export-helper"; diff --git a/libs/importer/src/importers/base-importer.ts b/libs/importer/src/importers/base-importer.ts index fed35a391a1..7c3110ad232 100644 --- a/libs/importer/src/importers/base-importer.ts +++ b/libs/importer/src/importers/base-importer.ts @@ -1,12 +1,12 @@ import * as papa from "papaparse"; -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { FieldType, SecureNoteType } from "@bitwarden/common/enums"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; diff --git a/libs/importer/src/importers/bitwarden/bitwarden-csv-importer.ts b/libs/importer/src/importers/bitwarden/bitwarden-csv-importer.ts index 45bfc0f1275..9024f5fff63 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-csv-importer.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-csv-importer.ts @@ -1,8 +1,8 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { FieldType, SecureNoteType } from "@bitwarden/common/enums"; 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 { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.view"; diff --git a/libs/importer/src/importers/padlock-csv-importer.ts b/libs/importer/src/importers/padlock-csv-importer.ts index 7b81041f9f1..1d09fcdaacb 100644 --- a/libs/importer/src/importers/padlock-csv-importer.ts +++ b/libs/importer/src/importers/padlock-csv-importer.ts @@ -1,4 +1,4 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { ImportResult } from "../models/import-result"; diff --git a/libs/importer/src/importers/passpack-csv-importer.ts b/libs/importer/src/importers/passpack-csv-importer.ts index f08de898eb6..43c8b3dba9e 100644 --- a/libs/importer/src/importers/passpack-csv-importer.ts +++ b/libs/importer/src/importers/passpack-csv-importer.ts @@ -1,4 +1,4 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { ImportResult } from "../models/import-result"; diff --git a/libs/importer/src/models/import-result.ts b/libs/importer/src/models/import-result.ts index d6d6726b648..cc4c487d3d8 100644 --- a/libs/importer/src/models/import-result.ts +++ b/libs/importer/src/models/import-result.ts @@ -1,5 +1,5 @@ -import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; export class ImportResult { diff --git a/libs/importer/src/services/import.service.spec.ts b/libs/importer/src/services/import.service.spec.ts index 629df464002..e748c118443 100644 --- a/libs/importer/src/services/import.service.spec.ts +++ b/libs/importer/src/services/import.service.spec.ts @@ -1,10 +1,10 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { BitwardenPasswordProtectedImporter } from "../importers/bitwarden/bitwarden-password-protected-importer"; diff --git a/libs/importer/src/services/import.service.ts b/libs/importer/src/services/import.service.ts index 100e5202ab6..8cfe40248cf 100644 --- a/libs/importer/src/services/import.service.ts +++ b/libs/importer/src/services/import.service.ts @@ -1,5 +1,3 @@ -import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; -import { CollectionWithIdRequest } from "@bitwarden/common/admin-console/models/request/collection-with-id.request"; import { ImportCiphersRequest } from "@bitwarden/common/models/request/import-ciphers.request"; import { ImportOrganizationCiphersRequest } from "@bitwarden/common/models/request/import-organization-ciphers.request"; import { KvpRequest } from "@bitwarden/common/models/request/kvp.request"; @@ -8,9 +6,11 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; 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 { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherRequest } from "@bitwarden/common/vault/models/request/cipher.request"; +import { CollectionWithIdRequest } from "@bitwarden/common/vault/models/request/collection-with-id.request"; import { FolderWithIdRequest } from "@bitwarden/common/vault/models/request/folder-with-id.request"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; From a7f9984ddd14f60da7ffa9ee75acb1c331c1b144 Mon Sep 17 00:00:00 2001 From: mimartin12 <77340197+mimartin12@users.noreply.github.com> Date: Wed, 14 Jun 2023 08:16:42 -0600 Subject: [PATCH 17/29] Update build-web.yml (#5606) --- .github/workflows/build-web.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index ee8d689c219..05c6b0f8b6e 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -84,7 +84,7 @@ jobs: npm_command: "build:bit:poc" - name: "ee" npm_command: "build:bit:ee" - - name: "eudevtest" + - name: "cloud-eudevtest" npm_command: "build:bit:eudevtest" steps: From ed0490730076298590421473f95b5391ff51d011 Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Wed, 14 Jun 2023 13:09:56 -0700 Subject: [PATCH 18/29] [PM-2049] Update entity events dialog (#5417) * [AC-1145] Update entity-events.component.ts to a CL dialog - Add EntityEventsDialogParams - Add static helper method to open the dialog with the dialog service - Update existing usages of the entity-events.component.ts * [AC-1145] Update entity-events.component.ts to use CL components and form actions - Use bit-table and TableDataSource - Update to reactive form for date filter - Make dialog component standalone - Use bitAction in-place of component promises - Remove redundant try/catch that is now handled by bitAction and bitSubmit - Add new try/catch on first load to catch any errors during initial dialog open * [PM-2049] Make dataSource and filterFormGroup protected * [PM-2049] Remove bit-form-field container Remove the bit-form-field tags that wrapped the date inputs to avoid additional styling that is not applicable to inline form elements. Add back the missing `-` that was removed by mistake. * [PM-2049] Remove entity events dialog component selector --- .../manage/entity-events.component.html | 179 +++++++--------- .../manage/entity-events.component.ts | 191 +++++++++++------- .../members/people.component.html | 1 - .../organizations/members/people.component.ts | 20 +- .../src/app/shared/loose-components.module.ts | 3 - .../app/vault/org-vault/vault.component.html | 1 - .../app/vault/org-vault/vault.component.ts | 18 +- .../providers/manage/people.component.html | 1 - .../providers/manage/people.component.ts | 18 +- 9 files changed, 217 insertions(+), 215 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/manage/entity-events.component.html b/apps/web/src/app/admin-console/organizations/manage/entity-events.component.html index 85c9d474920..8d8cfad34e9 100644 --- a/apps/web/src/app/admin-console/organizations/manage/entity-events.component.html +++ b/apps/web/src/app/admin-console/organizations/manage/entity-events.component.html @@ -1,118 +1,89 @@ - 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 8048ade1c70..7b6b926e494 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.ts +++ b/apps/web/src/app/vault/org-vault/vault.component.ts @@ -56,7 +56,7 @@ import { CollectionView } from "@bitwarden/common/vault/models/view/collection.v import { Icons } from "@bitwarden/components"; import { GroupService, GroupView } from "../../admin-console/organizations/core"; -import { EntityEventsComponent } from "../../admin-console/organizations/manage/entity-events.component"; +import { openEntityEventsDialog } from "../../admin-console/organizations/manage/entity-events.component"; import { VaultFilterService } from "../../vault/individual-vault/vault-filter/services/abstractions/vault-filter.service"; import { VaultFilter } from "../../vault/individual-vault/vault-filter/shared/models/vault-filter.model"; import { @@ -109,8 +109,6 @@ export class VaultComponent implements OnInit, OnDestroy { cipherAddEditModalRef: ViewContainerRef; @ViewChild("collectionsModal", { read: ViewContainerRef, static: true }) collectionsModalRef: ViewContainerRef; - @ViewChild("eventsTemplate", { read: ViewContainerRef, static: true }) - eventsModalRef: ViewContainerRef; trashCleanupWarning: string = null; activeFilter: VaultFilter = new VaultFilter(); @@ -885,12 +883,14 @@ export class VaultComponent implements OnInit, OnDestroy { } async viewEvents(cipher: CipherView) { - await this.modalService.openViewRef(EntityEventsComponent, this.eventsModalRef, (comp) => { - comp.name = cipher.name; - comp.organizationId = this.organization.id; - comp.entityId = cipher.id; - comp.showUser = true; - comp.entity = "cipher"; + await openEntityEventsDialog(this.dialogService, { + data: { + name: cipher.name, + organizationId: this.organization.id, + entityId: cipher.id, + showUser: true, + entity: "cipher", + }, }); } diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html index 00bf5eda261..152253fe4d1 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.html @@ -209,7 +209,6 @@ - diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts index 7c787951d4d..304ab346f33 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/people.component.ts @@ -21,7 +21,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { EntityEventsComponent } from "@bitwarden/web-vault/app/admin-console/organizations/manage/entity-events.component"; +import { openEntityEventsDialog } from "@bitwarden/web-vault/app/admin-console/organizations/manage/entity-events.component"; import { BulkStatusComponent } from "@bitwarden/web-vault/app/admin-console/organizations/members/components/bulk/bulk-status.component"; import { BasePeopleComponent } from "@bitwarden/web-vault/app/common/base.people.component"; @@ -41,8 +41,6 @@ export class PeopleComponent @ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef; @ViewChild("groupsTemplate", { read: ViewContainerRef, static: true }) groupsModalRef: ViewContainerRef; - @ViewChild("eventsTemplate", { read: ViewContainerRef, static: true }) - eventsModalRef: ViewContainerRef; @ViewChild("bulkStatusTemplate", { read: ViewContainerRef, static: true }) bulkStatusModalRef: ViewContainerRef; @ViewChild("bulkConfirmTemplate", { read: ViewContainerRef, static: true }) @@ -167,12 +165,14 @@ export class PeopleComponent } async events(user: ProviderUserUserDetailsResponse) { - await this.modalService.openViewRef(EntityEventsComponent, this.eventsModalRef, (comp) => { - comp.name = this.userNamePipe.transform(user); - comp.providerId = this.providerId; - comp.entityId = user.id; - comp.showUser = false; - comp.entity = "user"; + await openEntityEventsDialog(this.dialogService, { + data: { + name: this.userNamePipe.transform(user), + providerId: this.providerId, + entityId: user.id, + showUser: false, + entity: "user", + }, }); } From 9ed59c6fa929d71291bdd3d954e6b6f3d87080f7 Mon Sep 17 00:00:00 2001 From: Daniel Chateau Date: Wed, 14 Jun 2023 16:59:29 -0400 Subject: [PATCH 19/29] Update request headers sent to AnonAddy API. (#5565) --- .../generator/username/email-forwarders/anon-addy-forwarder.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/common/src/tools/generator/username/email-forwarders/anon-addy-forwarder.ts b/libs/common/src/tools/generator/username/email-forwarders/anon-addy-forwarder.ts index 6b4bc423148..b20f22ecf82 100644 --- a/libs/common/src/tools/generator/username/email-forwarders/anon-addy-forwarder.ts +++ b/libs/common/src/tools/generator/username/email-forwarders/anon-addy-forwarder.ts @@ -18,6 +18,7 @@ export class AnonAddyForwarder implements Forwarder { headers: new Headers({ Authorization: "Bearer " + options.apiKey, "Content-Type": "application/json", + "X-Requested-With": "XMLHttpRequest", }), }; const url = "https://app.anonaddy.com/api/v1/aliases"; From 44f74483d96bddd2e00e374beedea42a12dfc19a Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Thu, 15 Jun 2023 12:43:36 -0400 Subject: [PATCH 20/29] Change ownership of autofill from vault to client integrations (#5619) --- .github/CODEOWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a954236cdf7..d0526b1a79e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -31,7 +31,6 @@ libs/exporter @bitwarden/team-tools-dev libs/importer @bitwarden/team-tools-dev ## Vault team files ## -apps/browser/src/autofill @bitwarden/team-vault-dev apps/browser/src/vault @bitwarden/team-vault-dev apps/cli/src/vault @bitwarden/team-vault-dev apps/desktop/src/vault @bitwarden/team-vault-dev @@ -69,6 +68,9 @@ apps/web/src/app/core @bitwarden/team-platform-dev apps/web/src/app/shared @bitwarden/team-platform-dev apps/web/src/translation-constants.ts @bitwarden/team-platform-dev +## Client Integrations team files ## +apps/browser/src/autofill @bitwarden/team-client-integrations-dev + ## Component Library ## libs/components @bitwarden/team-platform-dev From bec51c95f9b1e7a189ab8ae7e4a8d752bd590ddc Mon Sep 17 00:00:00 2001 From: Vince Grassia <593223+vgrassia@users.noreply.github.com> Date: Thu, 15 Jun 2023 12:54:39 -0400 Subject: [PATCH 21/29] Add EU Prod environment to Web build (#5620) --- .github/workflows/build-web.yml | 6 ++---- .github/workflows/deploy-prod-web.yml | 13 +++++++++++++ apps/web/config/euprd.json | 11 +++++++++++ apps/web/config/poc.json | 11 ----------- apps/web/package.json | 2 +- 5 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/deploy-prod-web.yml create mode 100644 apps/web/config/euprd.json delete mode 100644 apps/web/config/poc.json diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 05c6b0f8b6e..fd4a700131f 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -80,12 +80,10 @@ jobs: npm_command: "dist:bit:selfhost" - name: "cloud-QA" npm_command: "build:bit:qa" - - name: "cloud-POC2" - npm_command: "build:bit:poc" - name: "ee" npm_command: "build:bit:ee" - - name: "cloud-eudevtest" - npm_command: "build:bit:eudevtest" + - name: "cloud-euprd" + npm_command: "build:bit:euprd" steps: - name: Checkout repo diff --git a/.github/workflows/deploy-prod-web.yml b/.github/workflows/deploy-prod-web.yml new file mode 100644 index 00000000000..144b23e390b --- /dev/null +++ b/.github/workflows/deploy-prod-web.yml @@ -0,0 +1,13 @@ +--- +name: Deploy Web - EU Prod - STUB + +on: + workflow_dispatch: + +jobs: + stub-job: + name: Stub Job + runs-on: ubuntu-22.04 + steps: + - name: Stub Step + run: exit 0 diff --git a/apps/web/config/euprd.json b/apps/web/config/euprd.json new file mode 100644 index 00000000000..3813074b7cf --- /dev/null +++ b/apps/web/config/euprd.json @@ -0,0 +1,11 @@ +{ + "urls": { + "icons": "https://icons.bitwarden.net", + "notifications": "https://notifications.bitwarden.net", + "scim": "https://scim.bitwarden.net" + }, + "flags": { + "secretsManager": true, + "showPasswordless": true + } +} diff --git a/apps/web/config/poc.json b/apps/web/config/poc.json deleted file mode 100644 index 0d2f4d2ec46..00000000000 --- a/apps/web/config/poc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "urls": { - "icons": "https://icons.poc2.bitwarden.pw", - "notifications": "https://notifications.poc2.bitwarden.pw", - "scim": "https://scim.poc2.bitwarden.pw" - }, - "flags": { - "secretsManager": true, - "showPasswordless": true - } -} diff --git a/apps/web/package.json b/apps/web/package.json index c50b4df2a85..1aed639fdcc 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,7 +10,7 @@ "build:bit:dev:analyze": "cross-env LOGGING=false webpack -c ../../bitwarden_license/bit-web/webpack.config.js --profile --json > stats.json && npx webpack-bundle-analyzer stats.json build/", "build:bit:dev:watch": "cross-env ENV=development npm run build:bit:watch", "build:bit:qa": "cross-env NODE_ENV=production ENV=qa npm run build:bit", - "build:bit:poc": "cross-env NODE_ENV=production ENV=poc npm run build:bit", + "build:bit:euprd": "cross-env NODE_ENV=production ENV=euprd npm run build:bit", "build:bit:eudevtest": "cross-env NODE_ENV=production ENV=eudevtest npm run build:bit", "build:bit:cloud": "cross-env NODE_ENV=production ENV=cloud npm run build:bit", "build:oss:selfhost:watch": "cross-env ENV=selfhosted npm run build:oss:watch", From 0afbd90a2d7018fe58799cf82965196fd8d20836 Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Thu, 15 Jun 2023 14:53:21 -0700 Subject: [PATCH 22/29] [AC-1192] Create new device approvals component for TDE (#5548) * Add feature flag route guard and tests * Add additional test for not showing error toast * Strengthen error toast test with message check * Cleanup leaking test state in platformService mock * Negate if statement to reduce nesting * Update return type to CanActivateFn * Use null check instead of undefined * Introduce interface to support different feature flag types - Switch to observable pattern to access serverConfig$ subject - Add catchError handler to allow navigation in case of unexpected exception - Add additional tests * Add additional test for missing feature flag * Remove subscription to the serverConfig observable Introduce type checking logic to determine the appropriately typed flag getter to use in configService * [AC-1192] Create initial device approvals component and route * [AC-1192] Introduce appIfFeature directive for conditionally rendering content based on feature flags * [AC-1192] Add DeviceApprovals link in Settings navigation * Remove align middle from bitCell directive The bitRow directive supports alignment for the entire row and should be used instead * [AC-1192] Add initial device approvals page template * [AC-1192] Introduce fingerprint pipe * [AC-1192] Create core organization module in bitwarden_license directory * [AC-1192] Add support for new Devices icon to no items component - Add new Devices svg - Make icon property of bit-no-items an Input property * [AC-1192] Introduce organization-auth-request.service.ts with related views/responses * [AC-1192] Display pending requests on device approvals page - Add support for loading spinner and no items component * [AC-1192] Add method to bulk deny auth requests * [AC-1192] Add functionality to deny requests from device approvals page * [AC-1192] Add organizationUserId to pending-auth-request.view.ts * [AC-1192] Add approvePendingRequest method to organization-auth-request.service.ts * [AC-1192] Add logic to approve a device approval request * [AC-1192] Change bitMenuItem directive into a component and implement ButtonLikeAbstraction Update the bitMenuItem to be a component and implement the ButtonLikeAbstraction to support the bitAction directive. * [AC-1192] Update menu items to use bitActions * [AC-1192] Update device approvals description copy * [AC-1192] Revert changes to bitMenuItem directive * [AC-1192] Rework menus to use click handlers - Wrap async actions to catch/log any exceptions, set an in-progress state, and refresh after completion - Show a loading spinner in the header when an action is in progress - Disable all menu items when an action is in progress * [AC-1192] Move Devices icon into admin-console web directory * [AC-1192] bit-no-items formatting * [AC-1192] Update appIfFeature directive to hide content on error * [AC-1192] Remove deprecated providedIn for OrganizationAuthRequestService * [AC-1192] Rename key to encryptedUserKey to be more descriptive * [AC-1192] Cleanup loading/spinner logic on data refresh * [AC-1192] Set middle as the default bitRow.alignContent * [AC-1192] Change default alignRowContent for table story * [AC-1192] Rename userId to fingerprintMaterial to be more general The fingerprint material is not always the userId so this name is more general * [AC-1192] Remove redundant alignContent attribute * [AC-1192] Move fingerprint pipe to platform --- .../src/app/admin-console/icons/devices.ts | 17 ++ apps/web/src/app/admin-console/icons/index.ts | 1 + .../settings/settings.component.html | 10 + .../settings/settings.component.ts | 2 + apps/web/src/locales/en/messages.json | 36 ++++ .../core/core-organization.module.ts | 8 + .../admin-console/organizations/core/index.ts | 1 + .../admin-auth-request-update.request.ts | 8 + .../bulk-deny-auth-requests.request.ts | 6 + .../core/services/auth-requests/index.ts | 2 + .../organization-auth-request.service.ts | 54 ++++++ ...ding-organization-auth-request.response.ts | 26 +++ .../core/views/pending-auth-request.view.ts | 23 +++ .../device-approvals.component.html | 100 ++++++++++ .../device-approvals.component.ts | 174 ++++++++++++++++++ .../organizations-routing.module.ts | 15 ++ .../organizations/organizations.module.ts | 6 +- .../directives/if-feature.directive.spec.ts | 137 ++++++++++++++ .../src/directives/if-feature.directive.ts | 67 +++++++ libs/angular/src/jslib.module.ts | 16 +- .../src/platform/pipes/fingerprint.pipe.ts | 32 ++++ .../src/no-items/no-items.component.ts | 4 +- libs/components/src/table/cell.directive.ts | 4 +- libs/components/src/table/row.directive.ts | 2 +- libs/components/src/table/table.stories.ts | 4 +- 25 files changed, 746 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/app/admin-console/icons/devices.ts create mode 100644 apps/web/src/app/admin-console/icons/index.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/admin-auth-request-update.request.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/bulk-deny-auth-requests.request.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/index.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/pending-organization-auth-request.response.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.html create mode 100644 bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts create mode 100644 libs/angular/src/directives/if-feature.directive.spec.ts create mode 100644 libs/angular/src/directives/if-feature.directive.ts create mode 100644 libs/angular/src/platform/pipes/fingerprint.pipe.ts diff --git a/apps/web/src/app/admin-console/icons/devices.ts b/apps/web/src/app/admin-console/icons/devices.ts new file mode 100644 index 00000000000..348c836c4b7 --- /dev/null +++ b/apps/web/src/app/admin-console/icons/devices.ts @@ -0,0 +1,17 @@ +import { svgIcon } from "@bitwarden/components"; + +export const Devices = svgIcon` + + + + + + + + + + + + + +`; diff --git a/apps/web/src/app/admin-console/icons/index.ts b/apps/web/src/app/admin-console/icons/index.ts new file mode 100644 index 00000000000..e0c2c124af1 --- /dev/null +++ b/apps/web/src/app/admin-console/icons/index.ts @@ -0,0 +1 @@ +export * from "./devices"; diff --git a/apps/web/src/app/admin-console/organizations/settings/settings.component.html b/apps/web/src/app/admin-console/organizations/settings/settings.component.html index 146a7203430..bc2b2e54a0c 100644 --- a/apps/web/src/app/admin-console/organizations/settings/settings.component.html +++ b/apps/web/src/app/admin-console/organizations/settings/settings.component.html @@ -60,6 +60,16 @@ > {{ "singleSignOn" | i18n }} + + + {{ "deviceApprovals" | i18n }} + + ; + FeatureFlag = FeatureFlag; constructor(private route: ActivatedRoute, private organizationService: OrganizationService) {} diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 9224bfe8d11..b9124dca169 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -6844,5 +6844,41 @@ }, "updatedTempPassword": { "message": "User updated a password issued through account recovery." + }, + "deviceApprovals": { + "message": "Device approvals" + }, + "deviceApprovalsDesc": { + "message": "Approve login requests below to allow the requesting member to finish logging in. Unapproved requests expire after 1 week. Verify the member’s information before approving." + }, + "deviceInfo": { + "message": "Device info" + }, + "time": { + "message": "Time" + }, + "denyAllRequests": { + "message": "Deny all requests" + }, + "denyRequest": { + "message": "Deny request" + }, + "approveRequest": { + "message": "Approve request" + }, + "noDeviceRequests": { + "message": "No device requests" + }, + "noDeviceRequestsDesc": { + "message": "Member device approval requests will appear here" + }, + "loginRequestDenied": { + "message": "Login request denied" + }, + "allLoginRequestsDenied": { + "message": "All login requests denied" + }, + "loginRequestApproved": { + "message": "Login request approved" } } diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts new file mode 100644 index 00000000000..bba3bfce930 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts @@ -0,0 +1,8 @@ +import { NgModule } from "@angular/core"; + +import { OrganizationAuthRequestService } from "./services/auth-requests"; + +@NgModule({ + providers: [OrganizationAuthRequestService], +}) +export class CoreOrganizationModule {} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts new file mode 100644 index 00000000000..4d758be8c6b --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts @@ -0,0 +1 @@ +export * from "./core-organization.module"; diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/admin-auth-request-update.request.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/admin-auth-request-update.request.ts new file mode 100644 index 00000000000..a190d5809ce --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/admin-auth-request-update.request.ts @@ -0,0 +1,8 @@ +export class AdminAuthRequestUpdateRequest { + /** + * + * @param requestApproved - Whether the request was approved/denied. If true, the key must be provided. + * @param encryptedUserKey The user's symmetric key that has been encrypted with a device public key if the request was approved. + */ + constructor(public requestApproved: boolean, public encryptedUserKey?: string) {} +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/bulk-deny-auth-requests.request.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/bulk-deny-auth-requests.request.ts new file mode 100644 index 00000000000..09054c4b589 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/bulk-deny-auth-requests.request.ts @@ -0,0 +1,6 @@ +export class BulkDenyAuthRequestsRequest { + private ids: string[]; + constructor(authRequestIds: string[]) { + this.ids = authRequestIds; + } +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/index.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/index.ts new file mode 100644 index 00000000000..d8c4bacd697 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/index.ts @@ -0,0 +1,2 @@ +export * from "./pending-organization-auth-request.response"; +export * from "./organization-auth-request.service"; diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts new file mode 100644 index 00000000000..77e4cba0333 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts @@ -0,0 +1,54 @@ +import { Injectable } from "@angular/core"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { ListResponse } from "@bitwarden/common/models/response/list.response"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; + +import { PendingAuthRequestView } from "../../views/pending-auth-request.view"; + +import { AdminAuthRequestUpdateRequest } from "./admin-auth-request-update.request"; +import { BulkDenyAuthRequestsRequest } from "./bulk-deny-auth-requests.request"; +import { PendingOrganizationAuthRequestResponse } from "./pending-organization-auth-request.response"; + +@Injectable() +export class OrganizationAuthRequestService { + constructor(private apiService: ApiService) {} + + async listPendingRequests(organizationId: string): Promise { + const r = await this.apiService.send( + "GET", + `/organizations/${organizationId}/auth-requests`, + null, + true, + true + ); + + const listResponse = new ListResponse(r, PendingOrganizationAuthRequestResponse); + + return listResponse.data.map((ar) => PendingAuthRequestView.fromResponse(ar)); + } + + async denyPendingRequests(organizationId: string, ...requestIds: string[]): Promise { + await this.apiService.send( + "POST", + `/organizations/${organizationId}/auth-requests/deny`, + new BulkDenyAuthRequestsRequest(requestIds), + true, + false + ); + } + + async approvePendingRequest( + organizationId: string, + requestId: string, + encryptedKey: EncString + ): Promise { + await this.apiService.send( + "POST", + `/organizations/${organizationId}/auth-requests/${requestId}`, + new AdminAuthRequestUpdateRequest(true, encryptedKey.encryptedString), + true, + false + ); + } +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/pending-organization-auth-request.response.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/pending-organization-auth-request.response.ts new file mode 100644 index 00000000000..b4854eea4aa --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/pending-organization-auth-request.response.ts @@ -0,0 +1,26 @@ +import { BaseResponse } from "@bitwarden/common/models/response/base.response"; + +export class PendingOrganizationAuthRequestResponse extends BaseResponse { + id: string; + userId: string; + organizationUserId: string; + email: string; + publicKey: string; + requestDeviceIdentifier: string; + requestDeviceType: string; + requestIpAddress: string; + creationDate: string; + + constructor(response: any) { + super(response); + this.id = this.getResponseProperty("Id"); + this.userId = this.getResponseProperty("UserId"); + this.organizationUserId = this.getResponseProperty("OrganizationUserId"); + this.email = this.getResponseProperty("Email"); + this.publicKey = this.getResponseProperty("PublicKey"); + this.requestDeviceIdentifier = this.getResponseProperty("RequestDeviceIdentifier"); + this.requestDeviceType = this.getResponseProperty("RequestDeviceType"); + this.requestIpAddress = this.getResponseProperty("RequestIpAddress"); + this.creationDate = this.getResponseProperty("CreationDate"); + } +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts new file mode 100644 index 00000000000..8f3415a236b --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts @@ -0,0 +1,23 @@ +import { View } from "@bitwarden/common/models/view/view"; + +import { PendingOrganizationAuthRequestResponse } from "../services/auth-requests"; + +export class PendingAuthRequestView implements View { + id: string; + userId: string; + organizationUserId: string; + email: string; + publicKey: string; + requestDeviceIdentifier: string; + requestDeviceType: string; + requestIpAddress: string; + creationDate: Date; + + static fromResponse(response: PendingOrganizationAuthRequestResponse): PendingAuthRequestView { + const view = Object.assign(new PendingAuthRequestView(), response) as PendingAuthRequestView; + + view.creationDate = new Date(response.creationDate); + + return view; + } +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.html b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.html new file mode 100644 index 00000000000..4758cc47ce0 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.html @@ -0,0 +1,100 @@ +

+ {{ "deviceApprovals" | i18n }} + + {{ "loading" | i18n }} +

+

+ {{ "deviceApprovalsDesc" | i18n }} +

+ + + + + {{ "member" | i18n }} + {{ "deviceInfo" | i18n }} + {{ "time" | i18n }} + + + + + + + + + + + +
{{ r.email }}
+ {{ r.publicKey | fingerprint : r.email | async }} + + +
{{ r.requestDeviceType }}
+
{{ r.requestIpAddress }}
+ + + {{ r.creationDate | date : "medium" }} + + + + + + + + + +
+
+ + + {{ "noDeviceRequests" | i18n }} + {{ "noDeviceRequestsDesc" | i18n }} + diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts new file mode 100644 index 00000000000..6325a72f80d --- /dev/null +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts @@ -0,0 +1,174 @@ +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { BehaviorSubject, Subject, switchMap, takeUntil, tap } from "rxjs"; + +import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service"; +import { OrganizationUserResetPasswordDetailsResponse } from "@bitwarden/common/abstractions/organization-user/responses"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +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 { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { TableDataSource } from "@bitwarden/components"; +import { Devices } from "@bitwarden/web-vault/app/admin-console/icons"; + +import { OrganizationAuthRequestService } from "../../core/services/auth-requests"; +import { PendingAuthRequestView } from "../../core/views/pending-auth-request.view"; + +@Component({ + selector: "app-org-device-approvals", + templateUrl: "./device-approvals.component.html", +}) +export class DeviceApprovalsComponent implements OnInit, OnDestroy { + tableDataSource = new TableDataSource(); + organizationId: string; + loading = true; + actionInProgress = false; + + protected readonly Devices = Devices; + + private destroy$ = new Subject(); + private refresh$ = new BehaviorSubject(null); + + constructor( + private organizationAuthRequestService: OrganizationAuthRequestService, + private organizationUserService: OrganizationUserService, + private cryptoService: CryptoService, + private route: ActivatedRoute, + private platformUtilsService: PlatformUtilsService, + private i18nService: I18nService, + private logService: LogService, + private validationService: ValidationService + ) {} + + async ngOnInit() { + this.route.params + .pipe( + tap((params) => (this.organizationId = params.organizationId)), + switchMap(() => + this.refresh$.pipe( + tap(() => (this.loading = true)), + switchMap(() => + this.organizationAuthRequestService.listPendingRequests(this.organizationId) + ) + ) + ), + takeUntil(this.destroy$) + ) + .subscribe((r) => { + this.tableDataSource.data = r; + this.loading = false; + }); + } + + /** + * Creates a copy of the user's symmetric key that has been encrypted with the provided device's public key. + * @param devicePublicKey + * @param resetPasswordDetails + * @private + */ + private async getEncryptedUserSymKey( + devicePublicKey: string, + resetPasswordDetails: OrganizationUserResetPasswordDetailsResponse + ): Promise { + const encryptedUserSymKey = resetPasswordDetails.resetPasswordKey; + const encryptedOrgPrivateKey = resetPasswordDetails.encryptedPrivateKey; + const devicePubKey = Utils.fromB64ToArray(devicePublicKey); + + // Decrypt Organization's encrypted Private Key with org key + const orgSymKey = await this.cryptoService.getOrgKey(this.organizationId); + const decOrgPrivateKey = await this.cryptoService.decryptToBytes( + new EncString(encryptedOrgPrivateKey), + orgSymKey + ); + + // Decrypt User's symmetric key with decrypted org private key + const decValue = await this.cryptoService.rsaDecrypt(encryptedUserSymKey, decOrgPrivateKey); + const userSymKey = new SymmetricCryptoKey(decValue); + + // Re-encrypt User's Symmetric Key with the Device Public Key + return await this.cryptoService.rsaEncrypt(userSymKey.key, devicePubKey.buffer); + } + + async approveRequest(authRequest: PendingAuthRequestView) { + await this.performAsyncAction(async () => { + const details = await this.organizationUserService.getOrganizationUserResetPasswordDetails( + this.organizationId, + authRequest.organizationUserId + ); + + // The user must be enrolled in account recovery (password reset) in order for the request to be approved. + if (details == null || details.resetPasswordKey == null) { + this.platformUtilsService.showToast( + "error", + null, + this.i18nService.t("resetPasswordDetailsError") + ); + return; + } + + const encryptedKey = await this.getEncryptedUserSymKey(authRequest.publicKey, details); + + await this.organizationAuthRequestService.approvePendingRequest( + this.organizationId, + authRequest.id, + encryptedKey + ); + + this.platformUtilsService.showToast( + "success", + null, + this.i18nService.t("loginRequestApproved") + ); + }); + } + + async denyRequest(requestId: string) { + await this.performAsyncAction(async () => { + await this.organizationAuthRequestService.denyPendingRequests(this.organizationId, requestId); + this.platformUtilsService.showToast("error", null, this.i18nService.t("loginRequestDenied")); + }); + } + + async denyAllRequests() { + if (this.tableDataSource.data.length === 0) { + return; + } + + await this.performAsyncAction(async () => { + await this.organizationAuthRequestService.denyPendingRequests( + this.organizationId, + ...this.tableDataSource.data.map((r) => r.id) + ); + this.platformUtilsService.showToast( + "error", + null, + this.i18nService.t("allLoginRequestsDenied") + ); + }); + } + + private async performAsyncAction(action: () => Promise) { + if (this.actionInProgress) { + return; + } + this.actionInProgress = true; + try { + await action(); + this.refresh$.next(); + } catch (err: unknown) { + this.logService.error(err.toString()); + this.validationService.showError(err); + } finally { + this.actionInProgress = false; + } + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts index d1f71325ce9..22cd2571cae 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts @@ -2,14 +2,17 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; import { AuthGuard } from "@bitwarden/angular/auth/guards/auth.guard"; +import { canAccessFeature } from "@bitwarden/angular/guard/feature-flag.guard"; import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { OrganizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard"; import { OrganizationLayoutComponent } from "@bitwarden/web-vault/app/admin-console/organizations/layouts/organization-layout.component"; import { SettingsComponent } from "@bitwarden/web-vault/app/admin-console/organizations/settings/settings.component"; import { SsoComponent } from "../../auth/sso/sso.component"; +import { DeviceApprovalsComponent } from "./manage/device-approvals/device-approvals.component"; import { DomainVerificationComponent } from "./manage/domain-verification/domain-verification.component"; import { ScimComponent } from "./manage/scim.component"; @@ -51,6 +54,18 @@ const routes: Routes = [ organizationPermissions: (org: Organization) => org.canManageScim, }, }, + { + path: "device-approvals", + component: DeviceApprovalsComponent, + canActivate: [ + OrganizationPermissionsGuard, + canAccessFeature(FeatureFlag.TrustedDeviceEncryption), + ], + data: { + organizationPermissions: (org: Organization) => org.canManageUsersPassword, + titleId: "deviceApprovals", + }, + }, ], }, ], diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts index 08f7dea6406..3e939fa74f5 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts @@ -1,21 +1,25 @@ import { NgModule } from "@angular/core"; +import { NoItemsModule } from "@bitwarden/components"; import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; import { SsoComponent } from "../../auth/sso/sso.component"; +import { CoreOrganizationModule } from "./core"; +import { DeviceApprovalsComponent } from "./manage/device-approvals/device-approvals.component"; import { DomainAddEditDialogComponent } from "./manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component"; import { DomainVerificationComponent } from "./manage/domain-verification/domain-verification.component"; import { ScimComponent } from "./manage/scim.component"; import { OrganizationsRoutingModule } from "./organizations-routing.module"; @NgModule({ - imports: [SharedModule, OrganizationsRoutingModule], + imports: [SharedModule, CoreOrganizationModule, OrganizationsRoutingModule, NoItemsModule], declarations: [ SsoComponent, ScimComponent, DomainVerificationComponent, DomainAddEditDialogComponent, + DeviceApprovalsComponent, ], }) export class OrganizationsModule {} diff --git a/libs/angular/src/directives/if-feature.directive.spec.ts b/libs/angular/src/directives/if-feature.directive.spec.ts new file mode 100644 index 00000000000..bf73a172a55 --- /dev/null +++ b/libs/angular/src/directives/if-feature.directive.spec.ts @@ -0,0 +1,137 @@ +import { Component } from "@angular/core"; +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; +import { mock, MockProxy } from "jest-mock-extended"; + +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; + +import { IfFeatureDirective } from "./if-feature.directive"; + +const testBooleanFeature: FeatureFlag = "boolean-feature" as FeatureFlag; +const testStringFeature: FeatureFlag = "string-feature" as FeatureFlag; +const testStringFeatureValue = "test-value"; + +@Component({ + template: ` +
+
Hidden behind feature flag
+
+
+
Hidden behind feature flag
+
+
+
+ Hidden behind missing flag. Should not be visible. +
+
+ `, +}) +class TestComponent { + testBooleanFeature = testBooleanFeature; + stringFeature = testStringFeature; + stringFeatureValue = testStringFeatureValue; + + missingFlag = "missing-flag" as FeatureFlag; +} + +describe("IfFeatureDirective", () => { + let fixture: ComponentFixture; + let content: HTMLElement; + let mockConfigService: MockProxy; + + const mockConfigFlagValue = (flag: FeatureFlag, flagValue: any) => { + if (typeof flagValue === "boolean") { + mockConfigService.getFeatureFlagBool.mockImplementation((f, defaultValue = false) => + flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue) + ); + } else if (typeof flagValue === "string") { + mockConfigService.getFeatureFlagString.mockImplementation((f, defaultValue = "") => + flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue) + ); + } else if (typeof flagValue === "number") { + mockConfigService.getFeatureFlagNumber.mockImplementation((f, defaultValue = 0) => + flag == f ? Promise.resolve(flagValue) : Promise.resolve(defaultValue) + ); + } + }; + const queryContent = (testId: string) => + fixture.debugElement.query(By.css(`[data-testid="${testId}"]`))?.nativeElement; + + beforeEach(async () => { + mockConfigService = mock(); + + await TestBed.configureTestingModule({ + declarations: [IfFeatureDirective, TestComponent], + providers: [ + { provide: LogService, useValue: mock() }, + { + provide: ConfigServiceAbstraction, + useValue: mockConfigService, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(TestComponent); + }); + + it("renders content when the feature flag is enabled", async () => { + mockConfigFlagValue(testBooleanFeature, true); + fixture.detectChanges(); + await fixture.whenStable(); + + content = queryContent("boolean-content"); + + expect(content).toBeDefined(); + }); + + it("renders content when the feature flag value matches the provided value", async () => { + mockConfigFlagValue(testStringFeature, testStringFeatureValue); + fixture.detectChanges(); + await fixture.whenStable(); + + content = queryContent("string-content"); + + expect(content).toBeDefined(); + }); + + it("hides content when the feature flag is disabled", async () => { + mockConfigFlagValue(testBooleanFeature, false); + fixture.detectChanges(); + await fixture.whenStable(); + + content = queryContent("boolean-content"); + + expect(content).toBeUndefined(); + }); + + it("hides content when the feature flag value does not match the provided value", async () => { + mockConfigFlagValue(testStringFeature, "wrong-value"); + fixture.detectChanges(); + await fixture.whenStable(); + + content = queryContent("string-content"); + + expect(content).toBeUndefined(); + }); + + it("hides content when the feature flag is missing", async () => { + fixture.detectChanges(); + await fixture.whenStable(); + + content = queryContent("missing-flag-content"); + + expect(content).toBeUndefined(); + }); + + it("hides content when the directive throws an unexpected exception", async () => { + mockConfigService.getFeatureFlagBool.mockImplementation(() => Promise.reject("Some error")); + fixture.detectChanges(); + await fixture.whenStable(); + + content = queryContent("boolean-content"); + + expect(content).toBeUndefined(); + }); +}); diff --git a/libs/angular/src/directives/if-feature.directive.ts b/libs/angular/src/directives/if-feature.directive.ts new file mode 100644 index 00000000000..1a0ee35dc68 --- /dev/null +++ b/libs/angular/src/directives/if-feature.directive.ts @@ -0,0 +1,67 @@ +import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from "@angular/core"; + +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; + +// Replace this with a type safe lookup of the feature flag values in PM-2282 +type FlagValue = boolean | number | string; + +/** + * Directive that conditionally renders the element when the feature flag is enabled and/or + * matches the value specified by {@link appIfFeatureValue}. + * + * When a feature flag is not found in the config service, the element is hidden. + */ +@Directive({ + selector: "[appIfFeature]", +}) +export class IfFeatureDirective implements OnInit { + /** + * The feature flag to check. + */ + @Input() appIfFeature: FeatureFlag; + + /** + * Optional value to compare against the value of the feature flag in the config service. + * @default true + */ + @Input() appIfFeatureValue: FlagValue = true; + + private hasView = false; + + constructor( + private templateRef: TemplateRef, + private viewContainer: ViewContainerRef, + private configService: ConfigServiceAbstraction, + private logService: LogService + ) {} + + async ngOnInit() { + try { + let flagValue: FlagValue; + + if (typeof this.appIfFeatureValue === "boolean") { + flagValue = await this.configService.getFeatureFlagBool(this.appIfFeature); + } else if (typeof this.appIfFeatureValue === "number") { + flagValue = await this.configService.getFeatureFlagNumber(this.appIfFeature); + } else if (typeof this.appIfFeatureValue === "string") { + flagValue = await this.configService.getFeatureFlagString(this.appIfFeature); + } + + if (this.appIfFeatureValue === flagValue) { + if (!this.hasView) { + this.viewContainer.createEmbeddedView(this.templateRef); + this.hasView = true; + } + } else { + this.viewContainer.clear(); + this.hasView = false; + } + } catch (e) { + this.logService.error(e); + this.viewContainer.clear(); + this.hasView = false; + } + } +} diff --git a/libs/angular/src/jslib.module.ts b/libs/angular/src/jslib.module.ts index bfe8f758f92..929875bbb20 100644 --- a/libs/angular/src/jslib.module.ts +++ b/libs/angular/src/jslib.module.ts @@ -11,6 +11,7 @@ import { AutofocusDirective } from "./directives/autofocus.directive"; import { BoxRowDirective } from "./directives/box-row.directive"; import { CopyClickDirective } from "./directives/copy-click.directive"; import { FallbackSrcDirective } from "./directives/fallback-src.directive"; +import { IfFeatureDirective } from "./directives/if-feature.directive"; import { InputStripSpacesDirective } from "./directives/input-strip-spaces.directive"; import { InputVerbatimDirective } from "./directives/input-verbatim.directive"; import { LaunchClickDirective } from "./directives/launch-click.directive"; @@ -25,6 +26,7 @@ import { SearchPipe } from "./pipes/search.pipe"; import { UserNamePipe } from "./pipes/user-name.pipe"; import { UserTypePipe } from "./pipes/user-type.pipe"; import { EllipsisPipe } from "./platform/pipes/ellipsis.pipe"; +import { FingerprintPipe } from "./platform/pipes/fingerprint.pipe"; import { I18nPipe } from "./platform/pipes/i18n.pipe"; import { PasswordStrengthComponent } from "./shared/components/password-strength/password-strength.component"; import { ExportScopeCalloutComponent } from "./tools/export/components/export-scope-callout.component"; @@ -68,6 +70,8 @@ import { IconComponent } from "./vault/components/icon.component"; UserNamePipe, PasswordStrengthComponent, UserTypePipe, + IfFeatureDirective, + FingerprintPipe, ], exports: [ A11yInvalidDirective, @@ -97,7 +101,17 @@ import { IconComponent } from "./vault/components/icon.component"; UserNamePipe, PasswordStrengthComponent, UserTypePipe, + IfFeatureDirective, + FingerprintPipe, + ], + providers: [ + CreditCardNumberPipe, + DatePipe, + I18nPipe, + SearchPipe, + UserNamePipe, + UserTypePipe, + FingerprintPipe, ], - providers: [CreditCardNumberPipe, DatePipe, I18nPipe, SearchPipe, UserNamePipe, UserTypePipe], }) export class JslibModule {} diff --git a/libs/angular/src/platform/pipes/fingerprint.pipe.ts b/libs/angular/src/platform/pipes/fingerprint.pipe.ts new file mode 100644 index 00000000000..198b3a57f7c --- /dev/null +++ b/libs/angular/src/platform/pipes/fingerprint.pipe.ts @@ -0,0 +1,32 @@ +import { Pipe } from "@angular/core"; + +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; + +@Pipe({ + name: "fingerprint", +}) +export class FingerprintPipe { + constructor(private cryptoService: CryptoService) {} + + async transform(publicKey: string | Uint8Array, fingerprintMaterial: string): Promise { + try { + if (typeof publicKey === "string") { + publicKey = Utils.fromB64ToArray(publicKey); + } + + const fingerprint = await this.cryptoService.getFingerprint( + fingerprintMaterial, + publicKey.buffer + ); + + if (fingerprint != null) { + return fingerprint.join("-"); + } + + return ""; + } catch { + return ""; + } + } +} diff --git a/libs/components/src/no-items/no-items.component.ts b/libs/components/src/no-items/no-items.component.ts index a172a2eeabd..d85c6a34571 100644 --- a/libs/components/src/no-items/no-items.component.ts +++ b/libs/components/src/no-items/no-items.component.ts @@ -1,4 +1,4 @@ -import { Component } from "@angular/core"; +import { Component, Input } from "@angular/core"; import { Icons } from ".."; @@ -10,5 +10,5 @@ import { Icons } from ".."; templateUrl: "./no-items.component.html", }) export class NoItemsComponent { - protected icon = Icons.Search; + @Input() icon = Icons.Search; } diff --git a/libs/components/src/table/cell.directive.ts b/libs/components/src/table/cell.directive.ts index 058d90e5774..61c75571063 100644 --- a/libs/components/src/table/cell.directive.ts +++ b/libs/components/src/table/cell.directive.ts @@ -1,10 +1,10 @@ -import { HostBinding, Directive } from "@angular/core"; +import { Directive, HostBinding } from "@angular/core"; @Directive({ selector: "th[bitCell], td[bitCell]", }) export class CellDirective { @HostBinding("class") get classList() { - return ["tw-p-3", "tw-align-middle"]; + return ["tw-p-3"]; } } diff --git a/libs/components/src/table/row.directive.ts b/libs/components/src/table/row.directive.ts index 5d9eaca2613..19f3d3f775b 100644 --- a/libs/components/src/table/row.directive.ts +++ b/libs/components/src/table/row.directive.ts @@ -4,7 +4,7 @@ import { Directive, HostBinding, Input } from "@angular/core"; selector: "tr[bitRow]", }) export class RowDirective { - @Input() alignContent: "top" | "middle" | "bottom" | "baseline" = "baseline"; + @Input() alignContent: "top" | "middle" | "bottom" | "baseline" = "middle"; get alignmentClass(): string { switch (this.alignContent) { diff --git a/libs/components/src/table/table.stories.ts b/libs/components/src/table/table.stories.ts index 2d9830b7dad..9c1fac6956b 100644 --- a/libs/components/src/table/table.stories.ts +++ b/libs/components/src/table/table.stories.ts @@ -1,5 +1,5 @@ import { ScrollingModule } from "@angular/cdk/scrolling"; -import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { Meta, moduleMetadata, StoryObj } from "@storybook/angular"; import { countries } from "../form/countries"; @@ -62,7 +62,7 @@ export const Default: Story = { `, }), args: { - alignRowContent: "baseline", + alignRowContent: "middle", }, }; From 5cd51374d7e746c36da77314d7d84f8361de36a1 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Thu, 15 Jun 2023 21:03:48 -0500 Subject: [PATCH 23/29] [AC-1416] Expose Organization Fingerprint (#5557) * refactor: change getFingerprint param to fingerprintMaterial, refs PM-1522 * feat: generate and show fingerprint for organization (WIP), refs AC-1416 * feat: update legacy params subscription to best practice (WIP), refs AC-1461 * refactor: update to use reactive forms, refs AC-1416 * refactor: remove boostrap specific classes and update to component library paradigms, refs AC-1416 * refactor: remove boostrap specific classes and update to component library paradigms, refs AC-1416 * refactor: create shared fingerprint component to redude boilerplate for settings fingerprint views, refs AC-1416 * refactor: use grid to emulate col-6 and remove unnecessary theme extensions, refs AC-1416 * refactor: remove negative margin and clean up extra divs, refs AC-1416 * [AC-1431] Add missing UserVerificationModule import (#5555) * [PM-2238] Add nord and solarize themes (#5491) * Fix simple configurable dialog stories (#5560) * chore(deps): update bitwarden/gh-actions digest to 72594be (#5523) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * refactor: remove extra div leftover from card-body class, refs AC-1416 * refactor: use bitTypography for headers, refs AC-1416 * fix: update crypto service abstraction path, refs AC-1416 * refactor: remove try/catch on handler, remove bootstrap class, update api chaining in observable, refs AC-1416 * fix: replace faulty combineLatest logic, refs AC-1416 * refactor: simplify observable logic again, refs AC-1416 --------- Co-authored-by: Shane Melton Co-authored-by: Oscar Hinton Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../settings/account.component.html | 103 +++++-------- .../settings/account.component.ts | 140 +++++++++++++----- .../settings/organization-settings.module.ts | 9 +- .../src/app/settings/profile.component.html | 18 +-- .../web/src/app/settings/profile.component.ts | 13 +- .../account-fingerprint.component.html | 16 ++ .../account-fingerprint.component.ts | 30 ++++ .../src/app/shared/loose-components.module.ts | 2 + apps/web/src/locales/en/messages.json | 4 + .../platform/abstractions/crypto.service.ts | 2 +- .../src/platform/services/crypto.service.ts | 4 +- 11 files changed, 206 insertions(+), 135 deletions(-) create mode 100644 apps/web/src/app/shared/components/account-fingerprint/account-fingerprint.component.html create mode 100644 apps/web/src/app/shared/components/account-fingerprint/account-fingerprint.component.ts diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html index 08059ed99fd..c7ac9910ac5 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.html +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html @@ -1,95 +1,66 @@ - +

{{ "organizationInfo" | i18n }}

- {{ "loading" | i18n }} + {{ "loading" | i18n }}
-
-
-
-
- - -
-
- - -
-
- - -
+ +
+
+ + {{ "organizationName" | i18n }} + + + + {{ "billingEmail" | i18n }} + + + + {{ "businessName" | i18n }} + +
-
+
+ +
- -
-

{{ "apiKey" | i18n }}

-
+

{{ "apiKey" | i18n }}

{{ "apiKeyDesc" | i18n }} {{ "learnMore" | i18n }}

- - -
-

{{ "dangerZone" | i18n }}

-
-
-
-

{{ "dangerZoneDesc" | i18n }}

- - -
+

{{ "dangerZone" | i18n }}

+
+

{{ "dangerZoneDesc" | i18n }}

+ +
diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.ts b/apps/web/src/app/admin-console/organizations/settings/account.component.ts index 2d0c1b17bea..48dcb2c88c6 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.ts +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.ts @@ -1,6 +1,7 @@ import { Component, ViewChild, ViewContainerRef } from "@angular/core"; +import { FormBuilder, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; -import { lastValueFrom } from "rxjs"; +import { combineLatest, lastValueFrom, Subject, switchMap, takeUntil, from } from "rxjs"; import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog"; import { ModalService } from "@bitwarden/angular/services/modal.service"; @@ -13,6 +14,7 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ApiKeyComponent } from "../../../settings/api-key.component"; import { PurgeVaultComponent } from "../../../settings/purge-vault.component"; @@ -23,7 +25,6 @@ import { DeleteOrganizationDialogResult, openDeleteOrganizationDialog } from "./ selector: "app-org-account", templateUrl: "account.component.html", }) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil export class AccountComponent { @ViewChild("purgeOrganizationTemplate", { read: ViewContainerRef, static: true }) purgeModalRef: ViewContainerRef; @@ -40,7 +41,29 @@ export class AccountComponent { formPromise: Promise; taxFormPromise: Promise; - private organizationId: string; + // FormGroup validators taken from server Organization domain object + protected formGroup = this.formBuilder.group({ + orgName: this.formBuilder.control( + { value: "", disabled: true }, + { + validators: [Validators.required, Validators.maxLength(50)], + updateOn: "change", + } + ), + billingEmail: this.formBuilder.control( + { value: "", disabled: true }, + { validators: [Validators.required, Validators.email, Validators.maxLength(256)] } + ), + businessName: this.formBuilder.control( + { value: "", disabled: true }, + { validators: [Validators.maxLength(50)] } + ), + }); + + protected organizationId: string; + protected publicKeyBuffer: ArrayBuffer; + + private destroy$ = new Subject(); constructor( private modalService: ModalService, @@ -52,53 +75,88 @@ export class AccountComponent { private router: Router, private organizationService: OrganizationService, private organizationApiService: OrganizationApiServiceAbstraction, - private dialogService: DialogServiceAbstraction + private dialogService: DialogServiceAbstraction, + private formBuilder: FormBuilder ) {} async ngOnInit() { this.selfHosted = this.platformUtilsService.isSelfHost(); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.parent.parent.params.subscribe(async (params) => { - this.organizationId = params.organizationId; - this.canEditSubscription = this.organizationService.get( - this.organizationId - ).canEditSubscription; - try { - this.org = await this.organizationApiService.get(this.organizationId); - this.canUseApi = this.org.useApi; - } catch (e) { - this.logService.error(e); - } - }); - this.loading = false; + this.route.parent.parent.params + .pipe( + switchMap((params) => { + return combineLatest([ + // Organization domain + this.organizationService.get$(params.organizationId), + // OrganizationResponse for form population + from(this.organizationApiService.get(params.organizationId)), + // Organization Public Key + from(this.organizationApiService.getKeys(params.organizationId)), + ]); + }), + takeUntil(this.destroy$) + ) + .subscribe(([organization, orgResponse, orgKeys]) => { + // Set domain level organization variables + this.organizationId = organization.id; + this.canEditSubscription = organization.canEditSubscription; + this.canUseApi = organization.useApi; + + // Org Response + this.org = orgResponse; + + // Public Key Buffer for Org Fingerprint Generation + this.publicKeyBuffer = Utils.fromB64ToArray(orgKeys?.publicKey)?.buffer; + + // Patch existing values + this.formGroup.patchValue({ + orgName: this.org.name, + billingEmail: this.org.billingEmail, + businessName: this.org.businessName, + }); + + // Update disabled states - reactive forms prefers not using disabled attribute + if (!this.selfHosted) { + this.formGroup.get("orgName").enable(); + } + + if (!this.selfHosted || this.canEditSubscription) { + this.formGroup.get("billingEmail").enable(); + this.formGroup.get("businessName").enable(); + } + + this.loading = false; + }); } - async submit() { - try { - const request = new OrganizationUpdateRequest(); - request.name = this.org.name; - request.businessName = this.org.businessName; - request.billingEmail = this.org.billingEmail; + ngOnDestroy(): void { + // You must first call .next() in order for the notifier to properly close subscriptions using takeUntil + this.destroy$.next(); + this.destroy$.complete(); + } - // Backfill pub/priv key if necessary - if (!this.org.hasPublicAndPrivateKeys) { - const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId); - const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey); - request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString); - } - - this.formPromise = this.organizationApiService.save(this.organizationId, request); - await this.formPromise; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("organizationUpdated") - ); - } catch (e) { - this.logService.error(e); + submit = async () => { + this.formGroup.markAllAsTouched(); + if (this.formGroup.invalid) { + return; } - } + + const request = new OrganizationUpdateRequest(); + request.name = this.formGroup.value.orgName; + request.businessName = this.formGroup.value.businessName; + request.billingEmail = this.formGroup.value.billingEmail; + + // Backfill pub/priv key if necessary + if (!this.org.hasPublicAndPrivateKeys) { + const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId); + const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey); + request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString); + } + + this.formPromise = this.organizationApiService.save(this.organizationId, request); + await this.formPromise; + this.platformUtilsService.showToast("success", null, this.i18nService.t("organizationUpdated")); + }; async deleteOrganization() { const dialog = openDeleteOrganizationDialog(this.dialogService, { diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts index c5500c6a94a..9eaec0a068e 100644 --- a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts +++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { LooseComponentsModule, SharedModule } from "../../../shared"; +import { AccountFingerprintComponent } from "../../../shared/components/account-fingerprint/account-fingerprint.component"; import { PoliciesModule } from "../../organizations/policies"; import { AccountComponent } from "./account.component"; @@ -9,7 +10,13 @@ import { SettingsComponent } from "./settings.component"; import { TwoFactorSetupComponent } from "./two-factor-setup.component"; @NgModule({ - imports: [SharedModule, LooseComponentsModule, PoliciesModule, OrganizationSettingsRoutingModule], + imports: [ + SharedModule, + LooseComponentsModule, + PoliciesModule, + OrganizationSettingsRoutingModule, + AccountFingerprintComponent, + ], declarations: [SettingsComponent, AccountComponent, TwoFactorSetupComponent], }) export class OrganizationSettingsModule {} diff --git a/apps/web/src/app/settings/profile.component.html b/apps/web/src/app/settings/profile.component.html index be0e58eaa1d..91e0d4b985a 100644 --- a/apps/web/src/app/settings/profile.component.html +++ b/apps/web/src/app/settings/profile.component.html @@ -46,19 +46,11 @@ Customize
-
-

- {{ "yourAccountsFingerprint" | i18n }}: - -
- {{ fingerprint }} -

+ +