diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 6b34998b99b..6e142edf8a7 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -363,6 +363,8 @@ "@types/jsdom", "@types/papaparse", "@types/zxcvbn", + "async-trait", + "clap", "jsdom", "jszip", "oidc-client-ts", @@ -435,5 +437,11 @@ description: "Higher versions of lowdb do not need separate types", }, ], - ignoreDeps: ["@types/koa-bodyparser", "bootstrap", "node-ipc", "@bitwarden/sdk-internal"], + ignoreDeps: [ + "@types/koa-bodyparser", + "bootstrap", + "node-ipc", + "@bitwarden/sdk-internal", + "@bitwarden/commercial-sdk-internal", + ], } diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index 772cb25d98d..3990a8bef95 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -349,7 +349,7 @@ jobs: - name: Upload dev extension artifact if: ${{ matrix.browser.archive_name_dev != '' }} - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: ${{ matrix.license_type.artifact_prefix }}${{ matrix.browser.artifact_name_dev }}-${{ env._BUILD_NUMBER }}.zip path: browser-source/apps/browser/dist/${{matrix.license_type.archive_name_prefix}}${{ matrix.browser.archive_name_dev }} diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 20eb31a5453..505a8404233 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "تعيين كلمة مرور رئيسية" }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index d8d8589f47e..086b66380b5 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Ana parolu ayarla" }, @@ -5810,13 +5813,13 @@ "message": "\"Premium\"a yüksəlt" }, "upgradeCompleteSecurity": { - "message": "Upgrade for complete security" + "message": "Tam təhlükəsizlik üçün yüksəldin" }, "premiumGivesMoreTools": { - "message": "Premium gives you more tools to stay secure, work efficiently, and stay in control." + "message": "Premium, güvəndə qalmağınız, səmərəli çalışmağınız və nəzarətə sahib olmağınız üçün daha çox alət verir." }, "explorePremium": { - "message": "Explore Premium" + "message": "Premium-u kəşf et" }, "loadingVault": { "message": "Seyf yüklənir" diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 47bafb7efe3..16a6d739962 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Прызначыць асноўны пароль" }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 98da9bf033e..3dba65d6aa7 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Задаване на главна парола" }, diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 794e380d012..d2519cb13e3 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "মূল পাসওয়ার্ড ধার্য করুন" }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 611cb4f5f55..917180579f2 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 01611cc0764..a9ebdf139d7 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Estableix la contrasenya mestra" }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 5c0c8fbf524..ca5d4b09f28 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Tato stránka narušuje zážitek z Bitwardenu. Vložené menu Bitwarden bylo dočasně vypnuto jako bezpečnostní opatření." + }, "setMasterPassword": { "message": "Nastavit hlavní heslo" }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 3bd81cc8039..1f83ff72f62 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Gosod prif gyfrinair" }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 9a12f808f22..96aa81ce876 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Indstil hovedadgangskode" }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 517dc638aff..b32c9a68c06 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Master-Passwort festlegen" }, @@ -5813,10 +5816,10 @@ "message": "Upgrade für umfassende Sicherheit" }, "premiumGivesMoreTools": { - "message": "Premium gives you more tools to stay secure, work efficiently, and stay in control." + "message": "Premium gibt dir mehr Werkzeuge, um sicher zu bleiben, effizient zu arbeiten und die Kontrolle zu behalten." }, "explorePremium": { - "message": "Explore Premium" + "message": "Premium erkunden" }, "loadingVault": { "message": "Tresor wird geladen" diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index ae685fff651..f4c3c0d53a5 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Ορισμός κύριου κωδικού πρόσβασης" }, diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 5cc7c30bfb4..14915175da1 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -4902,6 +4902,9 @@ "premium": { "message": "Premium" }, + "unlockFeaturesWithPremium": { + "message": "Unlock reporting, emergency access, and more security features with Premium." + }, "freeOrgsCannotUseAttachments": { "message": "Free organizations cannot use attachments" }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 5079e1e6689..96c3323faef 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 2a34400ea58..b9f777148e3 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 8100fa80435..92dbe15fad2 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Establecer contraseña maestra" }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 0f69561df57..bb029bf7777 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Määra ülemparool" }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index c60ce5e4da7..06a4f8ea48d 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Ezarri pasahitz nagusia" }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 5a03f8427fa..33f4a02277d 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "تنظیم کلمه عبور اصلی" }, diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index db4649c33a7..9953782f504 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Aseta pääsalasana" }, @@ -4984,7 +4987,7 @@ } }, "defaultLabelWithValue": { - "message": "Default ( $VALUE$ )", + "message": "Oletus ( $VALUE$ )", "description": "A label that indicates the default value for a field with the current default value in parentheses.", "placeholders": { "value": { @@ -5656,7 +5659,7 @@ "message": "Close this tab" }, "phishingPageContinueV2": { - "message": "Continue to this site (not recommended)" + "message": "Jatka tälle sivustolle (ei suositeltavaa)" }, "phishingPageExplanation1": { "message": "This site was found in ", @@ -5773,7 +5776,7 @@ "message": "Show less" }, "next": { - "message": "Next" + "message": "Seuraava" }, "moreBreadcrumbs": { "message": "More breadcrumbs", @@ -5819,20 +5822,20 @@ "message": "Explore Premium" }, "loadingVault": { - "message": "Loading vault" + "message": "Ladataan holvia" }, "vaultLoaded": { - "message": "Vault loaded" + "message": "Holvi ladattu" }, "settingDisabledByPolicy": { "message": "This setting is disabled by your organization's policy.", "description": "This hint text is displayed when a user setting is disabled due to an organization policy." }, "zipPostalCodeLabel": { - "message": "ZIP / Postal code" + "message": "Postinumero" }, "cardNumberLabel": { - "message": "Card number" + "message": "Kortin numero" }, "sessionTimeoutSettingsAction": { "message": "Timeout action" diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 6239e9d4f97..687863550a7 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Itakda ang master password" }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 1cc04809a1b..87c1a20a38a 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -32,7 +32,7 @@ "message": "Utiliser l'authentification unique" }, "yourOrganizationRequiresSingleSignOn": { - "message": "Your organization requires single sign-on." + "message": "Votre organisation exige l’authentification unique." }, "welcomeBack": { "message": "Content de vous revoir" @@ -592,10 +592,10 @@ "message": "Afficher" }, "viewAll": { - "message": "View all" + "message": "Tout afficher" }, "viewLess": { - "message": "View less" + "message": "Afficher moins" }, "viewLogin": { "message": "Afficher l'Identifiant" @@ -800,10 +800,10 @@ "message": "Au verrouillage" }, "onIdle": { - "message": "On system idle" + "message": "À l'inactivité du système" }, "onSleep": { - "message": "On system sleep" + "message": "À la mise en veille du système" }, "onRestart": { "message": "Au redémarrage du navigateur" @@ -1044,10 +1044,10 @@ "message": "Élément enregistré" }, "savedWebsite": { - "message": "Saved website" + "message": "Site Web enregistré" }, "savedWebsites": { - "message": "Saved websites ( $COUNT$ )", + "message": "Sites Web enregistrés ( $COUNT$)", "placeholders": { "count": { "content": "$1", @@ -1645,7 +1645,7 @@ "message": "Vous devez ajouter soit l'URL du serveur de base, soit au moins un environnement personnalisé." }, "selfHostedEnvMustUseHttps": { - "message": "URLs must use HTTPS." + "message": "Les URL doivent utiliser HTTPS." }, "customEnvironment": { "message": "Environnement personnalisé" @@ -1701,28 +1701,28 @@ "message": "Désactiver la saisie automatique" }, "confirmAutofill": { - "message": "Confirm autofill" + "message": "Confirmer la saisie automatique" }, "confirmAutofillDesc": { - "message": "This site doesn't match your saved login details. Before you fill in your login credentials, make sure it's a trusted site." + "message": "Ce site ne correspond pas à vos identifiants de connexion enregistrés. Avant de remplir vos identifiants de connexion, assurez-vous que c'est un site de confiance." }, "showInlineMenuLabel": { "message": "Afficher les suggestions de saisie automatique dans les champs d'un formulaire" }, "howDoesBitwardenProtectFromPhishing": { - "message": "How does Bitwarden protect your data from phishing?" + "message": "Comment Bitwarden protège-t-il vos données contre l'hameçonnage ?" }, "currentWebsite": { - "message": "Current website" + "message": "Site internet actuel" }, "autofillAndAddWebsite": { - "message": "Autofill and add this website" + "message": "Saisir automatiquement et ajouter ce site" }, "autofillWithoutAdding": { - "message": "Autofill without adding" + "message": "Saisir automatiquement sans ajouter" }, "doNotAutofill": { - "message": "Do not autofill" + "message": "Ne pas saisir automatiquement" }, "showInlineMenuIdentitiesLabel": { "message": "Afficher les identités sous forme de suggestions" @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Définir le mot de passe principal" }, @@ -3286,7 +3289,7 @@ "message": "Erreur de déchiffrement" }, "errorGettingAutoFillData": { - "message": "Error getting autofill data" + "message": "Erreur lors de l'obtention des données de saisie automatique" }, "couldNotDecryptVaultItemsBelow": { "message": "Bitwarden n’a pas pu déchiffrer le(s) élément(s) du coffre listé(s) ci-dessous." @@ -4060,13 +4063,13 @@ "description": "Toast message for informing the user that autofill on page load has been set to the default setting." }, "cannotAutofill": { - "message": "Cannot autofill" + "message": "Impossible de saisir automatiquement" }, "cannotAutofillExactMatch": { - "message": "Default matching is set to 'Exact Match'. The current website does not exactly match the saved login details for this item." + "message": "La correspondance par défaut est définie à 'Correspondance exacte'. Le site internet actuel ne correspond pas exactement aux informations de l'identifiant de connexion enregistrées pour cet élément." }, "okay": { - "message": "Okay" + "message": "Ok" }, "toggleSideNavigation": { "message": "Basculer la navigation latérale" @@ -4984,7 +4987,7 @@ } }, "defaultLabelWithValue": { - "message": "Default ( $VALUE$ )", + "message": "Par défaut ($VALUE$)", "description": "A label that indicates the default value for a field with the current default value in parentheses.", "placeholders": { "value": { @@ -5786,43 +5789,43 @@ "message": "Excellent travail pour sécuriser vos identifiants à risque !" }, "upgradeNow": { - "message": "Upgrade now" + "message": "Mettre à niveau maintenant" }, "builtInAuthenticator": { - "message": "Built-in authenticator" + "message": "Authentificateur intégré" }, "secureFileStorage": { - "message": "Secure file storage" + "message": "Stockage sécurisé de fichier" }, "emergencyAccess": { - "message": "Emergency access" + "message": "Accès d'urgence" }, "breachMonitoring": { - "message": "Breach monitoring" + "message": "Surveillance des fuites" }, "andMoreFeatures": { - "message": "And more!" + "message": "Et encore plus !" }, "planDescPremium": { - "message": "Complete online security" + "message": "Sécurité en ligne complète" }, "upgradeToPremium": { - "message": "Upgrade to Premium" + "message": "Mettre à niveau vers Premium" }, "upgradeCompleteSecurity": { - "message": "Upgrade for complete security" + "message": "Mettre à niveau pour une sécurité complète" }, "premiumGivesMoreTools": { - "message": "Premium gives you more tools to stay secure, work efficiently, and stay in control." + "message": "Premium vous donne plus d'outils pour rester en sécurité, travailler efficacement et garder le contrôle." }, "explorePremium": { - "message": "Explore Premium" + "message": "Explorer Premium" }, "loadingVault": { - "message": "Loading vault" + "message": "Chargement du coffre" }, "vaultLoaded": { - "message": "Vault loaded" + "message": "Coffre chargé" }, "settingDisabledByPolicy": { "message": "Ce paramètre est désactivé par la politique de sécurité de votre organisation.", @@ -5835,6 +5838,6 @@ "message": "Numéro de carte" }, "sessionTimeoutSettingsAction": { - "message": "Timeout action" + "message": "Action à l’expiration" } } diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 090bc6b1493..9b35af1aad4 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Definir contrasinal mestre" }, diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 2934d345600..7d1700cbbdc 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "הגדר סיסמה ראשית" }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 75011ebf8e5..0af38bf6964 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "मास्टर पासवर्ड सेट करें" }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index fb89e8940e3..9bb5ca08843 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Postavi glavnu lozinku" }, diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index f9a2f9ff009..9b6a5d756d5 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Ez az oldal zavarja a Bitwarden élményt. Biztonsági intézkedésként ideiglenesen letiltásra került a Bitwarden belső menü." + }, "setMasterPassword": { "message": "Mesterjelszó beállítása" }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index a88e3cc2d37..85fdfbf9afe 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Atur Kata Sandi Utama" }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index f0e63d99ecf..a76bb05d15a 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Imposta password principale" }, diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 98ac152a08f..1294335481c 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "マスターパスワードを設定" }, @@ -3365,7 +3368,7 @@ "message": "サービス" }, "forwardedEmail": { - "message": "転送されたメールエイリアス" + "message": "転送されるメールエイリアス" }, "forwardedEmailDesc": { "message": "外部転送サービスを使用してメールエイリアスを生成します。" @@ -4517,7 +4520,7 @@ "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "URI の一致検出方法は、Bitwarden が自動入力候補をどのように判別するかを指定します。", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index e6e8becd50a..52e9fbc5229 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index cb1a5c089fe..7c4dbaf85dc 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index c83d63762d6..d2ca68a0108 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "ಮಾಸ್ಟರ್ ಪಾಸ್ವರ್ಡ್ ಹೊಂದಿಸಿ" }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 50f49833d50..c583e173d91 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "마스터 비밀번호 설정" }, diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 21cd9ca401c..45ee71f75dd 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Pagrindinio slaptažodžio nustatymas" }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 088d671a2b5..d7e4b5eea9c 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Šī lapa traucē Bitwarden darbību. Bitwarden iekļautā izvēlne ir īslaicīgi atspējot kā drošības mērs." + }, "setMasterPassword": { "message": "Uzstādīt galveno paroli" }, @@ -5810,13 +5813,13 @@ "message": "Uzlabot uz Premium" }, "upgradeCompleteSecurity": { - "message": "Upgrade for complete security" + "message": "Uzlabo pilnīgas drošības iegūšanai" }, "premiumGivesMoreTools": { - "message": "Premium gives you more tools to stay secure, work efficiently, and stay in control." + "message": "Premium sniedz vairāk rīku drošībai, darba ražīgumam un pārraudzībai." }, "explorePremium": { - "message": "Explore Premium" + "message": "Izpētīt Premium" }, "loadingVault": { "message": "Ielādē glabātavu" diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index d76f579fac4..6c022f0043f 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "പ്രാഥമിക പാസ്‌വേഡ് സജ്ജമാക്കുക" }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index acbbc97ceac..d34d1c87971 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index cb1a5c089fe..7c4dbaf85dc 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 3933f66c541..11bd78ed56c 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Angi hovedpassord" }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index cb1a5c089fe..7c4dbaf85dc 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index a4d38f6c9ba..8817e04b163 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Deze pagina verstoort de Bitwarden-ervaring. Het inline-menu van Bitwarden is tijdelijk uitgeschakeld als veiligheidsmaatregel." + }, "setMasterPassword": { "message": "Hoofdwachtwoord instellen" }, diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index cb1a5c089fe..7c4dbaf85dc 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index cb1a5c089fe..7c4dbaf85dc 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 0847126f33e..41f679aba50 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Ustaw hasło główne" }, diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index dbd7229db2a..9e5d2331744 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Definir senha principal" }, diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 55065838ec8..4fd291e5c89 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Esta página está a interferir com a experiência do Bitwarden. O menu em linha do Bitwarden foi temporariamente desativado como medida de segurança." + }, "setMasterPassword": { "message": "Definir a palavra-passe mestra" }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 84a1937bf14..66a5b9d796b 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Setare parolă principală" }, diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 22e9052fe43..1f3d7c7234f 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Эта страница мешает работе Bitwarden. Встроенное меню Bitwarden было временно отключено в целях безопасности." + }, "setMasterPassword": { "message": "Задать мастер-пароль" }, diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index f4c00449a2b..61dc029754a 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "මාස්ටර් මුරපදය සකසන්න" }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index b8b820def35..865e832fda3 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Táto stránka narúša zážitok zo Bitwardenu. Inline ponuka Bitwardenu bola dočasne vypnutá ako bezpečnostné opatrenie." + }, "setMasterPassword": { "message": "Nastaviť hlavné heslo" }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 70d9c5f70c2..ebb245290f9 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Nastavi glavno geslo" }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 97fcb37fb58..d54a6ba928f 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Постави Главну Лозинку" }, diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index ea7a4d80359..245692a27aa 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Denna sida stör Bitwarden-upplevelsen. Bitwardens inbyggda meny har tillfälligt inaktiverats som en säkerhetsåtgärd." + }, "setMasterPassword": { "message": "Ange huvudlösenord" }, diff --git a/apps/browser/src/_locales/ta/messages.json b/apps/browser/src/_locales/ta/messages.json index a95da4d2059..a6e2ad0ee31 100644 --- a/apps/browser/src/_locales/ta/messages.json +++ b/apps/browser/src/_locales/ta/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "முதன்மை கடவுச்சொல்லை அமை" }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index cb1a5c089fe..7c4dbaf85dc 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Set master password" }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 9096067ce3b..ff0c05a470a 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "ตั้งรหัสผ่านหลัก" }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 4c7ca6937a4..b2bff83e8a9 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "Bu sayfa Bitwarden deneyimiyle çakışıyor. Güvenlik önlemi olarak Bitwarden satır içi menüsü geçici olarak devre dışı bırakıldı." + }, "setMasterPassword": { "message": "Ana parolayı belirle" }, diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 7f8b0f8b13b..b104f845fa7 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Встановити головний пароль" }, diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 414b4cc2cac..242b779ca26 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "This page is interfering with the Bitwarden experience. The Bitwarden inline menu has been temporarily disabled as a safety measure." + }, "setMasterPassword": { "message": "Đặt mật khẩu chính" }, diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 548bdd9e178..cf1664b6a6f 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "此页面正在干扰 Bitwarden 的使用体验。出于安全考虑,Bitwarden 内嵌菜单已被暂时禁用。" + }, "setMasterPassword": { "message": "设置主密码" }, diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 600447a29f3..0ef20edce81 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -2436,6 +2436,9 @@ } } }, + "topLayerHijackWarning": { + "message": "此頁面正在干擾 Bitwarden 的使用體驗。為了安全起見,已暫時停用 Bitwarden 的內嵌選單。" + }, "setMasterPassword": { "message": "設定主密碼" }, @@ -5810,13 +5813,13 @@ "message": "升級到 Premium" }, "upgradeCompleteSecurity": { - "message": "Upgrade for complete security" + "message": "升級以獲得完整的安全防護" }, "premiumGivesMoreTools": { - "message": "Premium gives you more tools to stay secure, work efficiently, and stay in control." + "message": "進階版提供更多工具,協助您維持安全、高效工作並保持掌控。" }, "explorePremium": { - "message": "Explore Premium" + "message": "探索進階版" }, "loadingVault": { "message": "正在載入密碼庫" diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 225cbbe66ca..0eb7d070de3 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -2949,17 +2949,21 @@ export class OverlayBackground implements OverlayBackgroundInterface { (await this.checkFocusedFieldHasValue(port.sender.tab)) && (await this.shouldShowSaveLoginInlineMenuList(port.sender.tab)); + const iframeUrl = chrome.runtime.getURL( + `overlay/menu-${isInlineMenuListPort ? "list" : "button"}.html`, + ); + const styleSheetUrl = chrome.runtime.getURL( + `overlay/menu-${isInlineMenuListPort ? "list" : "button"}.css`, + ); + const extensionOrigin = new URL(iframeUrl).origin; + this.postMessageToPort(port, { command: `initAutofillInlineMenu${isInlineMenuListPort ? "List" : "Button"}`, - iframeUrl: chrome.runtime.getURL( - `overlay/menu-${isInlineMenuListPort ? "list" : "button"}.html`, - ), + iframeUrl, pageTitle: chrome.i18n.getMessage( isInlineMenuListPort ? "bitwardenVault" : "bitwardenOverlayButton", ), - styleSheetUrl: chrome.runtime.getURL( - `overlay/menu-${isInlineMenuListPort ? "list" : "button"}.css`, - ), + styleSheetUrl, theme: await firstValueFrom(this.themeStateService.selectedTheme$), translations: this.getInlineMenuTranslations(), ciphers: isInlineMenuListPort ? await this.getInlineMenuCipherData() : null, @@ -2973,6 +2977,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { showSaveLoginMenu, showInlineMenuAccountCreation, authStatus, + extensionOrigin, }); this.updateInlineMenuPosition( port.sender, diff --git a/apps/browser/src/autofill/fido2/content/fido2-page-script-delay-append.mv2.ts b/apps/browser/src/autofill/fido2/content/fido2-page-script-delay-append.mv2.ts index 775bc76266d..e167f30af0a 100644 --- a/apps/browser/src/autofill/fido2/content/fido2-page-script-delay-append.mv2.ts +++ b/apps/browser/src/autofill/fido2/content/fido2-page-script-delay-append.mv2.ts @@ -8,6 +8,9 @@ } const script = globalContext.document.createElement("script"); + // This script runs in world: MAIN, eliminating the risk associated with this lint error. + // DOM injection is still needed for the iframe timing hack. + // eslint-disable-next-line @bitwarden/platform/no-page-script-url-leakage script.src = chrome.runtime.getURL("content/fido2-page-script.js"); script.async = false; diff --git a/apps/browser/src/autofill/overlay/inline-menu/abstractions/autofill-inline-menu-container.ts b/apps/browser/src/autofill/overlay/inline-menu/abstractions/autofill-inline-menu-container.ts index af60d1de77d..64fa8dde124 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/abstractions/autofill-inline-menu-container.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/abstractions/autofill-inline-menu-container.ts @@ -17,6 +17,7 @@ export type InitAutofillInlineMenuElementMessage = AutofillInlineMenuContainerMe translations: Record; ciphers: InlineMenuCipherData[] | null; portName: string; + extensionOrigin?: string; }; export type AutofillInlineMenuContainerWindowMessage = AutofillInlineMenuContainerMessage & diff --git a/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.spec.ts b/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.spec.ts index d7a61bec61f..e0a6e626b3c 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.spec.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.spec.ts @@ -184,4 +184,38 @@ describe("AutofillInlineMenuContainer", () => { expect(port.postMessage).not.toHaveBeenCalled(); }); }); + + describe("isExtensionUrlWithOrigin", () => { + it("validates extension URLs with matching origin", () => { + const url = "chrome-extension://test-id/path/to/file.html"; + const origin = "chrome-extension://test-id"; + + expect(autofillInlineMenuContainer["isExtensionUrlWithOrigin"](url, origin)).toBe(true); + }); + + it("rejects extension URLs with mismatched origin", () => { + const url = "chrome-extension://test-id/path/to/file.html"; + const origin = "chrome-extension://different-id"; + + expect(autofillInlineMenuContainer["isExtensionUrlWithOrigin"](url, origin)).toBe(false); + }); + + it("validates extension URL against its own origin when no expectedOrigin provided", () => { + const url = "moz-extension://test-id/path/to/file.html"; + + expect(autofillInlineMenuContainer["isExtensionUrlWithOrigin"](url)).toBe(true); + }); + + it("rejects non-extension protocols", () => { + const url = "https://example.com/path"; + const origin = "https://example.com"; + + expect(autofillInlineMenuContainer["isExtensionUrlWithOrigin"](url, origin)).toBe(false); + }); + + it("rejects empty or invalid URLs", () => { + expect(autofillInlineMenuContainer["isExtensionUrlWithOrigin"]("")).toBe(false); + expect(autofillInlineMenuContainer["isExtensionUrlWithOrigin"]("not-a-url")).toBe(false); + }); + }); }); diff --git a/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.ts b/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.ts index ad0b11f0bc6..aea6ef30b99 100644 --- a/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.ts +++ b/apps/browser/src/autofill/overlay/inline-menu/pages/menu-container/autofill-inline-menu-container.ts @@ -87,11 +87,13 @@ export class AutofillInlineMenuContainer { return; } - if (!this.isExtensionUrl(message.iframeUrl)) { + const expectedOrigin = message.extensionOrigin || this.extensionOrigin; + + if (!this.isExtensionUrlWithOrigin(message.iframeUrl, expectedOrigin)) { return; } - if (message.styleSheetUrl && !this.isExtensionUrl(message.styleSheetUrl)) { + if (message.styleSheetUrl && !this.isExtensionUrlWithOrigin(message.styleSheetUrl)) { return; } @@ -115,20 +117,25 @@ export class AutofillInlineMenuContainer { } /** - * validates that a URL is from the extension origin. - * prevents loading arbitrary URLs in the iframe. + * Validates that a URL uses an extension protocol and matches the expected extension origin. + * If no expectedOrigin is provided, validates against the URL's own origin. * * @param url - The URL to validate. */ - private isExtensionUrl(url: string): boolean { + private isExtensionUrlWithOrigin(url: string, expectedOrigin?: string): boolean { if (!url) { return false; } try { const urlObj = new URL(url); - return ( - urlObj.origin === this.extensionOrigin || urlObj.href.startsWith(this.extensionOrigin + "/") - ); + const isExtensionProtocol = /^[a-z]+(-[a-z]+)?-extension:$/i.test(urlObj.protocol); + + if (!isExtensionProtocol) { + return false; + } + + const originToValidate = expectedOrigin ?? urlObj.origin; + return urlObj.origin === originToValidate || urlObj.href.startsWith(originToValidate + "/"); } catch { return false; } diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 920f0f02caa..276daa052da 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -726,17 +726,6 @@ export default class MainBackground { const pinStateService = new PinStateService(this.stateProvider); - this.pinService = new PinService( - this.accountService, - this.encryptService, - this.kdfConfigService, - this.keyGenerationService, - this.logService, - this.keyService, - this.sdkService, - pinStateService, - ); - this.appIdService = new AppIdService(this.storageService, this.logService); this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); @@ -756,16 +745,6 @@ export default class MainBackground { VaultTimeoutStringType.OnRestart, // default vault timeout ); - this.biometricsService = new BackgroundBrowserBiometricsService( - runtimeNativeMessagingBackground, - this.logService, - this.keyService, - this.biometricStateService, - this.messagingService, - this.vaultTimeoutSettingsService, - this.pinService, - ); - this.apiService = new ApiService( this.tokenService, this.platformUtilsService, @@ -849,6 +828,27 @@ export default class MainBackground { this.configService, ); + this.pinService = new PinService( + this.accountService, + this.encryptService, + this.kdfConfigService, + this.keyGenerationService, + this.logService, + this.keyService, + this.sdkService, + pinStateService, + ); + + this.biometricsService = new BackgroundBrowserBiometricsService( + runtimeNativeMessagingBackground, + this.logService, + this.keyService, + this.biometricStateService, + this.messagingService, + this.vaultTimeoutSettingsService, + this.pinService, + ); + this.passwordStrengthService = new PasswordStrengthService(); this.passwordGenerationService = legacyPasswordGenerationServiceFactory( diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index 798a7583f85..597babdc777 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -293,14 +293,24 @@ export default class RuntimeBackground { case "openPopup": await this.openPopup(); break; - case VaultMessages.OpenAtRiskPasswords: + case VaultMessages.OpenAtRiskPasswords: { + if (await this.shouldRejectManyOriginMessage(msg)) { + return; + } + await this.main.openAtRisksPasswordsPage(); this.announcePopupOpen(); break; - case VaultMessages.OpenBrowserExtensionToUrl: + } + case VaultMessages.OpenBrowserExtensionToUrl: { + if (await this.shouldRejectManyOriginMessage(msg)) { + return; + } + await this.main.openTheExtensionToPage(msg.url); this.announcePopupOpen(); break; + } case "bgUpdateContextMenu": case "editedCipher": case "addedCipher": @@ -312,10 +322,7 @@ export default class RuntimeBackground { break; } case "authResult": { - const env = await firstValueFrom(this.environmentService.environment$); - const vaultUrl = env.getWebVaultUrl(); - - if (msg.referrer == null || Utils.getHostname(vaultUrl) !== msg.referrer) { + if (!(await this.isValidVaultReferrer(msg.referrer))) { return; } @@ -334,10 +341,7 @@ export default class RuntimeBackground { break; } case "webAuthnResult": { - const env = await firstValueFrom(this.environmentService.environment$); - const vaultUrl = env.getWebVaultUrl(); - - if (msg.referrer == null || Utils.getHostname(vaultUrl) !== msg.referrer) { + if (!(await this.isValidVaultReferrer(msg.referrer))) { return; } @@ -372,6 +376,48 @@ export default class RuntimeBackground { } } + /** + * For messages that can originate from a vault host page or extension, validate referrer or external + * + * @param message + * @returns true if message fails validation + */ + private async shouldRejectManyOriginMessage(message: { + webExtSender: chrome.runtime.MessageSender; + }): Promise { + const isValidVaultReferrer = await this.isValidVaultReferrer( + Utils.getHostname(message?.webExtSender?.origin), + ); + + if (isValidVaultReferrer) { + return false; + } + + return isExternalMessage(message); + } + + /** + * Validates a message's referrer matches the configured web vault hostname. + * + * @param referrer - hostname from message source + * @returns true if referrer matches web vault + */ + private async isValidVaultReferrer(referrer: string | null | undefined): Promise { + if (!referrer) { + return false; + } + + const env = await firstValueFrom(this.environmentService.environment$); + const vaultUrl = env.getWebVaultUrl(); + const vaultHostname = Utils.getHostname(vaultUrl); + + if (!vaultHostname) { + return false; + } + + return vaultHostname === referrer; + } + private async autofillPage(tabToAutoFill: chrome.tabs.Tab) { const totpCode = await this.autofillService.doAutoFill({ tab: tabToAutoFill, diff --git a/apps/browser/src/dirt/phishing-detection/pages/phishing-warning.component.html b/apps/browser/src/dirt/phishing-detection/popup/phishing-warning.component.html similarity index 100% rename from apps/browser/src/dirt/phishing-detection/pages/phishing-warning.component.html rename to apps/browser/src/dirt/phishing-detection/popup/phishing-warning.component.html diff --git a/apps/browser/src/dirt/phishing-detection/pages/phishing-warning.component.ts b/apps/browser/src/dirt/phishing-detection/popup/phishing-warning.component.ts similarity index 93% rename from apps/browser/src/dirt/phishing-detection/pages/phishing-warning.component.ts rename to apps/browser/src/dirt/phishing-detection/popup/phishing-warning.component.ts index 589b880b206..d8e9895237c 100644 --- a/apps/browser/src/dirt/phishing-detection/pages/phishing-warning.component.ts +++ b/apps/browser/src/dirt/phishing-detection/popup/phishing-warning.component.ts @@ -1,8 +1,5 @@ -// eslint-disable-next-line no-restricted-imports import { CommonModule } from "@angular/common"; -// eslint-disable-next-line no-restricted-imports import { Component, inject } from "@angular/core"; -// eslint-disable-next-line no-restricted-imports import { ActivatedRoute, RouterModule } from "@angular/router"; import { firstValueFrom, map } from "rxjs"; diff --git a/apps/browser/src/dirt/phishing-detection/pages/phishing-warning.stories.ts b/apps/browser/src/dirt/phishing-detection/popup/phishing-warning.stories.ts similarity index 97% rename from apps/browser/src/dirt/phishing-detection/pages/phishing-warning.stories.ts rename to apps/browser/src/dirt/phishing-detection/popup/phishing-warning.stories.ts index e79543605c2..32b3c102c36 100644 --- a/apps/browser/src/dirt/phishing-detection/pages/phishing-warning.stories.ts +++ b/apps/browser/src/dirt/phishing-detection/popup/phishing-warning.stories.ts @@ -1,5 +1,3 @@ -// TODO: This needs to be dealt with by moving this folder or updating the lint rule. -/* eslint-disable no-restricted-imports */ import { ActivatedRoute, RouterModule } from "@angular/router"; import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; import { BehaviorSubject, of } from "rxjs"; diff --git a/apps/browser/src/dirt/phishing-detection/pages/protected-by-component.html b/apps/browser/src/dirt/phishing-detection/popup/protected-by-component.html similarity index 100% rename from apps/browser/src/dirt/phishing-detection/pages/protected-by-component.html rename to apps/browser/src/dirt/phishing-detection/popup/protected-by-component.html diff --git a/apps/browser/src/dirt/phishing-detection/pages/protected-by-component.ts b/apps/browser/src/dirt/phishing-detection/popup/protected-by-component.ts similarity index 86% rename from apps/browser/src/dirt/phishing-detection/pages/protected-by-component.ts rename to apps/browser/src/dirt/phishing-detection/popup/protected-by-component.ts index 71cdac89aa2..8da916af5e6 100644 --- a/apps/browser/src/dirt/phishing-detection/pages/protected-by-component.ts +++ b/apps/browser/src/dirt/phishing-detection/popup/protected-by-component.ts @@ -1,6 +1,4 @@ -// eslint-disable-next-line no-restricted-imports import { CommonModule } from "@angular/common"; -// eslint-disable-next-line no-restricted-imports import { Component } from "@angular/core"; import { JslibModule } from "@bitwarden/angular/jslib.module"; diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 1834beb391e..a36396afa1a 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -56,8 +56,8 @@ import { BlockedDomainsComponent } from "../autofill/popup/settings/blocked-doma import { ExcludedDomainsComponent } from "../autofill/popup/settings/excluded-domains.component"; import { NotificationsSettingsComponent } from "../autofill/popup/settings/notifications.component"; import { PremiumV2Component } from "../billing/popup/settings/premium-v2.component"; -import { PhishingWarning } from "../dirt/phishing-detection/pages/phishing-warning.component"; -import { ProtectedByComponent } from "../dirt/phishing-detection/pages/protected-by-component"; +import { PhishingWarning } from "../dirt/phishing-detection/popup/phishing-warning.component"; +import { ProtectedByComponent } from "../dirt/phishing-detection/popup/protected-by-component"; import { RemovePasswordComponent } from "../key-management/key-connector/remove-password.component"; import BrowserPopupUtils from "../platform/browser/browser-popup-utils"; import { popupRouterCacheGuard } from "../platform/popup/view-cache/popup-router-cache.service"; diff --git a/apps/browser/src/popup/services/init.service.ts b/apps/browser/src/popup/services/init.service.ts index 1de1731013d..91b6f0ff105 100644 --- a/apps/browser/src/popup/services/init.service.ts +++ b/apps/browser/src/popup/services/init.service.ts @@ -2,7 +2,7 @@ import { DOCUMENT } from "@angular/common"; import { inject, Inject, Injectable } from "@angular/core"; import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; diff --git a/apps/browser/src/tools/popup/settings/settings-v2.component.html b/apps/browser/src/tools/popup/settings/settings-v2.component.html index a12c5fe005f..683b7d70ed6 100644 --- a/apps/browser/src/tools/popup/settings/settings-v2.component.html +++ b/apps/browser/src/tools/popup/settings/settings-v2.component.html @@ -1,4 +1,19 @@ + + {{ "unlockFeaturesWithPremium" | i18n }} + + + @@ -20,7 +35,7 @@

{{ "autofill" | i18n }}

{ + let account$: BehaviorSubject; + let mockAccountService: Partial; + let mockBillingState: { hasPremiumFromAnySource$: jest.Mock }; + let mockNudges: { + showNudgeBadge$: jest.Mock; + dismissNudge: jest.Mock; + }; + let mockAutofillSettings: { + defaultBrowserAutofillDisabled$: Subject; + isBrowserAutofillSettingOverridden: jest.Mock>; + }; + let dialogService: MockProxy; + let openSpy: jest.SpyInstance; + + beforeEach(waitForAsync(async () => { + dialogService = mock(); + account$ = new BehaviorSubject(null); + mockAccountService = { + activeAccount$: account$ as unknown as AccountService["activeAccount$"], + }; + + mockBillingState = { + hasPremiumFromAnySource$: jest.fn().mockReturnValue(of(false)), + }; + + mockNudges = { + showNudgeBadge$: jest.fn().mockImplementation(() => of(false)), + dismissNudge: jest.fn().mockResolvedValue(undefined), + }; + + mockAutofillSettings = { + defaultBrowserAutofillDisabled$: new BehaviorSubject(false), + isBrowserAutofillSettingOverridden: jest.fn().mockResolvedValue(false), + }; + + jest.spyOn(BrowserApi, "getBrowserClientVendor").mockReturnValue("Chrome"); + + const cfg = TestBed.configureTestingModule({ + imports: [SettingsV2Component, RouterTestingModule], + providers: [ + { provide: AccountService, useValue: mockAccountService }, + { provide: BillingAccountProfileStateService, useValue: mockBillingState }, + { provide: NudgesService, useValue: mockNudges }, + { provide: AutofillBrowserSettingsService, useValue: mockAutofillSettings }, + { provide: DialogService, useValue: dialogService }, + { provide: I18nService, useValue: { t: jest.fn((key: string) => key) } }, + { provide: GlobalStateProvider, useValue: new FakeGlobalStateProvider() }, + { provide: PlatformUtilsService, useValue: mock() }, + { provide: AvatarService, useValue: mock() }, + { provide: AuthService, useValue: mock() }, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }); + + TestBed.overrideComponent(SettingsV2Component, { + add: { + imports: [CurrentAccountStubComponent], + providers: [{ provide: DialogService, useValue: dialogService }], + }, + remove: { + imports: [CurrentAccountComponent], + }, + }); + + await cfg.compileComponents(); + })); + + afterEach(() => { + jest.resetAllMocks(); + }); + + function pushActiveAccount(id = "user-123"): Account { + const acct = { id } as Account; + account$.next(acct); + return acct; + } + + it("shows the premium spotlight when user does NOT have premium", async () => { + mockBillingState.hasPremiumFromAnySource$.mockReturnValue(of(false)); + pushActiveAccount(); + + const fixture = TestBed.createComponent(SettingsV2Component); + fixture.detectChanges(); + await fixture.whenStable(); + + const el: HTMLElement = fixture.nativeElement; + + expect(el.querySelector("bit-spotlight")).toBeTruthy(); + }); + + it("hides the premium spotlight when user HAS premium", async () => { + mockBillingState.hasPremiumFromAnySource$.mockReturnValue(of(true)); + pushActiveAccount(); + + const fixture = TestBed.createComponent(SettingsV2Component); + fixture.detectChanges(); + await fixture.whenStable(); + + const el: HTMLElement = fixture.nativeElement; + expect(el.querySelector("bit-spotlight")).toBeFalsy(); + }); + + it("openUpgradeDialog calls PremiumUpgradeDialogComponent.open with the DialogService", async () => { + openSpy = jest.spyOn(PremiumUpgradeDialogComponent, "open").mockImplementation(); + mockBillingState.hasPremiumFromAnySource$.mockReturnValue(of(false)); + pushActiveAccount(); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + component["openUpgradeDialog"](); + expect(openSpy).toHaveBeenCalledTimes(1); + expect(openSpy).toHaveBeenCalledWith(dialogService); + }); + + it("isBrowserAutofillSettingOverridden$ emits the value from the AutofillBrowserSettingsService", async () => { + pushActiveAccount(); + + mockAutofillSettings.isBrowserAutofillSettingOverridden.mockResolvedValue(true); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + const value = await firstValueFrom(component["isBrowserAutofillSettingOverridden$"]); + expect(value).toBe(true); + + mockAutofillSettings.isBrowserAutofillSettingOverridden.mockResolvedValue(false); + + const fixture2 = TestBed.createComponent(SettingsV2Component); + const component2 = fixture2.componentInstance; + fixture2.detectChanges(); + await fixture2.whenStable(); + + const value2 = await firstValueFrom(component2["isBrowserAutofillSettingOverridden$"]); + expect(value2).toBe(false); + }); + + it("showAutofillBadge$ emits true when default autofill is NOT disabled and nudge is true", async () => { + pushActiveAccount(); + + mockNudges.showNudgeBadge$.mockImplementation((type: NudgeType) => + of(type === NudgeType.AutofillNudge), + ); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + mockAutofillSettings.defaultBrowserAutofillDisabled$.next(false); + + const value = await firstValueFrom(component.showAutofillBadge$); + expect(value).toBe(true); + }); + + it("showAutofillBadge$ emits false when default autofill IS disabled even if nudge is true", async () => { + pushActiveAccount(); + + mockNudges.showNudgeBadge$.mockImplementation((type: NudgeType) => + of(type === NudgeType.AutofillNudge), + ); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + mockAutofillSettings.defaultBrowserAutofillDisabled$.next(true); + + const value = await firstValueFrom(component.showAutofillBadge$); + expect(value).toBe(false); + }); + + it("dismissBadge dismisses when showVaultBadge$ emits true", async () => { + const acct = pushActiveAccount(); + + mockNudges.showNudgeBadge$.mockImplementation((type: NudgeType) => { + return of(type === NudgeType.EmptyVaultNudge); + }); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + await component.dismissBadge(NudgeType.EmptyVaultNudge); + + expect(mockNudges.dismissNudge).toHaveBeenCalledTimes(1); + expect(mockNudges.dismissNudge).toHaveBeenCalledWith(NudgeType.EmptyVaultNudge, acct.id, true); + }); + + it("dismissBadge does nothing when showVaultBadge$ emits false", async () => { + pushActiveAccount(); + + mockNudges.showNudgeBadge$.mockReturnValue(of(false)); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + await component.dismissBadge(NudgeType.EmptyVaultNudge); + + expect(mockNudges.dismissNudge).not.toHaveBeenCalled(); + }); + + it("showDownloadBitwardenNudge$ proxies to nudges service for the active account", async () => { + const acct = pushActiveAccount("user-xyz"); + + mockNudges.showNudgeBadge$.mockImplementation((type: NudgeType) => + of(type === NudgeType.DownloadBitwarden), + ); + + const fixture = TestBed.createComponent(SettingsV2Component); + const component = fixture.componentInstance; + fixture.detectChanges(); + await fixture.whenStable(); + + const val = await firstValueFrom(component.showDownloadBitwardenNudge$); + expect(val).toBe(true); + expect(mockNudges.showNudgeBadge$).toHaveBeenCalledWith(NudgeType.DownloadBitwarden, acct.id); + }); +}); diff --git a/apps/browser/src/tools/popup/settings/settings-v2.component.ts b/apps/browser/src/tools/popup/settings/settings-v2.component.ts index 1c370381f54..95aeeb2f480 100644 --- a/apps/browser/src/tools/popup/settings/settings-v2.component.ts +++ b/apps/browser/src/tools/popup/settings/settings-v2.component.ts @@ -1,21 +1,31 @@ import { CommonModule } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; +import { ChangeDetectionStrategy, Component } from "@angular/core"; import { RouterModule } from "@angular/router"; import { combineLatest, filter, firstValueFrom, + from, map, Observable, shareReplay, switchMap, } from "rxjs"; +import { PremiumUpgradeDialogComponent } from "@bitwarden/angular/billing/components"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { NudgesService, NudgeType } from "@bitwarden/angular/vault"; +import { SpotlightComponent } from "@bitwarden/angular/vault/components/spotlight/spotlight.component"; import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; import { UserId } from "@bitwarden/common/types/guid"; -import { BadgeComponent, ItemModule } from "@bitwarden/components"; +import { + BadgeComponent, + DialogService, + ItemModule, + LinkModule, + TypographyModule, +} from "@bitwarden/components"; import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component"; import { AutofillBrowserSettingsService } from "../../../autofill/services/autofill-browser-settings.service"; @@ -24,8 +34,6 @@ import { PopOutComponent } from "../../../platform/popup/components/pop-out.comp import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ templateUrl: "settings-v2.component.html", imports: [ @@ -38,18 +46,30 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co ItemModule, CurrentAccountComponent, BadgeComponent, + SpotlightComponent, + TypographyModule, + LinkModule, ], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class SettingsV2Component implements OnInit { +export class SettingsV2Component { NudgeType = NudgeType; - activeUserId: UserId | null = null; - protected isBrowserAutofillSettingOverridden = false; + + protected isBrowserAutofillSettingOverridden$ = from( + this.autofillBrowserSettingsService.isBrowserAutofillSettingOverridden( + BrowserApi.getBrowserClientVendor(window), + ), + ); private authenticatedAccount$: Observable = this.accountService.activeAccount$.pipe( filter((account): account is Account => account !== null), shareReplay({ bufferSize: 1, refCount: true }), ); + protected hasPremium$ = this.authenticatedAccount$.pipe( + switchMap((account) => this.accountProfileStateService.hasPremiumFromAnySource$(account.id)), + ); + showDownloadBitwardenNudge$: Observable = this.authenticatedAccount$.pipe( switchMap((account) => this.nudgesService.showNudgeBadge$(NudgeType.DownloadBitwarden, account.id), @@ -79,13 +99,12 @@ export class SettingsV2Component implements OnInit { private readonly nudgesService: NudgesService, private readonly accountService: AccountService, private readonly autofillBrowserSettingsService: AutofillBrowserSettingsService, + private readonly accountProfileStateService: BillingAccountProfileStateService, + private readonly dialogService: DialogService, ) {} - async ngOnInit() { - this.isBrowserAutofillSettingOverridden = - await this.autofillBrowserSettingsService.isBrowserAutofillSettingOverridden( - BrowserApi.getBrowserClientVendor(window), - ); + protected openUpgradeDialog() { + PremiumUpgradeDialogComponent.open(this.dialogService); } async dismissBadge(type: NudgeType) { diff --git a/apps/browser/src/vault/popup/settings/more-from-bitwarden-page-v2.component.html b/apps/browser/src/vault/popup/settings/more-from-bitwarden-page-v2.component.html index a2d01ce752e..a8ed75b5de6 100644 --- a/apps/browser/src/vault/popup/settings/more-from-bitwarden-page-v2.component.html +++ b/apps/browser/src/vault/popup/settings/more-from-bitwarden-page-v2.component.html @@ -6,12 +6,6 @@ - - - {{ "premiumMembership" | i18n }} - - - ; protected familySponsorshipAvailable$: Observable; protected isFreeFamilyPolicyEnabled$: Observable; protected hasSingleEnterpriseOrg$: Observable; constructor( private dialogService: DialogService, - private billingAccountProfileStateService: BillingAccountProfileStateService, private environmentService: EnvironmentService, private organizationService: OrganizationService, private familiesPolicyService: FamiliesPolicyService, @@ -48,13 +45,6 @@ export class MoreFromBitwardenPageV2Component { this.familySponsorshipAvailable$ = getUserId(this.accountService.activeAccount$).pipe( switchMap((userId) => this.organizationService.familySponsorshipAvailable$(userId)), ); - this.canAccessPremium$ = this.accountService.activeAccount$.pipe( - switchMap((account) => - account - ? this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id) - : of(false), - ), - ); this.hasSingleEnterpriseOrg$ = this.familiesPolicyService.hasSingleEnterpriseOrg$(); this.isFreeFamilyPolicyEnabled$ = this.familiesPolicyService.isFreeFamilyPolicyEnabled$(); } diff --git a/apps/cli/package.json b/apps/cli/package.json index fc38440b70f..a7a7bfd0c7b 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -75,7 +75,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.2", + "koa": "2.16.3", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lowdb": "1.0.0", diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index aa43b353f9c..d0ab062d0b3 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -20,7 +20,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; @@ -28,7 +27,7 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request"; import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request/update-temp-password.request"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService, TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; import { ClientType } from "@bitwarden/common/enums"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index ebfb76eab2f..365205a1329 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -49,10 +49,14 @@ import { DefaultActiveUserAccessor } from "@bitwarden/common/auth/services/defau import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; import { MasterPasswordApiService } from "@bitwarden/common/auth/services/master-password/master-password-api.service.implementation"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service"; import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service"; import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service"; -import { TwoFactorApiService, DefaultTwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { + DefaultTwoFactorService, + TwoFactorService, + TwoFactorApiService, + DefaultTwoFactorApiService, +} from "@bitwarden/common/auth/two-factor"; import { AutofillSettingsService, AutofillSettingsServiceAbstraction, @@ -627,10 +631,11 @@ export class ServiceContainer { this.stateProvider, ); - this.twoFactorService = new TwoFactorService( + this.twoFactorService = new DefaultTwoFactorService( this.i18nService, this.platformUtilsService, this.globalStateProvider, + this.twoFactorApiService, ); const sdkClientFactory = flagEnabled("sdk") diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index e8cc9385bb2..a1cdb9f26eb 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -120,9 +120,9 @@ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arboard" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f533f8e0af236ffe5eb979b99381df3258853f00ba2e44b6e1955292c75227" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" dependencies = [ "clipboard-win", "log", @@ -131,6 +131,7 @@ dependencies = [ "objc2-foundation", "parking_lot", "percent-encoding", + "windows-sys 0.60.2", "wl-clipboard-rs", "x11rb", ] @@ -317,9 +318,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -555,10 +556,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.4" +version = "1.2.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -637,9 +639,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -647,9 +649,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -659,9 +661,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", @@ -1203,6 +1205,12 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1666,9 +1674,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index d7afd44e9cd..0b09daa9bdd 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -22,7 +22,7 @@ publish = false aes = "=0.8.4" aes-gcm = "=0.10.3" anyhow = "=1.0.94" -arboard = { version = "=3.6.0", default-features = false } +arboard = { version = "=3.6.1", default-features = false } ashpd = "=0.11.0" base64 = "=0.22.1" bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "a641316227227f8777fdf56ac9fa2d6b5f7fe662" } @@ -39,7 +39,7 @@ futures = "=0.3.31" hex = "=0.4.3" homedir = "=0.3.4" interprocess = "=2.2.1" -libc = "=0.2.172" +libc = "=0.2.177" linux-keyutils = "=0.2.4" memsec = "=0.7.0" napi = "=2.16.17" diff --git a/apps/desktop/desktop_native/bitwarden_chromium_import_helper/Cargo.toml b/apps/desktop/desktop_native/bitwarden_chromium_import_helper/Cargo.toml index 576a7d048fc..6455142023a 100644 --- a/apps/desktop/desktop_native/bitwarden_chromium_import_helper/Cargo.toml +++ b/apps/desktop/desktop_native/bitwarden_chromium_import_helper/Cargo.toml @@ -11,7 +11,7 @@ publish.workspace = true aes-gcm = { workspace = true } chacha20poly1305 = { workspace = true } chromium_importer = { path = "../chromium_importer" } -clap = { version = "=4.5.40", features = ["derive"] } +clap = { version = "=4.5.51", features = ["derive"] } scopeguard = { workspace = true } sysinfo = { workspace = true } windows = { workspace = true, features = [ diff --git a/apps/desktop/desktop_native/chromium_importer/Cargo.toml b/apps/desktop/desktop_native/chromium_importer/Cargo.toml index 4b02079bfdb..9e9a9e0fee8 100644 --- a/apps/desktop/desktop_native/chromium_importer/Cargo.toml +++ b/apps/desktop/desktop_native/chromium_importer/Cargo.toml @@ -8,7 +8,7 @@ publish = { workspace = true } [dependencies] aes = { workspace = true } anyhow = { workspace = true } -async-trait = "=0.1.88" +async-trait = "=0.1.89" dirs = { workspace = true } hex = { workspace = true } rand = { workspace = true } diff --git a/apps/desktop/desktop_native/objc/Cargo.toml b/apps/desktop/desktop_native/objc/Cargo.toml index c161b8226ba..5ef791fb586 100644 --- a/apps/desktop/desktop_native/objc/Cargo.toml +++ b/apps/desktop/desktop_native/objc/Cargo.toml @@ -14,7 +14,7 @@ tokio = { workspace = true } tracing = { workspace = true } [target.'cfg(target_os = "macos")'.build-dependencies] -cc = "=1.2.4" +cc = "=1.2.46" glob = "=0.3.2" [lints] diff --git a/apps/desktop/src/app/services/init.service.ts b/apps/desktop/src/app/services/init.service.ts index ae633bd4a69..73c4d38d3b2 100644 --- a/apps/desktop/src/app/services/init.service.ts +++ b/apps/desktop/src/app/services/init.service.ts @@ -6,7 +6,7 @@ import { AbstractThemingService } from "@bitwarden/angular/platform/services/the import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { DefaultVaultTimeoutService } from "@bitwarden/common/key-management/vault-timeout"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -39,7 +39,7 @@ export class InitService { private vaultTimeoutService: DefaultVaultTimeoutService, private i18nService: I18nServiceAbstraction, private eventUploadService: EventUploadServiceAbstraction, - private twoFactorService: TwoFactorServiceAbstraction, + private twoFactorService: TwoFactorService, private notificationsService: ServerNotificationsService, private platformUtilsService: PlatformUtilsServiceAbstraction, private stateService: StateServiceAbstraction, diff --git a/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts b/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts index e33ab0d4c3b..4dcf05a4220 100644 --- a/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts +++ b/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts @@ -5,6 +5,7 @@ import { LogService } from "@bitwarden/logging"; import { WindowMain } from "../../main/window.main"; import { stringIsNotUndefinedNullAndEmpty } from "../../utils"; +import { AutotypeMatchError } from "../models/autotype-errors"; import { AutotypeVaultData } from "../models/autotype-vault-data"; import { AutotypeKeyboardShortcut } from "../models/main-autotype-keyboard-shortcut"; @@ -56,6 +57,14 @@ export class MainDesktopAutotypeService { this.doAutotype(vaultData, this.autotypeKeyboardShortcut.getArrayFormat()); } }); + + ipcMain.on("autofill.completeAutotypeError", (_event, matchError: AutotypeMatchError) => { + this.logService.debug( + "autofill.completeAutotypeError", + "No match for window: " + matchError.windowTitle, + ); + this.logService.error("autofill.completeAutotypeError", matchError.errorMessage); + }); } disableAutotype() { diff --git a/apps/desktop/src/autofill/models/autotype-errors.ts b/apps/desktop/src/autofill/models/autotype-errors.ts new file mode 100644 index 00000000000..9e59b102302 --- /dev/null +++ b/apps/desktop/src/autofill/models/autotype-errors.ts @@ -0,0 +1,8 @@ +/** + * This error is surfaced when there is no matching + * vault item found. + */ +export interface AutotypeMatchError { + windowTitle: string; + errorMessage: string; +} diff --git a/apps/desktop/src/autofill/preload.ts b/apps/desktop/src/autofill/preload.ts index 22b5cdf9463..e839ac223b7 100644 --- a/apps/desktop/src/autofill/preload.ts +++ b/apps/desktop/src/autofill/preload.ts @@ -5,6 +5,7 @@ import type { autofill } from "@bitwarden/desktop-napi"; import { Command } from "../platform/main/autofill/command"; import { RunCommandParams, RunCommandResult } from "../platform/main/autofill/native-autofill.main"; +import { AutotypeMatchError } from "./models/autotype-errors"; import { AutotypeVaultData } from "./models/autotype-vault-data"; export default { @@ -141,7 +142,7 @@ export default { ipcRenderer.on( "autofill.listenAutotypeRequest", ( - event, + _event, data: { windowTitle: string; }, @@ -150,10 +151,11 @@ export default { fn(windowTitle, (error, vaultData) => { if (error) { - ipcRenderer.send("autofill.completeError", { + const matchError: AutotypeMatchError = { windowTitle, - error: error.message, - }); + errorMessage: error.message, + }; + ipcRenderer.send("autofill.completeAutotypeError", matchError); return; } if (vaultData !== null) { diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index acd5037bb6d..6cca98444b8 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -70,7 +70,7 @@ } }, "noEditPermissions": { - "message": "You don't have permission to edit this item" + "message": "Vous n'avez pas l'autorisation de modifier cet élément" }, "welcomeBack": { "message": "Content de vous revoir" @@ -4195,33 +4195,33 @@ "message": "Numéro de carte" }, "upgradeNow": { - "message": "Upgrade now" + "message": "Mettre à niveau maintenant" }, "builtInAuthenticator": { - "message": "Built-in authenticator" + "message": "Authentificateur intégré" }, "secureFileStorage": { - "message": "Secure file storage" + "message": "Stockage sécurisé de fichier" }, "emergencyAccess": { - "message": "Emergency access" + "message": "Accès d'urgence" }, "breachMonitoring": { - "message": "Breach monitoring" + "message": "Surveillance des fuites" }, "andMoreFeatures": { - "message": "And more!" + "message": "Et encore plus !" }, "planDescPremium": { - "message": "Complete online security" + "message": "Sécurité en ligne complète" }, "upgradeToPremium": { - "message": "Upgrade to Premium" + "message": "Mettre à niveau vers Premium" }, "sessionTimeoutSettingsAction": { - "message": "Timeout action" + "message": "Action à l’expiration" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Délai d'expiration de la session" } } diff --git a/apps/web/project.json b/apps/web/project.json index 4f51bf22740..710fd7cb5e7 100644 --- a/apps/web/project.json +++ b/apps/web/project.json @@ -154,45 +154,15 @@ }, "configurations": { "oss": { - "buildTarget": "web:build:oss" - }, - "oss-dev": { "buildTarget": "web:build:oss-dev" }, "commercial": { - "buildTarget": "web:build:commercial" - }, - "commercial-dev": { "buildTarget": "web:build:commercial-dev" }, - "commercial-qa": { - "buildTarget": "web:build:commercial-qa" - }, - "commercial-cloud": { - "buildTarget": "web:build:commercial-cloud" - }, - "commercial-euprd": { - "buildTarget": "web:build:commercial-euprd" - }, - "commercial-euqa": { - "buildTarget": "web:build:commercial-euqa" - }, - "commercial-usdev": { - "buildTarget": "web:build:commercial-usdev" - }, - "commercial-ee": { - "buildTarget": "web:build:commercial-ee" - }, "oss-selfhost": { - "buildTarget": "web:build:oss-selfhost" - }, - "oss-selfhost-dev": { "buildTarget": "web:build:oss-selfhost-dev" }, "commercial-selfhost": { - "buildTarget": "web:build:commercial-selfhost" - }, - "commercial-selfhost-dev": { "buildTarget": "web:build:commercial-selfhost-dev" } } diff --git a/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts b/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts index 46e39a112bf..95081af3a53 100644 --- a/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts +++ b/apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts @@ -11,16 +11,17 @@ import { } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { DialogRef, DialogService } from "@bitwarden/components"; +import { DialogRef, DialogService, ToastService } from "@bitwarden/components"; import { TwoFactorSetupDuoComponent } from "../../../auth/settings/two-factor/two-factor-setup-duo.component"; import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../../auth/settings/two-factor/two-factor-setup.component"; @@ -37,7 +38,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme tabbedHeader = false; constructor( dialogService: DialogService, - twoFactorApiService: TwoFactorApiService, + twoFactorService: TwoFactorService, messagingService: MessagingService, policyService: PolicyService, private route: ActivatedRoute, @@ -46,16 +47,20 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme protected accountService: AccountService, configService: ConfigService, i18nService: I18nService, + protected userVerificationService: UserVerificationService, + protected toastService: ToastService, ) { super( dialogService, - twoFactorApiService, + twoFactorService, messagingService, policyService, billingAccountProfileStateService, accountService, configService, i18nService, + userVerificationService, + toastService, ); } @@ -118,7 +123,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme } protected getTwoFactorProviders() { - return this.twoFactorApiService.getTwoFactorOrganizationProviders(this.organizationId); + return this.twoFactorService.getTwoFactorOrganizationProviders(this.organizationId); } protected filterProvider(type: TwoFactorProviderType): boolean { diff --git a/apps/web/src/app/auth/settings/account/change-email.component.spec.ts b/apps/web/src/app/auth/settings/account/change-email.component.spec.ts index 934de0f6453..56f2bfe2112 100644 --- a/apps/web/src/app/auth/settings/account/change-email.component.spec.ts +++ b/apps/web/src/app/auth/settings/account/change-email.component.spec.ts @@ -7,7 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { TwoFactorProviderResponse } from "@bitwarden/common/auth/models/response/two-factor-provider.response"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -23,14 +23,14 @@ describe("ChangeEmailComponent", () => { let fixture: ComponentFixture; let apiService: MockProxy; - let twoFactorApiService: MockProxy; + let twoFactorService: MockProxy; let accountService: FakeAccountService; let keyService: MockProxy; let kdfConfigService: MockProxy; beforeEach(async () => { apiService = mock(); - twoFactorApiService = mock(); + twoFactorService = mock(); keyService = mock(); kdfConfigService = mock(); accountService = mockAccountServiceWith("UserId" as UserId); @@ -40,7 +40,7 @@ describe("ChangeEmailComponent", () => { providers: [ { provide: AccountService, useValue: accountService }, { provide: ApiService, useValue: apiService }, - { provide: TwoFactorApiService, useValue: twoFactorApiService }, + { provide: TwoFactorService, useValue: twoFactorService }, { provide: I18nService, useValue: { t: (key: string) => key } }, { provide: KeyService, useValue: keyService }, { provide: MessagingService, useValue: mock() }, @@ -61,7 +61,7 @@ describe("ChangeEmailComponent", () => { describe("ngOnInit", () => { beforeEach(() => { - twoFactorApiService.getTwoFactorProviders.mockResolvedValue({ + twoFactorService.getEnabledTwoFactorProviders.mockResolvedValue({ data: [{ type: TwoFactorProviderType.Email, enabled: true } as TwoFactorProviderResponse], } as ListResponse); }); diff --git a/apps/web/src/app/auth/settings/account/change-email.component.ts b/apps/web/src/app/auth/settings/account/change-email.component.ts index ee29e0c8a9c..3daf2240fb2 100644 --- a/apps/web/src/app/auth/settings/account/change-email.component.ts +++ b/apps/web/src/app/auth/settings/account/change-email.component.ts @@ -8,7 +8,7 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p import { EmailTokenRequest } from "@bitwarden/common/auth/models/request/email-token.request"; import { EmailRequest } from "@bitwarden/common/auth/models/request/email.request"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { UserId } from "@bitwarden/common/types/guid"; @@ -40,7 +40,7 @@ export class ChangeEmailComponent implements OnInit { constructor( private accountService: AccountService, private apiService: ApiService, - private twoFactorApiService: TwoFactorApiService, + private twoFactorService: TwoFactorService, private i18nService: I18nService, private keyService: KeyService, private messagingService: MessagingService, @@ -52,7 +52,7 @@ export class ChangeEmailComponent implements OnInit { async ngOnInit() { this.userId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); - const twoFactorProviders = await this.twoFactorApiService.getTwoFactorProviders(); + const twoFactorProviders = await this.twoFactorService.getEnabledTwoFactorProviders(); this.showTwoFactorEmailWarning = twoFactorProviders.data.some( (p) => p.type === TwoFactorProviderType.Email && p.enabled, ); diff --git a/apps/web/src/app/auth/settings/account/set-account-verify-devices-dialog.component.ts b/apps/web/src/app/auth/settings/account/set-account-verify-devices-dialog.component.ts index 01be46c45b3..97f50df24c8 100644 --- a/apps/web/src/app/auth/settings/account/set-account-verify-devices-dialog.component.ts +++ b/apps/web/src/app/auth/settings/account/set-account-verify-devices-dialog.component.ts @@ -9,7 +9,7 @@ import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-a import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { SetVerifyDevicesRequest } from "@bitwarden/common/auth/models/request/set-verify-devices.request"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { Verification } from "@bitwarden/common/auth/types/verification"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -66,7 +66,7 @@ export class SetAccountVerifyDevicesDialogComponent implements OnInit, OnDestroy private userVerificationService: UserVerificationService, private dialogRef: DialogRef, private toastService: ToastService, - private twoFactorApiService: TwoFactorApiService, + private twoFactorService: TwoFactorService, ) { this.accountService.accountVerifyNewDeviceLogin$ .pipe(takeUntil(this.destroy$)) @@ -76,7 +76,7 @@ export class SetAccountVerifyDevicesDialogComponent implements OnInit, OnDestroy } async ngOnInit() { - const twoFactorProviders = await this.twoFactorApiService.getTwoFactorProviders(); + const twoFactorProviders = await this.twoFactorService.getEnabledTwoFactorProviders(); this.has2faConfigured = twoFactorProviders.data.length > 0; } diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.ts index 20c3c742db6..d93a5947445 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.ts @@ -12,7 +12,7 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p import { DisableTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/disable-two-factor-authenticator.request"; import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/update-two-factor-authenticator.request"; import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -96,7 +96,7 @@ export class TwoFactorSetupAuthenticatorComponent constructor( @Inject(DIALOG_DATA) protected data: AuthResponse, private dialogRef: DialogRef, - twoFactorApiService: TwoFactorApiService, + twoFactorService: TwoFactorService, i18nService: I18nService, userVerificationService: UserVerificationService, private formBuilder: FormBuilder, @@ -108,7 +108,7 @@ export class TwoFactorSetupAuthenticatorComponent protected toastService: ToastService, ) { super( - twoFactorApiService, + twoFactorService, i18nService, platformUtilsService, logService, @@ -158,7 +158,7 @@ export class TwoFactorSetupAuthenticatorComponent request.key = this.key; request.userVerificationToken = this.userVerificationToken; - const response = await this.twoFactorApiService.putTwoFactorAuthenticator(request); + const response = await this.twoFactorService.putTwoFactorAuthenticator(request); await this.processResponse(response); this.onUpdated.emit(true); } @@ -178,7 +178,7 @@ export class TwoFactorSetupAuthenticatorComponent request.type = this.type; request.key = this.key; request.userVerificationToken = this.userVerificationToken; - await this.twoFactorApiService.deleteTwoFactorAuthenticator(request); + await this.twoFactorService.deleteTwoFactorAuthenticator(request); this.enabled = false; this.toastService.showToast({ variant: "success", diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts index 1a476f2206d..b4c8ece92a7 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts @@ -6,7 +6,7 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { UpdateTwoFactorDuoRequest } from "@bitwarden/common/auth/models/request/update-two-factor-duo.request"; import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -67,7 +67,7 @@ export class TwoFactorSetupDuoComponent constructor( @Inject(DIALOG_DATA) protected data: TwoFactorDuoComponentConfig, - twoFactorApiService: TwoFactorApiService, + twoFactorService: TwoFactorService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, logService: LogService, @@ -78,7 +78,7 @@ export class TwoFactorSetupDuoComponent protected toastService: ToastService, ) { super( - twoFactorApiService, + twoFactorService, i18nService, platformUtilsService, logService, @@ -143,12 +143,12 @@ export class TwoFactorSetupDuoComponent let response: TwoFactorDuoResponse; if (this.organizationId != null) { - response = await this.twoFactorApiService.putTwoFactorOrganizationDuo( + response = await this.twoFactorService.putTwoFactorOrganizationDuo( this.organizationId, request, ); } else { - response = await this.twoFactorApiService.putTwoFactorDuo(request); + response = await this.twoFactorService.putTwoFactorDuo(request); } this.processResponse(response); diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts index 4219fb0b687..1402d6b8969 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-email.component.ts @@ -9,7 +9,7 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request"; import { UpdateTwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/update-two-factor-email.request"; import { TwoFactorEmailResponse } from "@bitwarden/common/auth/models/response/two-factor-email.response"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -70,7 +70,7 @@ export class TwoFactorSetupEmailComponent constructor( @Inject(DIALOG_DATA) protected data: AuthResponse, - twoFactorApiService: TwoFactorApiService, + twoFactorService: TwoFactorService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, logService: LogService, @@ -82,7 +82,7 @@ export class TwoFactorSetupEmailComponent protected toastService: ToastService, ) { super( - twoFactorApiService, + twoFactorService, i18nService, platformUtilsService, logService, @@ -135,7 +135,7 @@ export class TwoFactorSetupEmailComponent sendEmail = async () => { const request = await this.buildRequestModel(TwoFactorEmailRequest); request.email = this.email; - this.emailPromise = this.twoFactorApiService.postTwoFactorEmailSetup(request); + this.emailPromise = this.twoFactorService.postTwoFactorEmailSetup(request); await this.emailPromise; this.sentEmail = this.email; }; @@ -145,7 +145,7 @@ export class TwoFactorSetupEmailComponent request.email = this.email; request.token = this.token; - const response = await this.twoFactorApiService.putTwoFactorEmail(request); + const response = await this.twoFactorService.putTwoFactorEmail(request); await this.processResponse(response); this.onUpdated.emit(true); } diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts index ad8d401d3fc..5494353449d 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-method-base.component.ts @@ -5,7 +5,7 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request"; import { TwoFactorProviderRequest } from "@bitwarden/common/auth/models/request/two-factor-provider.request"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponseBase } from "@bitwarden/common/auth/types/auth-response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -32,7 +32,7 @@ export abstract class TwoFactorSetupMethodBaseComponent { protected componentName = ""; constructor( - protected twoFactorApiService: TwoFactorApiService, + protected twoFactorService: TwoFactorService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, protected logService: LogService, @@ -47,58 +47,6 @@ export abstract class TwoFactorSetupMethodBaseComponent { this.authed = true; } - /** @deprecated used for formPromise flows.*/ - protected async enable(enableFunction: () => Promise) { - try { - await enableFunction(); - this.onUpdated.emit(true); - } catch (e) { - this.logService.error(e); - } - } - - /** - * @deprecated used for formPromise flows. - * TODO: Remove this method when formPromises are removed from all flows. - * */ - protected async disable(promise: Promise) { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "disable" }, - content: { key: "twoStepDisableDesc" }, - type: "warning", - }); - - if (!confirmed) { - return; - } - - try { - const request = await this.buildRequestModel(TwoFactorProviderRequest); - if (this.type === undefined) { - throw new Error("Two-factor provider type is required"); - } - request.type = this.type; - if (this.organizationId != null) { - promise = this.twoFactorApiService.putTwoFactorOrganizationDisable( - this.organizationId, - request, - ); - } else { - promise = this.twoFactorApiService.putTwoFactorDisable(request); - } - await promise; - this.enabled = false; - this.toastService.showToast({ - variant: "success", - title: "", - message: this.i18nService.t("twoStepDisabled"), - }); - this.onUpdated.emit(false); - } catch (e) { - this.logService.error(e); - } - } - protected async disableMethod() { const confirmed = await this.dialogService.openSimpleDialog({ title: { key: "disable" }, @@ -116,9 +64,9 @@ export abstract class TwoFactorSetupMethodBaseComponent { } request.type = this.type; if (this.organizationId != null) { - await this.twoFactorApiService.putTwoFactorOrganizationDisable(this.organizationId, request); + await this.twoFactorService.putTwoFactorOrganizationDisable(this.organizationId, request); } else { - await this.twoFactorApiService.putTwoFactorDisable(request); + await this.twoFactorService.putTwoFactorDisable(request); } this.enabled = false; this.toastService.showToast({ diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts index acf83ab278e..11ba5955902 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-webauthn.component.ts @@ -12,7 +12,7 @@ import { ChallengeResponse, TwoFactorWebAuthnResponse, } from "@bitwarden/common/auth/models/response/two-factor-web-authn.response"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -72,7 +72,6 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom webAuthnListening: boolean = false; webAuthnResponse: PublicKeyCredential | null = null; challengePromise: Promise | undefined; - formPromise: Promise | undefined; override componentName = "app-two-factor-webauthn"; @@ -81,7 +80,7 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom constructor( @Inject(DIALOG_DATA) protected data: AuthResponse, private dialogRef: DialogRef, - twoFactorApiService: TwoFactorApiService, + twoFactorService: TwoFactorService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, private ngZone: NgZone, @@ -91,7 +90,7 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom toastService: ToastService, ) { super( - twoFactorApiService, + twoFactorService, i18nService, platformUtilsService, logService, @@ -129,7 +128,7 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom request.id = this.keyIdAvailable; request.name = this.formGroup.value.name || ""; - const response = await this.twoFactorApiService.putTwoFactorWebAuthn(request); + const response = await this.twoFactorService.putTwoFactorWebAuthn(request); this.processResponse(response); this.toastService.showToast({ title: this.i18nService.t("success"), @@ -165,7 +164,7 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom const request = await this.buildRequestModel(UpdateTwoFactorWebAuthnDeleteRequest); request.id = key.id; try { - key.removePromise = this.twoFactorApiService.deleteTwoFactorWebAuthn(request); + key.removePromise = this.twoFactorService.deleteTwoFactorWebAuthn(request); const response = await key.removePromise; key.removePromise = null; await this.processResponse(response); @@ -179,7 +178,7 @@ export class TwoFactorSetupWebAuthnComponent extends TwoFactorSetupMethodBaseCom return; } const request = await this.buildRequestModel(SecretVerificationRequest); - this.challengePromise = this.twoFactorApiService.getTwoFactorWebAuthnChallenge(request); + this.challengePromise = this.twoFactorService.getTwoFactorWebAuthnChallenge(request); const challenge = await this.challengePromise; this.readDevice(challenge); }; diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-yubikey.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-yubikey.component.ts index 09fb1ad308f..a58c659796d 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup-yubikey.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup-yubikey.component.ts @@ -13,7 +13,7 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { UpdateTwoFactorYubikeyOtpRequest } from "@bitwarden/common/auth/models/request/update-two-factor-yubikey-otp.request"; import { TwoFactorYubiKeyResponse } from "@bitwarden/common/auth/models/response/two-factor-yubi-key.response"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -74,9 +74,6 @@ export class TwoFactorSetupYubiKeyComponent keys: Key[] = []; anyKeyHasNfc = false; - formPromise: Promise | undefined; - disablePromise: Promise | undefined; - override componentName = "app-two-factor-yubikey"; formGroup: | FormGroup<{ @@ -95,7 +92,7 @@ export class TwoFactorSetupYubiKeyComponent constructor( @Inject(DIALOG_DATA) protected data: AuthResponse, - twoFactorApiService: TwoFactorApiService, + twoFactorService: TwoFactorService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, logService: LogService, @@ -105,7 +102,7 @@ export class TwoFactorSetupYubiKeyComponent protected toastService: ToastService, ) { super( - twoFactorApiService, + twoFactorService, i18nService, platformUtilsService, logService, @@ -178,7 +175,7 @@ export class TwoFactorSetupYubiKeyComponent request.key5 = keys != null && keys.length > 4 ? (keys[4]?.key ?? "") : ""; request.nfc = this.formGroup.value.anyKeyHasNfc ?? false; - this.processResponse(await this.twoFactorApiService.putTwoFactorYubiKey(request)); + this.processResponse(await this.twoFactorService.putTwoFactorYubiKey(request)); this.refreshFormArrayData(); this.toastService.showToast({ title: this.i18nService.t("success"), diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html index ee2d4dd7b63..69a0dbf4145 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.html @@ -71,15 +71,26 @@
{{ p.description }}
- + @if (p.premium && p.enabled && !(canAccessPremium$ | async)) { + + } @else { + + } diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts index 024455cc1bf..a85bf65ab74 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts @@ -12,26 +12,28 @@ import { } from "rxjs"; import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge"; +import { UserVerificationDialogComponent } from "@bitwarden/auth/angular"; 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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { TwoFactorProviderRequest } from "@bitwarden/common/auth/models/request/two-factor-provider.request"; import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response"; import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response"; import { TwoFactorEmailResponse } from "@bitwarden/common/auth/models/response/two-factor-email.response"; import { TwoFactorWebAuthnResponse } from "@bitwarden/common/auth/models/response/two-factor-web-authn.response"; import { TwoFactorYubiKeyResponse } from "@bitwarden/common/auth/models/response/two-factor-yubi-key.response"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { TwoFactorProviders } from "@bitwarden/common/auth/services/two-factor.service"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService, TwoFactorProviders } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { ProductTierType } from "@bitwarden/common/billing/enums"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { DialogRef, DialogService, ItemModule } from "@bitwarden/components"; +import { DialogRef, DialogService, ItemModule, ToastService } from "@bitwarden/components"; import { HeaderModule } from "../../../layouts/header/header.module"; import { SharedModule } from "../../../shared/shared.module"; @@ -59,7 +61,6 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy { recoveryCodeWarningMessage: string; showPolicyWarning = false; loading = true; - formPromise: Promise; tabbedHeader = true; @@ -69,13 +70,15 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy { constructor( protected dialogService: DialogService, - protected twoFactorApiService: TwoFactorApiService, + protected twoFactorService: TwoFactorService, protected messagingService: MessagingService, protected policyService: PolicyService, billingAccountProfileStateService: BillingAccountProfileStateService, protected accountService: AccountService, protected configService: ConfigService, protected i18nService: I18nService, + protected userVerificationService: UserVerificationService, + protected toastService: ToastService, ) { this.canAccessPremium$ = this.accountService.activeAccount$.pipe( switchMap((account) => @@ -150,6 +153,50 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy { return await lastValueFrom(twoFactorVerifyDialogRef.closed); } + /** + * For users who enabled a premium-only 2fa provider, + * they should still be allowed to disable that provider + * (without otherwise modifying) if they no longer have + * premium access [PM-21204] + * @param type the 2FA Provider Type + */ + async disablePremium2faTypeForNonPremiumUser(type: TwoFactorProviderType) { + // Use UserVerificationDialogComponent instead of TwoFactorVerifyComponent + // because the latter makes GET API calls that require premium for YubiKey/Duo. + // The disable endpoint only requires user verification, not provider configuration. + const result = await UserVerificationDialogComponent.open(this.dialogService, { + title: "twoStepLogin", + verificationType: { + type: "custom", + verificationFn: async (secret) => { + const request = await this.userVerificationService.buildRequest( + secret, + TwoFactorProviderRequest, + ); + request.type = type; + + await this.twoFactorService.putTwoFactorDisable(request); + return true; + }, + }, + }); + + if (result.userAction === "cancel") { + return; + } + + if (!result.verificationSuccess) { + return; + } + + this.toastService.showToast({ + variant: "success", + title: "", + message: this.i18nService.t("twoStepDisabled"), + }); + this.updateStatus(false, type); + } + async manage(type: TwoFactorProviderType) { // clear any existing subscriptions before creating a new one this.twoFactorSetupSubscription?.unsubscribe(); @@ -264,7 +311,7 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy { } protected getTwoFactorProviders() { - return this.twoFactorApiService.getTwoFactorProviders(); + return this.twoFactorService.getEnabledTwoFactorProviders(); } protected filterProvider(type: TwoFactorProviderType): boolean { diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-verify.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-verify.component.ts index 075d3bdf562..04c84ca0197 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-verify.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-verify.component.ts @@ -5,7 +5,7 @@ import { UserVerificationFormInputComponent } from "@bitwarden/auth/angular"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AuthResponse } from "@bitwarden/common/auth/types/auth-response"; import { TwoFactorResponse } from "@bitwarden/common/auth/types/two-factor-response"; import { VerificationWithSecret } from "@bitwarden/common/auth/types/verification"; @@ -54,7 +54,7 @@ export class TwoFactorVerifyComponent { constructor( @Inject(DIALOG_DATA) protected data: TwoFactorVerifyDialogData, private dialogRef: DialogRef, - private twoFactorApiService: TwoFactorApiService, + private twoFactorService: TwoFactorService, private i18nService: I18nService, private userVerificationService: UserVerificationService, ) { @@ -110,22 +110,22 @@ export class TwoFactorVerifyComponent { private apiCall(request: SecretVerificationRequest): Promise { switch (this.type) { case -1 as TwoFactorProviderType: - return this.twoFactorApiService.getTwoFactorRecover(request); + return this.twoFactorService.getTwoFactorRecover(request); case TwoFactorProviderType.Duo: case TwoFactorProviderType.OrganizationDuo: if (this.organizationId != null) { - return this.twoFactorApiService.getTwoFactorOrganizationDuo(this.organizationId, request); + return this.twoFactorService.getTwoFactorOrganizationDuo(this.organizationId, request); } else { - return this.twoFactorApiService.getTwoFactorDuo(request); + return this.twoFactorService.getTwoFactorDuo(request); } case TwoFactorProviderType.Email: - return this.twoFactorApiService.getTwoFactorEmail(request); + return this.twoFactorService.getTwoFactorEmail(request); case TwoFactorProviderType.WebAuthn: - return this.twoFactorApiService.getTwoFactorWebAuthn(request); + return this.twoFactorService.getTwoFactorWebAuthn(request); case TwoFactorProviderType.Authenticator: - return this.twoFactorApiService.getTwoFactorAuthenticator(request); + return this.twoFactorService.getTwoFactorAuthenticator(request); case TwoFactorProviderType.Yubikey: - return this.twoFactorApiService.getTwoFactorYubiKey(request); + return this.twoFactorService.getTwoFactorYubiKey(request); default: throw new Error(`Unknown two-factor type: ${this.type}`); } diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts index 6b03913ef7a..71e3578a7c6 100644 --- a/apps/web/src/app/core/init.service.ts +++ b/apps/web/src/app/core/init.service.ts @@ -6,7 +6,7 @@ import { AbstractThemingService } from "@bitwarden/angular/platform/services/the import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { DefaultVaultTimeoutService } from "@bitwarden/common/key-management/vault-timeout"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -31,7 +31,7 @@ export class InitService { private vaultTimeoutService: DefaultVaultTimeoutService, private i18nService: I18nServiceAbstraction, private eventUploadService: EventUploadServiceAbstraction, - private twoFactorService: TwoFactorServiceAbstraction, + private twoFactorService: TwoFactorService, private keyService: KeyServiceAbstraction, private themingService: AbstractThemingService, private encryptService: EncryptService, diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts index faf1b796b00..88132e56384 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts @@ -30,6 +30,8 @@ import { NavigationProductSwitcherComponent } from "./navigation-switcher.compon selector: "[mockOrgs]", standalone: false, }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix class MockOrganizationService implements Partial { private static _orgs = new BehaviorSubject([]); @@ -49,6 +51,8 @@ class MockOrganizationService implements Partial { selector: "[mockProviders]", standalone: false, }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix class MockProviderService implements Partial { private static _providers = new BehaviorSubject([]); diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts index 4c6af713464..4581f5981e6 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts @@ -30,6 +30,8 @@ import { ProductSwitcherService } from "./shared/product-switcher.service"; selector: "[mockOrgs]", standalone: false, }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix class MockOrganizationService implements Partial { private static _orgs = new BehaviorSubject([]); @@ -49,6 +51,8 @@ class MockOrganizationService implements Partial { selector: "[mockProviders]", standalone: false, }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix class MockProviderService implements Partial { private static _providers = new BehaviorSubject([]); diff --git a/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.spec.ts b/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.spec.ts index a19606f6d9c..b31759a1fe1 100644 --- a/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.spec.ts +++ b/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.spec.ts @@ -166,8 +166,8 @@ describe("BrowserExtensionPromptComponent", () => { it("shows manual open error message", () => { const manualText = fixture.debugElement.query(By.css("p")).nativeElement; - expect(manualText.textContent.trim()).toContain("openExtensionManuallyPart1"); - expect(manualText.textContent.trim()).toContain("openExtensionManuallyPart2"); + expect(manualText.textContent.trim()).toContain("openExtensionFromToolbarPart1"); + expect(manualText.textContent.trim()).toContain("openExtensionFromToolbarPart2"); }); }); }); diff --git a/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.ts b/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.ts index cb927d0848c..505a0df5032 100644 --- a/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.ts +++ b/apps/web/src/app/vault/components/browser-extension-prompt/browser-extension-prompt.component.ts @@ -1,5 +1,5 @@ import { CommonModule, DOCUMENT } from "@angular/common"; -import { Component, Inject, OnDestroy, OnInit } from "@angular/core"; +import { Component, Inject, OnDestroy, OnInit, ChangeDetectionStrategy } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { ActivatedRoute } from "@angular/router"; import { map, Observable, of, tap } from "rxjs"; @@ -14,12 +14,11 @@ import { } from "../../services/browser-extension-prompt.service"; import { ManuallyOpenExtensionComponent } from "../manually-open-extension/manually-open-extension.component"; -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ selector: "vault-browser-extension-prompt", templateUrl: "./browser-extension-prompt.component.html", imports: [CommonModule, I18nPipe, ButtonComponent, IconModule, ManuallyOpenExtensionComponent], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class BrowserExtensionPromptComponent implements OnInit, OnDestroy { protected VaultMessages = VaultMessages; diff --git a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.html b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.html index 22c36e51177..d15cdaa712b 100644 --- a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.html +++ b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.html @@ -1,8 +1,8 @@ -

- {{ "openExtensionManuallyPart1" | i18n }} +

+ {{ "openExtensionFromToolbarPart1" | i18n }} - {{ "openExtensionManuallyPart2" | i18n }} + {{ "openExtensionFromToolbarPart2" | i18n }}

diff --git a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts index 6105aeacf9c..435e847f6e9 100644 --- a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts +++ b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts @@ -1,12 +1,11 @@ -import { Component } from "@angular/core"; +import { Component, ChangeDetectionStrategy } from "@angular/core"; import { BitwardenIcon } from "@bitwarden/assets/svg"; import { IconModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ + changeDetection: ChangeDetectionStrategy.OnPush, selector: "vault-manually-open-extension", templateUrl: "./manually-open-extension.component.html", imports: [I18nPipe, IconModule], diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html index 038c258d4b6..1976321b4ee 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.html @@ -29,10 +29,7 @@ -
+
@@ -40,20 +37,15 @@ {{ (state === SetupExtensionState.Success ? "bitwardenExtensionInstalled" - : "openTheBitwardenExtension" + : "bitwardenExtensionIsInstalled" ) | i18n }}

- {{ - (state === SetupExtensionState.Success - ? "openExtensionToAutofill" - : "bitwardenExtensionInstalledOpenExtension" - ) | i18n - }} + {{ "openExtensionToAutofill" | i18n }}

-

+ +

{{ "gettingStartedWithBitwardenPart1" | i18n }} {{ "gettingStartedWithBitwardenPart2" | i18n }} @@ -73,7 +73,3 @@

- -
- -
diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts index fbf61f9a277..ef67e072116 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts @@ -4,7 +4,6 @@ import { Router, RouterModule } from "@angular/router"; import { BehaviorSubject } from "rxjs"; import { SYSTEM_THEME_OBSERVABLE } from "@bitwarden/angular/services/injection-tokens"; -import { BrowserExtensionIcon } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { DeviceType } from "@bitwarden/common/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -12,7 +11,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { Utils } from "@bitwarden/common/platform/misc/utils"; import { StateProvider } from "@bitwarden/common/platform/state"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; -import { AnonLayoutWrapperDataService } from "@bitwarden/components"; import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; @@ -25,14 +23,12 @@ describe("SetupExtensionComponent", () => { const navigate = jest.fn().mockResolvedValue(true); const openExtension = jest.fn().mockResolvedValue(true); const update = jest.fn().mockResolvedValue(true); - const setAnonLayoutWrapperData = jest.fn(); const extensionInstalled$ = new BehaviorSubject(null); beforeEach(async () => { navigate.mockClear(); openExtension.mockClear(); update.mockClear(); - setAnonLayoutWrapperData.mockClear(); window.matchMedia = jest.fn().mockReturnValue(false); await TestBed.configureTestingModule({ @@ -43,7 +39,6 @@ describe("SetupExtensionComponent", () => { { provide: PlatformUtilsService, useValue: { getDevice: () => DeviceType.UnknownBrowser } }, { provide: SYSTEM_THEME_OBSERVABLE, useValue: new BehaviorSubject("system") }, { provide: ThemeStateService, useValue: { selectedTheme$: new BehaviorSubject("system") } }, - { provide: AnonLayoutWrapperDataService, useValue: { setAnonLayoutWrapperData } }, { provide: AccountService, useValue: { activeAccount$: new BehaviorSubject({ account: { id: "account-id" } }) }, @@ -133,14 +128,6 @@ describe("SetupExtensionComponent", () => { tick(); expect(component["state"]).toBe(SetupExtensionState.ManualOpen); - expect(setAnonLayoutWrapperData).toHaveBeenCalledWith({ - pageTitle: { - key: "somethingWentWrong", - }, - pageIcon: BrowserExtensionIcon, - hideCardWrapper: false, - maxWidth: "md", - }); })); }); }); diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts index 974e73bc91e..809e404f5f1 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts @@ -5,7 +5,7 @@ import { Router, RouterModule } from "@angular/router"; import { firstValueFrom, pairwise, startWith } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { BrowserExtensionIcon, Party } from "@bitwarden/assets/svg"; +import { Party } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -14,7 +14,6 @@ import { StateProvider } from "@bitwarden/common/platform/state"; import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values"; import { getWebStoreUrl } from "@bitwarden/common/vault/utils/get-web-store-url"; import { - AnonLayoutWrapperDataService, ButtonComponent, CenterPositionStrategy, DialogRef, @@ -68,7 +67,6 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { private stateProvider = inject(StateProvider); private accountService = inject(AccountService); private document = inject(DOCUMENT); - private anonLayoutWrapperDataService = inject(AnonLayoutWrapperDataService); protected SetupExtensionState = SetupExtensionState; protected PartyIcon = Party; @@ -144,6 +142,16 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { } } + get showSuccessUI(): boolean { + const successStates = [ + SetupExtensionState.Success, + SetupExtensionState.AlreadyInstalled, + SetupExtensionState.ManualOpen, + ] as string[]; + + return successStates.includes(this.state); + } + /** Opens the add extension later dialog */ addItLater() { this.dialogRef = this.dialogService.open( @@ -161,16 +169,6 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { async openExtension() { await this.webBrowserExtensionInteractionService.openExtension().catch(() => { this.state = SetupExtensionState.ManualOpen; - - // Update the anon layout data to show the proper error design - this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ - pageTitle: { - key: "somethingWentWrong", - }, - pageIcon: BrowserExtensionIcon, - hideCardWrapper: false, - maxWidth: "md", - }); }); } diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts index 981e5703cb3..3b707f2d78c 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/organization-options.component.ts @@ -25,7 +25,6 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -181,13 +180,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { message: this.i18nService.t("unlinkedSso"), }); - const disableAlternateLoginMethodsFlagEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM22110_DisableAlternateLoginMethods, - ); - - if (disableAlternateLoginMethodsFlagEnabled) { - await this.removeEmailFromSsoRequiredCacheIfPresent(); - } + await this.removeEmailFromSsoRequiredCacheIfPresent(); } catch (e) { this.logService.error(e); } @@ -214,13 +207,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy { message: this.i18nService.t("leftOrganization"), }); - const disableAlternateLoginMethodsFlagEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM22110_DisableAlternateLoginMethods, - ); - - if (disableAlternateLoginMethodsFlagEnabled) { - await this.removeEmailFromSsoRequiredCacheIfPresent(); - } + await this.removeEmailFromSsoRequiredCacheIfPresent(); } catch (e) { this.logService.error(e); } diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 2fee7410e93..0aa86168472 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 7dbfa670741..9b8dde78dd6 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 9ff3fc46040..5181906dacc 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -94,7 +94,7 @@ "message": "İrəliləyişi izləmək üçün üzvlərə tapşırıqlar təyin edin" }, "onceYouReviewApplications": { - "message": "Once you review applications and mark them as critical, assign tasks to your members to change their passwords." + "message": "Tətbiqləri incələyib kritik olaraq işarələdikdən sonra, üzvlərə parollarını dəyişməsi üçün tapşırıqlar təyin edin." }, "sendReminders": { "message": "Xatırlatma göndər" @@ -179,34 +179,34 @@ } }, "noDataInOrgTitle": { - "message": "No data found" + "message": "Heç bir veri tapılmadı" }, "noDataInOrgDescription": { - "message": "Import your organization's login data to get started with Access Intelligence. Once you do that, you'll be able to:" + "message": "Access Intelligence-i istifadə etməyə başlamaq üçün təşkilatınızın giriş verilərini daxilə köçürün. Bunu etdikdən sonra, bunları edə biləcəksiniz:" }, "feature1Title": { - "message": "Mark applications as critical" + "message": "Tətbiqləri kritik olaraq işarələmə" }, "feature1Description": { - "message": "This will help you remove risks to your most important applications first." + "message": "Bu, əvvəlcə ən vacib tətbiqlərinizdəki riskləri xaric etməyinizə kömək edəcək." }, "feature2Title": { - "message": "Help members improve their security" + "message": "Üzvlərin təhlükəsizliyini təkmilləşdirməsinə kömək" }, "feature2Description": { - "message": "Assign at-risk members guided security tasks to update credentials." + "message": "Riskli üzvlərə kimlik məlumatlarını güncəlləməsi üçün təhlükəsizlik tapşırıqları təyin edin." }, "feature3Title": { - "message": "Monitor progress" + "message": "İrəliləyişin monitorinqi" }, "feature3Description": { - "message": "Track changes over time to show security improvements." + "message": "Təhlükəsizlik təkmilləşdirmələrini göstərmək üçün zamanla dəyişiklikləri izləyin." }, "noReportsRunTitle": { - "message": "Generate report" + "message": "Hesabat yaratma" }, "noReportsRunDescription": { - "message": "You’re ready to start generating reports. Once you generate, you’ll be able to:" + "message": "Hesabatın hazırlanmasına başlaya bilərsiniz. Hazırladıqdan sonra, bunları edə biləcəksiniz:" }, "noCriticalApplicationsTitle": { "message": "Heç bir tətbiqi kritik olaraq işarələməmisiniz" @@ -266,13 +266,13 @@ "message": "Riskli üzvlər" }, "membersWithAccessToAtRiskItemsForCriticalApplications": { - "message": "These members have access to vulnerable items for critical applications." + "message": "Bu üzvlər, kritik tətbiqlər üçün müdafiəsiz elementlərə erişə bilər." }, "membersWithAtRiskPasswords": { "message": "Riskli parollara sahib üzvlər" }, "membersWillReceiveSecurityTask": { - "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." + "message": "Təşkilatınızdakı üzvlərə, təhlükəsizlik boşluğu mövcud olan parolları dəyişdirməsi üçün bir tapşırıq təyin ediləcək. Üzvlər, Bitwarden brauzer uzantılarında bir bildiriş alacaq." }, "membersAtRiskCount": { "message": "$COUNT$ üzv risk altındadır", @@ -302,7 +302,7 @@ } }, "atRiskMemberDescription": { - "message": "These members are logging into critical applications with weak, exposed, or reused passwords." + "message": "Bu üzvlər, kritik tətbiqlərə zəif, ifşa olunmuş və ya təkrar istifadə olunan parollarla giriş edir." }, "atRiskMembersDescriptionNone": { "message": "Tətbiqlərə zəif, ifşa olunmuş və ya təkrar istifadə olunan parollarla giriş edən üzv yoxdur." @@ -344,7 +344,7 @@ "message": "İncələmə gözləyən müraciətlər" }, "newApplicationsCardTitle": { - "message": "Review new applications" + "message": "Yeni tətbiqləri incələ" }, "newApplicationsWithCount": { "message": "$COUNT$ yeni müraciət", @@ -386,7 +386,7 @@ "message": "Kritik tətbiqləri prioritetləşdir" }, "selectCriticalAppsDescription": { - "message": "Select which applications are most critical to your organization. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Təşkilatınız üçün ən kritik sayılan tətbiqləri seçin. Daha sonra, riskləri aradan qaldırmaları üçün üzvlərə təhlükəsizlik tapşırıqları təyin edə biləcəksiniz." }, "reviewNewApplications": { "message": "Yeni tətbiqlər incələ" @@ -5809,9 +5809,9 @@ "message": "Bütün elementlərin bir təşkilata məxsus olmasını tələb et və elementlərin hesab səviyyəsində saxlanılma seçimini ləğv et.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Bütün elementlər bir təşkilata məxsus olacaq və orada saxlanılacaq, bu da təşkilat üzrə kontrollar, görünürlük və hesabatları mümkün edəcək. İşə salındığı zaman, hər üzv üçün elementləri saxlaya biləcəyi ilkin bir kolleksiya mövcud olacaq. Daha ətraflı ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "daha ətraflı öyrənin", @@ -6668,7 +6668,7 @@ "message": "This option will save your members' encryption keys on their devices. If you choose this option, ensure that their devices are adequately protected." }, "learnMoreAboutDeviceProtection": { - "message": "Learn more about device protection" + "message": "Cihaz mühafizəsi barədə daha ətraflı" }, "sessionTimeoutConfirmationOnSystemLockTitle": { "message": "\"System lock\" will only apply to the browser and desktop app" @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Ödənişsiz Ailələr sınağını başlat" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Seyf vaxt bitmə əməliyyatınızı dəyişdirmək üçün bir kilid açma üsulu qurun." }, diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index e562c39ea7f..59d5d49ab1d 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index 1f897b5d74e..eb926015996 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -5809,9 +5809,9 @@ "message": "Изискване на всички елементи да бъдат притежавани от организация, премахвайки възможността за съхраняване на елементи в отделен акаунт.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Всички елементи ще се притежават от и съхраняват в организацията, което ще означава, че управлението, видимостта и докладите ще се извършват от организацията. Когато това и включено, всеки член ще може да съхранява елементите си в стандартна колекция. Научете повече относно управлението на ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "жизнения цикъл на данните за удостоверяване", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Започнете безплатния пробен период на Семейния план" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Задайте метод за отключване, за да може да промените действието при изтичане на времето за достъп до трезора." }, diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index 67fddc7d6e0..300f0bcd8f3 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index cae2a248d0a..3dc0ab7494c 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 77204835dbe..35db86e2b28 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index ccb2172dbf6..5693a5fc824 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -5809,9 +5809,9 @@ "message": "Vyžaduje, aby byly všechny položky vlastněny organizací s odebráním volby ukládat položky na úrovni účtu.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { + "organizationDataOwnershipDescContent": { "message": "Všechny položky budou vlastněny a uloženy v organizaci, což umožní organizaci ovládání, viditelnost a hlášení. Pokud je zapnuto, bude k dispozici výchozí sbírka pro každého člena pro ukládání položek. Další informace o správě ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "životního cyklu pověření", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Zahájit bezplatnou zkušební verzi pro rodiny" }, + "blockClaimedDomainAccountCreation": { + "message": "Blokovat vytvoření účtu pro nárokované domény" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Zabrání uživatelům ve vytváření účtů mimo Vaši organizaci pomocí e-mailových adres z nárokovaných domén." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "Před aktivací této zásady musí být nárokována doména." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Nastavte metodu odemknutí, abyste změnili časový limit Vašeho trezoru." }, diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index c140204619e..2b0222d7096 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index cc2a58aa27d..dee490c39e9 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 073126da446..4a83f8becc8 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -5809,9 +5809,9 @@ "message": "Verlangen, dass alle Einträge Eigentum einer Organisation sein müssen, wodurch die Möglichkeit, Einträge auf Kontoebene zu speichern, entfällt.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Alle Einträge sind Eigentum der Organisation und werden in ihr gespeichert, was eine organisationsweite Kontrolle, Sichtbarkeit und Berichterstattung ermöglicht. Wenn diese Funktion aktiviert ist, steht jedem Mitglied eine Standardsammlung zur Verfügung, in der es Einträge speichern kann. Erfahre mehr über die Verwaltung des ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "Zugangsdaten-Lebenszyklus", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Kostenlose Families-Testversion starten" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Richte eine Entsperrmethode ein, um deine Aktion bei Tresor-Timeout zu ändern." }, diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 606d10fa600..5e937df4a21 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 5cf1bea6fd8..90468c61d5c 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -11351,14 +11351,6 @@ "openedExtensionViewAtRiskPasswords": { "message": "Successfully opened the Bitwarden browser extension. You can now review your at-risk passwords." }, - "openExtensionManuallyPart1": { - "message": "We had trouble opening the Bitwarden browser extension. Open the Bitwarden icon", - "description": "This will be used as part of a larger sentence, broken up to include the Bitwarden icon. The full sentence will read 'We had trouble opening the Bitwarden browser extension. Open the Bitwarden icon [Bitwarden Icon] from the toolbar.'" - }, - "openExtensionManuallyPart2": { - "message": "from the toolbar.", - "description": "This will be used as part of a larger sentence, broken up to include the Bitwarden icon. The full sentence will read 'We had trouble opening the Bitwarden browser extension. Open the Bitwarden icon [Bitwarden Icon] from the toolbar.'" - }, "resellerRenewalWarningMsg": { "message": "Your subscription will renew soon. To ensure uninterrupted service, contact $RESELLER$ to confirm your renewal before $RENEWAL_DATE$.", "placeholders": { @@ -11679,11 +11671,8 @@ "bitwardenExtensionInstalled": { "message": "Bitwarden extension installed!" }, - "openTheBitwardenExtension": { - "message": "Open the Bitwarden extension" - }, - "bitwardenExtensionInstalledOpenExtension": { - "message": "The Bitwarden extension is installed! Open the extension to log in and start autofilling." + "bitwardenExtensionIsInstalled": { + "message": "Bitwarden extension is installed!" }, "openExtensionToAutofill": { "message": "Open the extension to log in and start autofilling." @@ -11699,6 +11688,14 @@ "message": "Learning Center", "description": "This will be displayed as part of a larger sentence. The whole sentence reads: 'For tips on getting started with Bitwarden visit the Learning Center and Help Center'" }, + "openExtensionFromToolbarPart1": { + "message": "If the extension didn't open, you may need to open Bitwarden from the icon ", + "description": "This will be used as part of a larger sentence, broken up to include the Bitwarden icon. The full sentence will read 'If the extension didn't open, you may need to open Bitwarden from the icon [Bitwarden Icon] on the toolbar.'" + }, + "openExtensionFromToolbarPart2": { + "message": " on the toolbar.", + "description": "This will be used as part of a larger sentence, broken up to include the Bitwarden icon. The full sentence will read 'If the extension didn't open, you may need to open Bitwarden from the icon [Bitwarden Icon] on the toolbar.'" + }, "gettingStartedWithBitwardenPart3": { "message": "Help Center", "description": "This will be displayed as part of a larger sentence. The whole sentence reads: 'For tips on getting started with Bitwarden visit the Learning Center and Help Center'" @@ -12178,5 +12175,8 @@ }, "confirmNoSelectedCriticalApplicationsDesc": { "message": "Are you sure you want to continue?" + }, + "userVerificationFailed": { + "message": "User verification failed." } } diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 2f40b6fa13d..7e0f79f9a11 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -182,7 +182,7 @@ "message": "No data found" }, "noDataInOrgDescription": { - "message": "Import your organization's login data to get started with Access Intelligence. Once you do that, you'll be able to:" + "message": "Import your organisation's login data to get started with Access Intelligence. Once you do that, you'll be able to:" }, "feature1Title": { "message": "Mark applications as critical" @@ -272,7 +272,7 @@ "message": "Members with at-risk passwords" }, "membersWillReceiveSecurityTask": { - "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." + "message": "Members of your organisation will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." }, "membersAtRiskCount": { "message": "$COUNT$ members at-risk", @@ -386,7 +386,7 @@ "message": "Prioritise critical applications" }, "selectCriticalAppsDescription": { - "message": "Select which applications are most critical to your organization. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Select which applications are most critical to your organisation. Then, you’ll be able to assign security tasks to members to remove risks." }, "reviewNewApplications": { "message": "Review new applications" @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organisation, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organisation, enabling organisation-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organisation, enabling organisation-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside your organisation using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 180b90cf878..864f66ade8e 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -182,7 +182,7 @@ "message": "No data found" }, "noDataInOrgDescription": { - "message": "Import your organization's login data to get started with Access Intelligence. Once you do that, you'll be able to:" + "message": "Import your organisation's login data to get started with Access Intelligence. Once you do that, you'll be able to:" }, "feature1Title": { "message": "Mark applications as critical" @@ -272,7 +272,7 @@ "message": "Members with at-risk passwords" }, "membersWillReceiveSecurityTask": { - "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." + "message": "Members of your organisation will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." }, "membersAtRiskCount": { "message": "$COUNT$ members at-risk", @@ -386,7 +386,7 @@ "message": "Prioritise critical applications" }, "selectCriticalAppsDescription": { - "message": "Select which applications are most critical to your organization. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Select which applications are most critical to your organisation. Then, you’ll be able to assign security tasks to members to remove risks." }, "reviewNewApplications": { "message": "Review new applications" @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organisation, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organisation, enabling organisation-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organisation, enabling organisation-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside your organisation using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 94fd92f45c9..3ec660dc5b2 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index be77b075923..b69c4ebf822 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 2dddfda1bb6..f96af492352 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index 785ba6e2e0d..20aec32c796 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index 71da2a1b8ba..56aa148b77a 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index b735280c312..a1332427b09 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index f91cf0d9bf0..9935386d012 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index d97fca90d57..db3aa3090b1 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -94,7 +94,7 @@ "message": "Affecter des tâches aux membres pour surveiller la progression" }, "onceYouReviewApplications": { - "message": "Once you review applications and mark them as critical, assign tasks to your members to change their passwords." + "message": "Une fois que vous passez en revue les demandes et que vous les marquez comme critiques, attribuez des tâches à vos membres pour changer leurs mots de passe." }, "sendReminders": { "message": "Envoyer des rappels" @@ -179,34 +179,34 @@ } }, "noDataInOrgTitle": { - "message": "No data found" + "message": "Aucune donnée n’a été trouvée" }, "noDataInOrgDescription": { - "message": "Import your organization's login data to get started with Access Intelligence. Once you do that, you'll be able to:" + "message": "Importez les données de connexion de votre organisation pour commencer avec Intelligence. Une fois que vous aurez fait cela, vous pourrez :" }, "feature1Title": { - "message": "Mark applications as critical" + "message": "Marquer les applications comme critiques" }, "feature1Description": { - "message": "This will help you remove risks to your most important applications first." + "message": "Cela vous aidera à éliminer les risques pour vos applications les plus importantes en premier." }, "feature2Title": { - "message": "Help members improve their security" + "message": "Aider les membres à améliorer leur sécurité" }, "feature2Description": { - "message": "Assign at-risk members guided security tasks to update credentials." + "message": "Assigner des membres à risque des tâches de sécurité guidées pour mettre à jour les identifiants." }, "feature3Title": { - "message": "Monitor progress" + "message": "Suivre la progression" }, "feature3Description": { - "message": "Track changes over time to show security improvements." + "message": "Suivez les changements au fil du temps pour afficher les améliorations de sécurité." }, "noReportsRunTitle": { - "message": "Generate report" + "message": "Générer un rapport" }, "noReportsRunDescription": { - "message": "You’re ready to start generating reports. Once you generate, you’ll be able to:" + "message": "Vous êtes prêt à commencer à générer des rapports. Une fois que vous en aurez généré, vous pourrez :" }, "noCriticalApplicationsTitle": { "message": "Vous n'avez marqué aucune application comme critique" @@ -266,13 +266,13 @@ "message": "Membres à risque" }, "membersWithAccessToAtRiskItemsForCriticalApplications": { - "message": "These members have access to vulnerable items for critical applications." + "message": "Ces membres ont accès à des éléments vulnérables pour des applications critiques." }, "membersWithAtRiskPasswords": { "message": "Membres avec des mots de passe à risque" }, "membersWillReceiveSecurityTask": { - "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." + "message": "Les membres de votre organisation seront assignés à une tâche pour changer les mots de passe vulnérables. Ils recevront une notification dans leur extension de navigateur Bitwarden." }, "membersAtRiskCount": { "message": "$COUNT$ membres à risque", @@ -302,7 +302,7 @@ } }, "atRiskMemberDescription": { - "message": "These members are logging into critical applications with weak, exposed, or reused passwords." + "message": "Ces membres se connectent à des applications critiques avec des mots de passe faibles, exposés ou réutilisés." }, "atRiskMembersDescriptionNone": { "message": "Aucun membre ne se connecte dans des applications avec des mots de passe faibles, exposés ou réutilisés." @@ -386,13 +386,13 @@ "message": "Prioriser les applications critiques" }, "selectCriticalAppsDescription": { - "message": "Select which applications are most critical to your organization. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Sélectionnez les applications les plus importantes pour votre organisation. Ensuite, vous pourrez assigner des tâches de sécurité aux membres pour supprimer les risques." }, "reviewNewApplications": { "message": "Examiner les nouvelles applications" }, "reviewNewAppsDescription": { - "message": "Review new applications with vulnerable items and mark those you’d like to monitor closely as critical. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Examinez les nouvelles applications avec des éléments vulnérables et marquez celles que vous souhaitez surveiller de près comme étant critiques. Ensuite, vous pourrez assigner des tâches de sécurité aux membres pour supprimer les risques." }, "clickIconToMarkAppAsCritical": { "message": "Cliquez sur l'icône étoile pour marquer une application comme critique" @@ -5809,9 +5809,9 @@ "message": "Exiger que tous les éléments appartiennent à une organisation, en supprimant la possibilité de sauvegarder des éléments au niveau du compte.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Tous les éléments seront détenus et enregistrés dans l'organisation, ce qui activera les contrôles, la visibilité et les rapports à l'échelle de l'organisation. Quand activé, une collection par défaut est disponible pour chaque membre pour enregistrer des éléments. En savoir plus sur la gestion de ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "Tous les éléments seront détenus et enregistrés dans l'organisation, ce qui activera les contrôles, la visibilité et les rapports à l'échelle de l'organisation. Une fois activé, une collection par défaut sera disponible pour chaque membre pour enregistrer des éléments. En savoir plus sur la gestion de ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "cycle de vie des identifiants", @@ -9851,7 +9851,7 @@ "message": "Assigner des tâches" }, "assignSecurityTasksToMembers": { - "message": "Send notifications to change passwords" + "message": "Envoyer des notifications pour modifier les mots de passe" }, "assignToCollections": { "message": "Assigner aux collections" @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Commencez l'essai gratuit au forfait Familles" }, + "blockClaimedDomainAccountCreation": { + "message": "Bloquer la création de compte pour les domaines réclamés" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Empêcher les utilisateurs de créer des comptes en dehors de votre organisation en utilisant les adresses courriel des domaines revendiqués." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "Un domaine doit être réclamé avant d'activer cette politique de sécurité." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Configurez une méthode de déverrouillage pour changer le délai d'expiration de votre coffre." }, diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index c9fc10749d7..5ff4117909b 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 5eb5c7969ee..f5f8bfd3c78 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -5809,9 +5809,9 @@ "message": "דרוש שכל הפריטים יהיו בבעלות ארגון, מה שמסיר את האפשרות לאחסן פריטים ברמת החשבון.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "כל הפריטים יהיו בבעלות הארגון ויישמרו בו, מה שמאפשר בקרות, נראות, ודיווח כלל־ארגוניות. כאשר אפשרות זו מופעלת, אוסף ברירת מחדל יהיה זמין עבור כל חבר כדי לאחסן פריטים. למד עוד על ניהול ה", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "מחזור החיים של אישורים", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "התחל ניסיון משפחות בחינם" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "הגדר שיטת ביטול נעילה כדי לשנות את פעולת פסק הזמן לכספת שלך." }, diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 766c6c3e8bd..b3ecb676b4d 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index a0dbd290ab3..26a784acf5c 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -5809,9 +5809,9 @@ "message": "Zahtijevaj da su sve stavke u vlasništvu organizacije čime se onemogućuje spremanje stavki na osobnoj razini.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Sve će stavke biti u vlasništvu i spremljene u organizaciji, što će omogućiti kontrolu, vidljivost i izvještavanje na razini cijele organizacije. Kada je uključeno, svakom će članu biti dostupna zadana kolekcija za pohranu stavki. Saznaj više o upravljanju ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "životnim ciklusom vjerodajnica", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Započni besplatno probno razdoblje za Families" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Postavi metodu otključavanja za promjenu radnje nakon isteka vremenskog ograničenja trezora." }, diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index df292a29c02..82a892eb094 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -5809,9 +5809,9 @@ "message": "Szükséges, hogy minden elem egy szervezet tulajdonában legyen, megújítva a fiókszintű elemek tárolásának lehetőségét.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { + "organizationDataOwnershipDescContent": { "message": "Minden elem a szervezet tulajdonába és elmentésre kerül, lehetővé téve az egész szervezetre kiterjedő vezérlést, láthatóságot és jelentést. Ha be van kapcsolva, minden tag számára elérhető egy alapértelmezett gyűjtemény az elemek tárolására. Tudjunk meg többet a kezelésről:", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "hitelesítő életciklus", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Az ingyenes Családok próbaverzió elindítása" }, + "blockClaimedDomainAccountCreation": { + "message": "Fiók létrehozásának letiltása az igényelt tartományokhoz" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Megakadályozza, hogy a felhasználók a szervezetén kívül fiókokat hozzanak létre az igényelt tartományokból származó email címek használatával." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A házirend aktiválása előtt egy tartományt igényelni kell." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Állítsunk be egy feloldási módot a széf időkifutási műveletének módosításához." }, diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 388ca3ba9cf..86b9356ac08 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index b60e8f4584a..ffc82cfcb4f 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -5809,9 +5809,9 @@ "message": "Richiede che tutti gli elementi siano di proprietà di un'organizzazione. Disabilita per memorizzare gli elementi a livello di account personale.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Tutti gli elementi saranno posseduti e memorizzati dall'organizzazione, e saranno disponibili controlli, visibilità e reporting. Quando attivato, è disponibile una raccolta predefinita per ogni utente. Per sapere di più sulla gestione del ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "ciclo di vita delle credenziali", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index eed4085320d..66f30f93f96 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index b64d882bb03..c4069973d90 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 9f57ed8c6ca..b23e2e3cbac 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 41017933852..49d834e9cae 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 971a2ee59ae..33d812d1537 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index ba978730477..9b1b54cf0b5 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -5809,9 +5809,9 @@ "message": "Visiem vienumiem jāpieder apvienībai, tādējādi noņemot iespēju glabāt tos konta līmenī.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Uzsākt ģimenes plāna bezmaksas izmēģinājumu" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Jāuzstāda atslēgšanas veids, lai mainītu glabātavas noildzes darbību." }, diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 14f5b921ce7..1632226b9ce 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index a7a1e405ed7..b71d94fe31e 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index 9f57ed8c6ca..b23e2e3cbac 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 345d875875c..33ff6b1fb58 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 8387c568e94..d87792ef4b5 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 35d61fc7ce3..0d8840a1889 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -5809,9 +5809,9 @@ "message": "Verplicht dat items eigendom zijn van een organisatie, dit verwijdert de mogelijkheid van het opslaan van items op accountniveau.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Alle items worden eigendom en opgeslagen bij de organisatie, wat organisatiebrede controle, zichtbaarheid en rapportage mogelijk maakt. Bij inschakelen is er een standaardcollectie beschikbaar voor elk lid voor het opslaan van items. Meer informatie over het beheren van de ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "Alle items worden eigendom van en opgeslagen bij de organisatie, wat organisatiebrede controle, zichtbaarheid en rapportage mogelijk maakt. Bij inschakelen is er een standaardcollectie beschikbaar voor elk lid voor het opslaan van items. Meer informatie over het beheren van de ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "levenscyclus van inloggegevens", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start gratis Families-proefperiode" }, + "blockClaimedDomainAccountCreation": { + "message": "Blokkeer het aanmaken van een account voor geclaimde domeinen" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Voorkom dat gebruikers buiten je organisatie accounts aanmaken met behulp van e-mailadressen van geclaimde domeinen." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "Voordat dit beleid geactiveerd kan worden, moet je een domein claimen." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Stel een ontgrendelingsmethode in om je kluis time-out actie te wijzigen." }, diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 4979a3eb72a..2777a14d5c7 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index 9f57ed8c6ca..b23e2e3cbac 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 48f25c451ae..38b7fb51de3 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 4520e190b53..09dd1b14c4a 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -5809,9 +5809,9 @@ "message": "Exigir que todos os itens sejam propriedade de uma organização, removendo a opção de armazenar itens ao nível da conta.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Todos os itens serão propriedade e salvos na organização, ativando controles, visibilidade, e relatórios em toda a organização. Ao ativar, a coleção padrão estará disponível para que cada membro possa armazenar itens. Aprenda mais sobre gerenciar o", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "ciclo de vida credencial", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 4831f14d694..4e240bafc19 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -15,7 +15,7 @@ "message": "Não há aplicações críticas em risco" }, "accessIntelligence": { - "message": "Aceder à informação" + "message": "Inteligência de Acesso" }, "passwordRisk": { "message": "Risco da palavra-passe" @@ -182,31 +182,31 @@ "message": "Não foram encontrados dados" }, "noDataInOrgDescription": { - "message": "Import your organization's login data to get started with Access Intelligence. Once you do that, you'll be able to:" + "message": "Importe os dados de início de sessão da sua organização para começar a utilizar a Inteligência de Acesso. Depois disso, poderá:" }, "feature1Title": { - "message": "Mark applications as critical" + "message": "Marcar aplicações como críticas" }, "feature1Description": { - "message": "This will help you remove risks to your most important applications first." + "message": "Isto ajudá-lo-á a eliminar primeiro os riscos nas suas aplicações mais importantes." }, "feature2Title": { - "message": "Help members improve their security" + "message": "Ajude os membros a melhorar a sua segurança" }, "feature2Description": { - "message": "Assign at-risk members guided security tasks to update credentials." + "message": "Atribua aos membros em risco tarefas de segurança orientadas para atualizarem as suas credenciais." }, "feature3Title": { - "message": "Monitor progress" + "message": "Monitorizar o progresso" }, "feature3Description": { - "message": "Track changes over time to show security improvements." + "message": "Acompanhe as alterações ao longo do tempo para mostrar as melhorias na segurança." }, "noReportsRunTitle": { - "message": "Generate report" + "message": "Gerar relatório" }, "noReportsRunDescription": { - "message": "You’re ready to start generating reports. Once you generate, you’ll be able to:" + "message": "Está pronto para começar a gerar relatórios. Depois de os gerar, poderá:" }, "noCriticalApplicationsTitle": { "message": "Não marcou nenhuma aplicação como crítica" @@ -266,13 +266,13 @@ "message": "Membros em risco" }, "membersWithAccessToAtRiskItemsForCriticalApplications": { - "message": "These members have access to vulnerable items for critical applications." + "message": "Estes membros têm acesso a itens vulneráveis de aplicações críticas." }, "membersWithAtRiskPasswords": { "message": "Membros com palavras-passe em risco" }, "membersWillReceiveSecurityTask": { - "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." + "message": "Os membros da sua organização serão atribuídos a uma tarefa para alterar palavras-passe vulneráveis. Receberão uma notificação na extensão do Bitwarden do navegador." }, "membersAtRiskCount": { "message": "$COUNT$ membros em risco", @@ -302,7 +302,7 @@ } }, "atRiskMemberDescription": { - "message": "These members are logging into critical applications with weak, exposed, or reused passwords." + "message": "Estes membros estão a iniciar sessão em aplicações críticas com palavras-passe fracas, expostas ou reutilizadas." }, "atRiskMembersDescriptionNone": { "message": "Estes não são membros que iniciam sessão em aplicações com palavras-passe fracas, expostas ou reutilizadas." @@ -386,13 +386,13 @@ "message": "Dê prioridade a aplicações críticas" }, "selectCriticalAppsDescription": { - "message": "Select which applications are most critical to your organization. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Selecione quais aplicações são mais críticas para a sua organização. Depois, poderá atribuir tarefas de segurança aos membros para eliminar os riscos." }, "reviewNewApplications": { "message": "Rever novas aplicações" }, "reviewNewAppsDescription": { - "message": "Review new applications with vulnerable items and mark those you’d like to monitor closely as critical. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "Reveja as novas aplicações com itens vulneráveis e marque como críticas aquelas que pretende monitorizar de perto. Depois, poderá atribuir tarefas de segurança aos membros para eliminar os riscos." }, "clickIconToMarkAppAsCritical": { "message": "Clique no ícone de estrela para marcar uma app como crítica" @@ -5809,9 +5809,9 @@ "message": "Exigir que todos os itens sejam propriedade de uma organização, removendo a opção de armazenar itens ao nível da conta.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Todos os itens pertencerão e serão guardados na organização, permitindo controlos, visibilidade e relatórios para toda a organização. Quando ativada, estará disponível uma coleção predefinida para cada membro armazenar itens. Saiba mais sobre como gerir o ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "Todos os itens passarão a ser propriedade da organização e serão aí guardados, permitindo controlos, visibilidade e relatórios a nível organizacional. Quando esta opção estiver ativa, ficará disponível uma coleção predefinida para cada membro guardar itens. Saiba mais sobre a gestão do ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "ciclo de vida das credenciais", @@ -9851,7 +9851,7 @@ "message": "Atribuir tarefas" }, "assignSecurityTasksToMembers": { - "message": "Send notifications to change passwords" + "message": "Enviar notificações para alterar palavras-passe" }, "assignToCollections": { "message": "Atribuir às coleções" @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Comece o teste gratuito do plano Familiar" }, + "blockClaimedDomainAccountCreation": { + "message": "Bloquear a criação de contas para domínios reclamados" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Impedir que os utilizadores criem contas fora da sua organização utilizando endereços de e-mail de domínios reclamados." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "Um domínio tem de ser reclamado antes de ativar esta política." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Configure um método de desbloqueio para alterar a ação de tempo limite do seu cofre." }, diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 0c3eaa3ea08..5b03a1b7440 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 205e953c0ed..f2b9856e97a 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -5809,9 +5809,9 @@ "message": "Необходимо, чтобы все элементы принадлежали организации, что исключает возможность их хранения на уровне аккаунта.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { + "organizationDataOwnershipDescContent": { "message": "Все элементы будут принадлежать организации и сохраняться в ней, что позволит осуществлять контроль, видимость и отчетность в масштабах всей организации. При включении для каждого участника будет доступна коллекция по умолчанию для хранения элементов. Узнайте больше об управлении ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "жизненным циклом учетных данных", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Начать пробную версию Families" }, + "blockClaimedDomainAccountCreation": { + "message": "Блокировать создание аккаунта для заявленных доменов" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Запретите пользователям создавать аккаунты за пределами вашей организации, используя адреса email из заявленных доменов." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "Перед активацией этой политики необходимо заявить домен." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Настройте способ разблокировки для изменения действия по тайм-ауту хранилища." }, diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index aeb1a4b4e0e..65838aec607 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 30afb3afcc2..933a3494404 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -5809,9 +5809,9 @@ "message": "Odstrániť možnosť uložiť položku pod kontom a požadovať aby všetky položky boli vlastnené organizáciou.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Všetky položky budú vo vlastníctve organizácie a uložené v nej, čo umožní kontrolu, prehľadnosť a vykazovanie v rámci celej organizácie. Po zapnutí bude každému členovi k dispozícii predvolená zbierka na ukladanie položiek. Dozvedieť sa viac o správe ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "životného cyklu položiek", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Začať bezplatnú skúšku pre predplatné Rodiny" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 2f14c42dd95..b1d5da3db34 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 6201f3a7e4e..9052035c174 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/sr_CY/messages.json b/apps/web/src/locales/sr_CY/messages.json index 1d0ae7b0897..c7dd63b5805 100644 --- a/apps/web/src/locales/sr_CY/messages.json +++ b/apps/web/src/locales/sr_CY/messages.json @@ -5809,9 +5809,9 @@ "message": "Захтевајте све ставке да буду у власништву организације, уклањајући опцију за чување предмета на нивоу рачуна.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index 3ebe0499428..a90524b95bc 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -5809,9 +5809,9 @@ "message": "Kräv att alla objekt ägs av en organisation och ta bort möjligheten att lagra objekt på kontonivå.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Alla objekt kommer att ägas och sparas i organisationen, vilket möjliggör kontroll, synlighet och rapportering för hela organisationen. När funktionen är aktiverad finns en standardsamling tillgänglig för varje medlem att lagra objekt i. Läs mer om hur du hanterar ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "livscykel för inloggningsuppgifter", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Starta gratis testperiod för Families" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Konfigurera en upplåsningsmetod för att ändra tidsgränsåtgärden för valvet." }, diff --git a/apps/web/src/locales/ta/messages.json b/apps/web/src/locales/ta/messages.json index 64ce03adb11..eabda4c7611 100644 --- a/apps/web/src/locales/ta/messages.json +++ b/apps/web/src/locales/ta/messages.json @@ -5809,9 +5809,9 @@ "message": "கணக்கு மட்டத்தில் பொருட்களை சேமிக்கும் விருப்பத்தை நீக்கி, அனைத்து பொருட்களும் ஒரு நிறுவனத்திற்கு சொந்தமானதாக இருக்க வேண்டும்.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "அனைத்து பொருட்களும் நிறுவனத்திற்குச் சொந்தமானதாகவும், சேமிக்கப்படுவதாகவும் இருக்கும், இது நிறுவனம் முழுவதும் கட்டுப்பாடுகள், தெரிவுநிலை மற்றும் அறிக்கையிடலை செயல்படுத்துகிறது. இயக்கப்படும் போது, ஒவ்வொரு உறுப்பினருக்கும் பொருட்களைச் சேமிக்க ஒரு இயல்புநிலை கலெக்‌ஷன் கிடைக்கும். நிர்வகிப்பது பற்றி மேலும் அறிக ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "சான்றளிப்பு வாழ்க்கைச் சுழற்சி", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index 9f57ed8c6ca..b23e2e3cbac 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index 30a75f4d4da..bcaada3bea5 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -5809,9 +5809,9 @@ "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "credential lifecycle", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 448172f3c43..82ca8d37b61 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -5809,9 +5809,9 @@ "message": "Tüm kayıtların bir kuruluşa ait olmasını zorunlu kılın ve kayıtları hesap düzeyinde depolama seçeneğini kaldırın.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Tüm kayıtlar kuruluşun mülkiyetinde olacak ve kuruluşta saklanacak, böylece kuruluş genelinde kontrol, görünürlük ve raporlama sağlanacaktır. Etkinleştirildiğinde, her üyenin kayıtları depolaması için varsayılan bir koleksiyon kullanılabilir hale gelir. Yönetme hakkında daha fazla bilgi edinin ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "kimlik bilgisi yaşam döngüsü", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Kasa zaman aşımı eyleminizi değiştirmek için kilit açma yönteminizi ayarlayın." }, diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index f1f7d6530b7..85fbbc317e7 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -5809,9 +5809,9 @@ "message": "Вимагати, щоб усіма записами володіла організація, вилучивши функцію збереження на рівні облікового запису.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Усі записи зберігатимуться в організації та належатимуть їй, забезпечуючи керування, доступність і звітування на рівні організації. Якщо ввімкнути цю функцію, кожен учасник зможе зберігати записи в типовій збірці. Докладніше про ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "життєвий цикл облікових даних", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Start free Families trial" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index f05004b46da..b361fb88822 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -5809,9 +5809,9 @@ "message": "Yêu cầu tất cả các mục phải thuộc sở hữu của một tổ chức, loại bỏ tùy chọn lưu trữ mục ở cấp tài khoản.", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "Tất cả các mục sẽ thuộc sở hữu và được lưu vào tổ chức, cho phép kiểm soát, giám sát và báo cáo trên toàn tổ chức. Khi bật, một bộ sưu tập mặc định sẽ có sẵn cho mỗi thành viên để lưu trữ mục. Tìm hiểu thêm về quản lý ", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "vòng đời thông tin xác thực", @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "Bắt đầu dùng thử Gói Gia đình miễn phí" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Set up an unlock method to change your vault timeout action." }, diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 05534b3a8b2..6ccfef71f97 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -194,7 +194,7 @@ "message": "帮助成员提升他们的安全性" }, "feature2Description": { - "message": "为存在风险的成员分配引导式安全任务,以更新凭证。" + "message": "为存在风险的成员分配指导性安全任务,以更新其凭据。" }, "feature3Title": { "message": "监测进度" @@ -266,7 +266,7 @@ "message": "存在风险的成员" }, "membersWithAccessToAtRiskItemsForCriticalApplications": { - "message": "这些成员拥有关键应用程序中易受攻击项目的访问权限。" + "message": "这些成员拥有对关键应用程序中易受攻击项目的访问权限。" }, "membersWithAtRiskPasswords": { "message": "密码存在风险的成员" @@ -392,7 +392,7 @@ "message": "审查新应用程序" }, "reviewNewAppsDescription": { - "message": "审查具有易受攻击项目的新应用程序然后将需要密切监测的应用程序标记为关键。然后,您可以将安全任务分配给成员以消除风险。" + "message": "审查具有易受攻击项目的新应用程序,并将需要密切监测的应用程序标记为关键。然后,您可以将安全任务分配给成员以消除风险。" }, "clickIconToMarkAppAsCritical": { "message": "点击星形图标以将 App 标记为关键" @@ -5809,9 +5809,9 @@ "message": "要求所有项目归组织所有,禁用此选项以在账户级别存储项目。", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "所有项目都将归组织所有并保存到组织中,从而实现整个组织范围内的控制、可见性和报告。开启后,每个成员都可以使用默认集合来存储项目。进一步了解如何管理", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "所有项目都将归组织所有并保存至组织,从而实现组织范围的控制、可见性和报告功能。启用后,每个成员都将拥有一个默认集合来存储项目。进一步了解", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "凭据的生命周期", @@ -9851,7 +9851,7 @@ "message": "分配任务" }, "assignSecurityTasksToMembers": { - "message": "发送通知以更改密码" + "message": "发送更改密码的通知" }, "assignToCollections": { "message": "分配到集合" @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "开始免费家庭版试用" }, + "blockClaimedDomainAccountCreation": { + "message": "阻止为已声明的域名创建账户" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "禁止用户使用已声明域名的电子邮件地址在组织外部创建账户。" + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "必须先声明域名,然后才能激活此策略。" + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "设置一个解锁方式以更改您的密码库超时动作。" }, diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 3036366816a..add3fa6a84d 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -94,7 +94,7 @@ "message": "指派成員任務以監控進度" }, "onceYouReviewApplications": { - "message": "Once you review applications and mark them as critical, assign tasks to your members to change their passwords." + "message": "當您審查應用程式並將其標記為關鍵後,可指派任務給成員以變更其密碼。" }, "sendReminders": { "message": "傳送提醒" @@ -179,34 +179,34 @@ } }, "noDataInOrgTitle": { - "message": "No data found" + "message": "找不到資料" }, "noDataInOrgDescription": { - "message": "Import your organization's login data to get started with Access Intelligence. Once you do that, you'll be able to:" + "message": "匯入您組織的登入資料以開始使用存取智慧功能。完成後,您將能夠:" }, "feature1Title": { - "message": "Mark applications as critical" + "message": "將應用程式標記為關鍵" }, "feature1Description": { - "message": "This will help you remove risks to your most important applications first." + "message": "這將協助您優先消除最重要應用程式的風險。" }, "feature2Title": { - "message": "Help members improve their security" + "message": "協助成員提升其安全性" }, "feature2Description": { - "message": "Assign at-risk members guided security tasks to update credentials." + "message": "指派有風險的成員執行指導式安全任務以更新憑證。" }, "feature3Title": { - "message": "Monitor progress" + "message": "監控進展" }, "feature3Description": { - "message": "Track changes over time to show security improvements." + "message": "追蹤隨時間變化的狀況以顯示安全性改善。" }, "noReportsRunTitle": { - "message": "Generate report" + "message": "產生報告" }, "noReportsRunDescription": { - "message": "You’re ready to start generating reports. Once you generate, you’ll be able to:" + "message": "您已準備好開始產生報告。產生報告後,您將能夠:" }, "noCriticalApplicationsTitle": { "message": "您尚未將任何應用程式標記為關鍵" @@ -266,13 +266,13 @@ "message": "具有風險的成員" }, "membersWithAccessToAtRiskItemsForCriticalApplications": { - "message": "These members have access to vulnerable items for critical applications." + "message": "這些成員可存取關鍵應用程式中的高風險項目。" }, "membersWithAtRiskPasswords": { "message": "使用有風險密碼的成員" }, "membersWillReceiveSecurityTask": { - "message": "Members of your organization will be assigned a task to change vulnerable passwords. They’ll receive a notification within their Bitwarden browser extension." + "message": "您組織的成員將被指派變更高風險密碼的任務。他們會在 Bitwarden 瀏覽器擴充套件中收到通知。" }, "membersAtRiskCount": { "message": "$COUNT$ 位有風險的成員", @@ -302,7 +302,7 @@ } }, "atRiskMemberDescription": { - "message": "These members are logging into critical applications with weak, exposed, or reused passwords." + "message": "這些成員正以薄弱、已外洩或重複使用的密碼登入關鍵應用程式。" }, "atRiskMembersDescriptionNone": { "message": "目前沒有成員使用弱密碼、外洩密碼或重複密碼登入應用程式。" @@ -386,13 +386,13 @@ "message": "優先處理關鍵應用程式" }, "selectCriticalAppsDescription": { - "message": "Select which applications are most critical to your organization. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "選擇哪些應用程式對您的組織最為關鍵。之後,您將能指派安全任務給成員以消除風險。" }, "reviewNewApplications": { "message": "審查新應用程式" }, "reviewNewAppsDescription": { - "message": "Review new applications with vulnerable items and mark those you’d like to monitor closely as critical. Then, you’ll be able to assign security tasks to members to remove risks." + "message": "審查包含高風險項目的新應用程式,並將您希望密切監控的項目標記為關鍵。之後,您將能指派安全任務給成員以消除風險。" }, "clickIconToMarkAppAsCritical": { "message": "點擊星形圖示以將應用程式標記為關鍵" @@ -5809,9 +5809,9 @@ "message": "要求所有項目由組織擁有,移除在帳號層級儲存項目的選項。", "description": "This is the policy description shown in the policy list." }, - "organizationDataOwnershipContent": { - "message": "所有項目將由組織擁有並儲存,啟用組織範圍的控管、可見性及報告。啟用後,每位成員將有預設集合可用於儲存項目。瞭解更多關於管理", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" + "organizationDataOwnershipDescContent": { + "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection will be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { "message": "憑證生命週期", @@ -9851,7 +9851,7 @@ "message": "指派任務" }, "assignSecurityTasksToMembers": { - "message": "Send notifications to change passwords" + "message": "傳送變更密碼的通知" }, "assignToCollections": { "message": "指派至集合" @@ -12118,6 +12118,15 @@ "startFreeFamiliesTrial": { "message": "開始免費家庭試用" }, + "blockClaimedDomainAccountCreation": { + "message": "Block account creation for claimed domains" + }, + "blockClaimedDomainAccountCreationDesc": { + "message": "Prevent users from creating accounts outside of your organization using email addresses from claimed domains." + }, + "blockClaimedDomainAccountCreationPrerequisite": { + "message": "A domain must be claimed before activating this policy." + }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "設定一個解鎖方式來變更您的密碼庫逾時動作。" }, diff --git a/apps/web/webpack.base.js b/apps/web/webpack.base.js index f1e627a58a8..cc17b3b7cfd 100644 --- a/apps/web/webpack.base.js +++ b/apps/web/webpack.base.js @@ -13,9 +13,11 @@ const config = require(path.resolve(__dirname, "config.js")); const pjson = require(path.resolve(__dirname, "package.json")); module.exports.getEnv = function getEnv(params) { - const ENV = params.env || (process.env.ENV == null ? "development" : process.env.ENV); - const NODE_ENV = process.env.NODE_ENV == null ? "development" : process.env.NODE_ENV; - const LOGGING = process.env.LOGGING != "false"; + const ENV = params.env?.ENV ?? process.env?.ENV ?? "development"; + const NODE_ENV = params.env?.NODE_ENV ?? process.env?.NODE_ENV ?? "development"; + const LOGGING = + params.env?.LOGGING ?? + (process.env?.LOGGING === undefined ? true : process.env.LOGGING !== "false"); return { ENV, NODE_ENV, LOGGING }; }; @@ -35,7 +37,11 @@ const DEFAULT_PARAMS = { * tsConfig: string; * outputPath?: string; * mode?: string; - * env?: string; + * env?: { + * ENV?: string; + * NODE_ENV?: string; + * LOGGING?: boolean; + * }; * importAliases?: import("webpack").ResolveOptions["alias"]; * }} params */ diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js index 962d72ac825..275a6a5f3b0 100644 --- a/apps/web/webpack.config.js +++ b/apps/web/webpack.config.js @@ -15,6 +15,7 @@ module.exports = (webpackConfig, context) => { }, tsConfig: "apps/web/tsconfig.build.json", outputPath: path.resolve(context.context.root, context.options.outputPath), + env: context.options.env, }); } else { return buildConfig({ diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/new-applications-dialog.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/new-applications-dialog.component.html index 04db5f6d521..2742dfdd8cb 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/new-applications-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/new-applications-dialog.component.html @@ -28,7 +28,7 @@ >(new Set()); + protected readonly applicationIcons = signal>( + new Map(), + ); + protected readonly applicationsWithIcons = computed(() => { + return this.dialogParams.newApplications.map((app) => { + const iconCipher = this.applicationIcons().get(app.applicationName); + return { ...app, iconCipher } as ApplicationHealthReportDetail & { iconCipher: CipherIcon }; + }); + }); + // Used to determine if there are unassigned at-risk cipher IDs private readonly _tasks!: Signal; @@ -150,6 +161,7 @@ export class NewApplicationsDialogComponent { private securityTasksService: AccessIntelligenceSecurityTasksService, private toastService: ToastService, ) { + this.setApplicationIconMap(this.dialogParams.newApplications); // Setup the _tasks signal by manually passing in the injector this._tasks = toSignal(this.securityTasksService.tasks$, { initialValue: [], @@ -172,10 +184,6 @@ export class NewApplicationsDialogComponent { ); } - getApplications() { - return this.dialogParams.newApplications; - } - /** * Returns true if the organization has no existing critical applications. * Used to conditionally show different titles and descriptions. @@ -184,6 +192,22 @@ export class NewApplicationsDialogComponent { return !this.dialogParams.hasExistingCriticalApplications; } + /** + * Maps applications to a corresponding iconCipher + * + * @param applications + */ + setApplicationIconMap(applications: ApplicationHealthReportDetail[]) { + // Map the report data to include the iconCipher for each application + const iconCiphers = new Map(); + applications.forEach((app) => { + const iconCipher = + app.cipherIds.length > 0 ? this.dataService.getCipherIcon(app.cipherIds[0]) : undefined; + iconCiphers.set(app.applicationName, iconCipher); + }); + this.applicationIcons.set(iconCiphers); + } + /** * Toggles the selection state of an application. * @param applicationName The application to toggle diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.html index 244cf2c5931..99053cbf94d 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.html @@ -62,7 +62,11 @@
- + @if (app.iconCipher) { + + } @else { + + } {{ app.applicationName }}
diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.ts index 7a269d3aa15..172a4e01579 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/activity/application-review-dialog/review-applications-view.component.ts @@ -5,6 +5,9 @@ import { FormsModule } from "@angular/forms"; import { ApplicationHealthReportDetail } from "@bitwarden/bit-common/dirt/reports/risk-insights"; import { ButtonModule, DialogModule, SearchModule, TypographyModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; +import { SharedModule } from "@bitwarden/web-vault/app/shared"; + +import { CipherIcon } from "../../shared/app-table-row-scrollable.component"; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -18,10 +21,12 @@ import { I18nPipe } from "@bitwarden/ui-common"; SearchModule, TypographyModule, I18nPipe, + SharedModule, ], }) export class ReviewApplicationsViewComponent { - readonly applications = input.required(); + readonly applications = + input.required>(); readonly selectedApplications = input.required>(); protected readonly searchText = signal(""); diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/app-table-row-scrollable.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/app-table-row-scrollable.component.html index edd90eaf97d..76a03e0c525 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/app-table-row-scrollable.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/shared/app-table-row-scrollable.component.html @@ -45,7 +45,6 @@ tabindex="0" [attr.aria-label]="'viewItem' | i18n" > - { const isNxBuild = context && context.options; + if (isNxBuild) { return buildConfig({ configName: "Commercial", @@ -23,6 +24,7 @@ module.exports = (webpackConfig, context) => { alias: "@bitwarden/commercial-sdk-internal", }, ], + env: context.options.env, }); } else { return buildConfig({ diff --git a/eslint.config.mjs b/eslint.config.mjs index df98b3af424..1e12e0e1e19 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -63,7 +63,7 @@ export default tseslint.config( // TODO: Enable these. "@angular-eslint/component-class-suffix": "error", "@angular-eslint/contextual-lifecycle": "error", - "@angular-eslint/directive-class-suffix": 0, + "@angular-eslint/directive-class-suffix": "error", "@angular-eslint/no-empty-lifecycle-method": 0, "@angular-eslint/no-input-rename": 0, "@angular-eslint/no-inputs-metadata-property": "error", @@ -80,6 +80,7 @@ export default tseslint.config( "@bitwarden/platform/required-using": "error", "@bitwarden/platform/no-enums": "error", + "@bitwarden/platform/no-page-script-url-leakage": "error", "@bitwarden/components/require-theme-colors-in-svg": "error", "@typescript-eslint/explicit-member-accessibility": ["error", { accessibility: "no-public" }], diff --git a/libs/angular/src/auth/components/user-verification.component.ts b/libs/angular/src/auth/components/user-verification.component.ts index 1f0659a92ff..a2cee2f1099 100644 --- a/libs/angular/src/auth/components/user-verification.component.ts +++ b/libs/angular/src/auth/components/user-verification.component.ts @@ -24,6 +24,8 @@ import { KeyService } from "@bitwarden/key-management"; selector: "app-user-verification", standalone: false, }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix export class UserVerificationComponent implements ControlValueAccessor, OnInit, OnDestroy { private _invalidSecret = false; // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals diff --git a/libs/angular/src/directives/cipherListVirtualScroll.directive.ts b/libs/angular/src/directives/cipherListVirtualScroll.directive.ts index 442e01c1c79..8e7b5cc204d 100644 --- a/libs/angular/src/directives/cipherListVirtualScroll.directive.ts +++ b/libs/angular/src/directives/cipherListVirtualScroll.directive.ts @@ -45,6 +45,8 @@ export function _cipherListVirtualScrollStrategyFactory(cipherListDir: CipherLis }, ], }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix export class CipherListVirtualScroll extends CdkFixedSizeVirtualScroll { _scrollStrategy: CipherListVirtualScrollStrategy; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 9099c8e884f..395ab6823d9 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -102,7 +102,6 @@ import { MasterPasswordApiService as MasterPasswordApiServiceAbstraction } from import { PasswordResetEnrollmentServiceAbstraction } from "@bitwarden/common/auth/abstractions/password-reset-enrollment.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction"; import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { WebAuthnLoginApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login-api.service.abstraction"; @@ -125,13 +124,17 @@ import { OrganizationInviteService } from "@bitwarden/common/auth/services/organ import { PasswordResetEnrollmentServiceImplementation } from "@bitwarden/common/auth/services/password-reset-enrollment.service.implementation"; import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service"; import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service"; import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service"; import { WebAuthnLoginApiService } from "@bitwarden/common/auth/services/webauthn-login/webauthn-login-api.service"; import { WebAuthnLoginPrfKeyService } from "@bitwarden/common/auth/services/webauthn-login/webauthn-login-prf-key.service"; import { WebAuthnLoginService } from "@bitwarden/common/auth/services/webauthn-login/webauthn-login.service"; -import { TwoFactorApiService, DefaultTwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { + TwoFactorApiService, + DefaultTwoFactorApiService, + TwoFactorService, + DefaultTwoFactorService, +} from "@bitwarden/common/auth/two-factor"; import { AutofillSettingsService, AutofillSettingsServiceAbstraction, @@ -525,7 +528,7 @@ const safeProviders: SafeProvider[] = [ KeyConnectorServiceAbstraction, EnvironmentService, StateServiceAbstraction, - TwoFactorServiceAbstraction, + TwoFactorService, I18nServiceAbstraction, EncryptService, PasswordStrengthServiceAbstraction, @@ -1169,9 +1172,14 @@ const safeProviders: SafeProvider[] = [ deps: [StateProvider], }), safeProvider({ - provide: TwoFactorServiceAbstraction, - useClass: TwoFactorService, - deps: [I18nServiceAbstraction, PlatformUtilsServiceAbstraction, GlobalStateProvider], + provide: TwoFactorService, + useClass: DefaultTwoFactorService, + deps: [ + I18nServiceAbstraction, + PlatformUtilsServiceAbstraction, + GlobalStateProvider, + TwoFactorApiService, + ], }), safeProvider({ provide: FormValidationErrorsServiceAbstraction, diff --git a/libs/angular/src/vault/components/spotlight/spotlight.component.html b/libs/angular/src/vault/components/spotlight/spotlight.component.html index 720bf5c1908..92b88eb967d 100644 --- a/libs/angular/src/vault/components/spotlight/spotlight.component.html +++ b/libs/angular/src/vault/components/spotlight/spotlight.component.html @@ -3,20 +3,20 @@ >
-

{{ title }}

+

{{ title() }}

- +
diff --git a/libs/angular/src/vault/components/spotlight/spotlight.component.spec.ts b/libs/angular/src/vault/components/spotlight/spotlight.component.spec.ts new file mode 100644 index 00000000000..3d4d35fdf63 --- /dev/null +++ b/libs/angular/src/vault/components/spotlight/spotlight.component.spec.ts @@ -0,0 +1,208 @@ +import { CommonModule } from "@angular/common"; +import { ChangeDetectionStrategy, Component } from "@angular/core"; +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; + +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; + +import { SpotlightComponent } from "./spotlight.component"; + +describe("SpotlightComponent", () => { + let fixture: ComponentFixture; + let component: SpotlightComponent; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SpotlightComponent], + providers: [{ provide: I18nService, useValue: { t: (key: string) => key } }], + }).compileComponents(); + + fixture = TestBed.createComponent(SpotlightComponent); + component = fixture.componentInstance; + }); + + function detect(): void { + fixture.detectChanges(); + } + + it("should create", () => { + expect(component).toBeTruthy(); + }); + + describe("rendering when inputs are null", () => { + it("should render without crashing when inputs are null/undefined", () => { + // Explicitly drive the inputs to null to exercise template null branches + fixture.componentRef.setInput("title", null); + fixture.componentRef.setInput("subtitle", null); + fixture.componentRef.setInput("buttonText", null); + fixture.componentRef.setInput("buttonIcon", null); + // persistent has a default, but drive it as well for coverage sanity + fixture.componentRef.setInput("persistent", false); + + expect(() => detect()).not.toThrow(); + + const root = fixture.debugElement.nativeElement as HTMLElement; + expect(root).toBeTruthy(); + }); + }); + + describe("close button visibility based on persistent", () => { + it("should show the close button when persistent is false", () => { + fixture.componentRef.setInput("persistent", false); + detect(); + + // Assumes dismiss uses bitIconButton + const dismissButton = fixture.debugElement.query(By.css("button[bitIconButton]")); + + expect(dismissButton).toBeTruthy(); + }); + + it("should hide the close button when persistent is true", () => { + fixture.componentRef.setInput("persistent", true); + detect(); + + const dismissButton = fixture.debugElement.query(By.css("button[bitIconButton]")); + expect(dismissButton).toBeNull(); + }); + }); + + describe("event emission", () => { + it("should emit onButtonClick when CTA button is clicked", () => { + const clickSpy = jest.fn(); + component.onButtonClick.subscribe(clickSpy); + + fixture.componentRef.setInput("buttonText", "Click me"); + detect(); + + const buttonDe = fixture.debugElement.query(By.css("button[bitButton]")); + expect(buttonDe).toBeTruthy(); + + const event = new MouseEvent("click"); + buttonDe.triggerEventHandler("click", event); + + expect(clickSpy).toHaveBeenCalledTimes(1); + expect(clickSpy.mock.calls[0][0]).toBeInstanceOf(MouseEvent); + }); + + it("should emit onDismiss when close button is clicked", () => { + const dismissSpy = jest.fn(); + component.onDismiss.subscribe(dismissSpy); + + fixture.componentRef.setInput("persistent", false); + detect(); + + const dismissButton = fixture.debugElement.query(By.css("button[bitIconButton]")); + expect(dismissButton).toBeTruthy(); + + dismissButton.triggerEventHandler("click", new MouseEvent("click")); + + expect(dismissSpy).toHaveBeenCalledTimes(1); + }); + + it("handleButtonClick should emit via onButtonClick()", () => { + const clickSpy = jest.fn(); + component.onButtonClick.subscribe(clickSpy); + + const event = new MouseEvent("click"); + component.handleButtonClick(event); + + expect(clickSpy).toHaveBeenCalledTimes(1); + expect(clickSpy.mock.calls[0][0]).toBe(event); + }); + + it("handleDismiss should emit via onDismiss()", () => { + const dismissSpy = jest.fn(); + component.onDismiss.subscribe(dismissSpy); + + component.handleDismiss(); + + expect(dismissSpy).toHaveBeenCalledTimes(1); + }); + }); + + describe("content projection behavior", () => { + @Component({ + standalone: true, + imports: [SpotlightComponent], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + Projected content + + `, + }) + class HostWithProjectionComponent {} + + let hostFixture: ComponentFixture; + + beforeEach(async () => { + hostFixture = TestBed.createComponent(HostWithProjectionComponent); + }); + + it("should render projected content inside the spotlight", () => { + hostFixture.detectChanges(); + + const projected = hostFixture.debugElement.query(By.css(".tw-text-sm")); + expect(projected).toBeTruthy(); + expect(projected.nativeElement.textContent.trim()).toBe("Projected content"); + }); + }); + + describe("boolean attribute transform for persistent", () => { + @Component({ + standalone: true, + imports: [CommonModule, SpotlightComponent], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` + + + + + + + + + `, + }) + class BooleanHostComponent { + mode: "bare" | "none" | "falseStr" = "bare"; + } + + let boolFixture: ComponentFixture; + let boolHost: BooleanHostComponent; + + beforeEach(async () => { + boolFixture = TestBed.createComponent(BooleanHostComponent); + boolHost = boolFixture.componentInstance; + }); + + function getSpotlight(): SpotlightComponent { + const de = boolFixture.debugElement.query(By.directive(SpotlightComponent)); + return de.componentInstance as SpotlightComponent; + } + + it("treats bare 'persistent' attribute as true via booleanAttribute", () => { + boolHost.mode = "bare"; + boolFixture.detectChanges(); + + const spotlight = getSpotlight(); + expect(spotlight.persistent()).toBe(true); + }); + + it("uses default false when 'persistent' is omitted", () => { + boolHost.mode = "none"; + boolFixture.detectChanges(); + + const spotlight = getSpotlight(); + expect(spotlight.persistent()).toBe(false); + }); + + it('treats persistent="false" as false', () => { + boolHost.mode = "falseStr"; + boolFixture.detectChanges(); + + const spotlight = getSpotlight(); + expect(spotlight.persistent()).toBe(false); + }); + }); +}); diff --git a/libs/angular/src/vault/components/spotlight/spotlight.component.ts b/libs/angular/src/vault/components/spotlight/spotlight.component.ts index a912e4ce11b..1b75e1ee737 100644 --- a/libs/angular/src/vault/components/spotlight/spotlight.component.ts +++ b/libs/angular/src/vault/components/spotlight/spotlight.component.ts @@ -1,43 +1,28 @@ import { CommonModule } from "@angular/common"; -import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { booleanAttribute, ChangeDetectionStrategy, Component, input, output } from "@angular/core"; import { ButtonModule, IconButtonModule, TypographyModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; -// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush -// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @Component({ selector: "bit-spotlight", templateUrl: "spotlight.component.html", imports: [ButtonModule, CommonModule, IconButtonModule, I18nPipe, TypographyModule], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class SpotlightComponent { // The title of the component - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input({ required: true }) title: string | null = null; + readonly title = input(); // The subtitle of the component - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input() subtitle?: string | null = null; + readonly subtitle = input(); // The text to display on the button - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input() buttonText?: string; - // Wheter the component can be dismissed, if true, the component will not show a close button - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input() persistent = false; + readonly buttonText = input(); + // Whether the component can be dismissed, if true, the component will not show a close button + readonly persistent = input(false, { transform: booleanAttribute }); // Optional icon to display on the button - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input() buttonIcon: string | null = null; - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onDismiss = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onButtonClick = new EventEmitter(); + readonly buttonIcon = input(); + readonly onDismiss = output(); + readonly onButtonClick = output(); handleButtonClick(event: MouseEvent): void { this.onButtonClick.emit(event); diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index 51379ed213e..0b011b5641f 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -205,14 +205,9 @@ export class LoginComponent implements OnInit, OnDestroy { await this.loadRememberedEmail(); } - const disableAlternateLoginMethodsFlagEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM22110_DisableAlternateLoginMethods, - ); - if (disableAlternateLoginMethodsFlagEnabled) { - // This SSO required check should come after email has had a chance to be pre-filled (if it - // was found in query params or was the remembered email) - await this.determineIfSsoRequired(); - } + // This SSO required check should come after email has had a chance to be pre-filled (if it + // was found in query params or was the remembered email) + await this.determineIfSsoRequired(); } private async desktopOnInit(): Promise { diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts index 000d391b62c..8976236f48c 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-email/two-factor-auth-email.component.ts @@ -4,10 +4,9 @@ import { ReactiveFormsModule, FormsModule, FormControl } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request"; -import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -68,7 +67,6 @@ export class TwoFactorAuthEmailComponent implements OnInit { protected loginStrategyService: LoginStrategyServiceAbstraction, protected platformUtilsService: PlatformUtilsService, protected logService: LogService, - protected twoFactorApiService: TwoFactorApiService, protected appIdService: AppIdService, private toastService: ToastService, private cacheService: TwoFactorAuthEmailComponentCacheService, @@ -137,7 +135,7 @@ export class TwoFactorAuthEmailComponent implements OnInit { request.deviceIdentifier = await this.appIdService.getAppId(); request.authRequestAccessCode = (await this.loginStrategyService.getAccessCode()) ?? ""; request.authRequestId = (await this.loginStrategyService.getAuthRequestId()) ?? ""; - this.emailPromise = this.twoFactorApiService.postTwoFactorEmail(request); + this.emailPromise = this.twoFactorService.postTwoFactorEmail(request); await this.emailPromise; this.emailSent = true; diff --git a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-webauthn/two-factor-auth-webauthn.component.ts b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-webauthn/two-factor-auth-webauthn.component.ts index 71a91ec20e7..54d6f7c5f77 100644 --- a/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-webauthn/two-factor-auth-webauthn.component.ts +++ b/libs/auth/src/angular/two-factor-auth/child-components/two-factor-auth-webauthn/two-factor-auth-webauthn.component.ts @@ -6,8 +6,8 @@ import { firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { WebAuthnIFrame } from "@bitwarden/common/auth/webauthn-iframe"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts index 5d36fd384ca..af9fb03e01e 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.spec.ts @@ -18,12 +18,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction, diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts index 52f20b04601..8e10539823d 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.component.ts @@ -32,12 +32,12 @@ import { import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.spec.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.spec.ts index 116da73173f..37fbf6bf794 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.spec.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.spec.ts @@ -4,8 +4,8 @@ import { provideRouter, Router } from "@angular/router"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject } from "rxjs"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { LoginStrategyServiceAbstraction } from "../../common"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.ts b/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.ts index 2aec0bae441..a7ed4010ef5 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-auth.guard.ts @@ -8,7 +8,7 @@ import { } from "@angular/router"; import { firstValueFrom } from "rxjs"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { LoginStrategyServiceAbstraction } from "../../common"; diff --git a/libs/auth/src/angular/two-factor-auth/two-factor-options.component.ts b/libs/auth/src/angular/two-factor-auth/two-factor-options.component.ts index d0ad9be6103..d8b2ab2508b 100644 --- a/libs/auth/src/angular/two-factor-auth/two-factor-options.component.ts +++ b/libs/auth/src/angular/two-factor-auth/two-factor-options.component.ts @@ -9,11 +9,8 @@ import { TwoFactorAuthWebAuthnIcon, TwoFactorAuthYubicoIcon, } from "@bitwarden/assets/svg"; -import { - TwoFactorProviderDetails, - TwoFactorService, -} from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { TwoFactorProviderDetails, TwoFactorService } from "@bitwarden/common/auth/two-factor"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { diff --git a/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts b/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts index 09d428d4ba7..1304df2a763 100644 --- a/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts +++ b/libs/auth/src/angular/user-verification/user-verification-dialog.component.ts @@ -277,13 +277,13 @@ export class UserVerificationDialogComponent { }); } } - } catch (e) { + } catch { // Catch handles OTP and MP verification scenarios as those throw errors on verification failure instead of returning false like PIN and biometrics. this.invalidSecret = true; this.toastService.showToast({ variant: "error", title: this.i18nService.t("error"), - message: e.message, + message: this.i18nService.t("userVerificationFailed"), }); return; } diff --git a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts index 0b19fecdc4e..b536ae0dc4b 100644 --- a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts @@ -3,8 +3,8 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; diff --git a/libs/auth/src/common/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts index a23f8034238..e9eed27d5a1 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -5,7 +5,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; @@ -16,6 +15,7 @@ import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/id import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response"; import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index 7ad5cd24353..35f13246593 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -3,7 +3,6 @@ import { BehaviorSubject, filter, firstValueFrom, timeout, Observable } from "rx import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; @@ -16,6 +15,7 @@ import { WebAuthnLoginTokenRequest } from "@bitwarden/common/auth/models/request import { IdentityDeviceVerificationResponse } from "@bitwarden/common/auth/models/response/identity-device-verification.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts index 3f709e7472b..26ae1270f39 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts @@ -5,12 +5,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service"; diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index bce05b35e62..03de5f36c2d 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -3,12 +3,12 @@ import { BehaviorSubject, of } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncryptedString } from "@bitwarden/common/key-management/crypto/models/enc-string"; diff --git a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts index a6446401f70..9bf282dee11 100644 --- a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts @@ -3,7 +3,7 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; diff --git a/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts index 25ae8a31ef6..53bc1c57905 100644 --- a/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts @@ -3,11 +3,11 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service"; diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts index f97158477f1..831692c160f 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.spec.ts @@ -4,13 +4,13 @@ import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; import { PreloginResponse } from "@bitwarden/common/auth/models/response/prelogin.response"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts index 084fafc4aea..5720fce254e 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts @@ -13,10 +13,10 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { TwoFactorService } from "@bitwarden/common/auth/two-factor"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; diff --git a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts index 86f7be8dfc7..975e065e21e 100644 --- a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts +++ b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.spec.ts @@ -1,7 +1,6 @@ import { MockProxy, mock } from "jest-mock-extended"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; @@ -58,62 +57,35 @@ describe("DefaultLoginSuccessHandlerService", () => { expect(loginEmailService.clearLoginEmail).toHaveBeenCalled(); }); - describe("when PM22110_DisableAlternateLoginMethods flag is disabled", () => { + it("should get SSO email", async () => { + await service.run(userId); + + expect(ssoLoginService.getSsoEmail).toHaveBeenCalled(); + }); + + describe("given SSO email is not found", () => { beforeEach(() => { - configService.getFeatureFlag.mockResolvedValue(false); + ssoLoginService.getSsoEmail.mockResolvedValue(null); }); - it("should not check SSO requirements", async () => { + it("should log error and return early", async () => { await service.run(userId); - expect(ssoLoginService.getSsoEmail).not.toHaveBeenCalled(); + expect(logService.error).toHaveBeenCalledWith("SSO login email not found."); expect(ssoLoginService.updateSsoRequiredCache).not.toHaveBeenCalled(); }); }); - describe("given PM22110_DisableAlternateLoginMethods flag is enabled", () => { + describe("given SSO email is found", () => { beforeEach(() => { - configService.getFeatureFlag.mockResolvedValue(true); + ssoLoginService.getSsoEmail.mockResolvedValue(testEmail); }); - it("should check feature flag", async () => { + it("should call updateSsoRequiredCache() and clearSsoEmail()", async () => { await service.run(userId); - expect(configService.getFeatureFlag).toHaveBeenCalledWith( - FeatureFlag.PM22110_DisableAlternateLoginMethods, - ); - }); - - it("should get SSO email", async () => { - await service.run(userId); - - expect(ssoLoginService.getSsoEmail).toHaveBeenCalled(); - }); - - describe("given SSO email is not found", () => { - beforeEach(() => { - ssoLoginService.getSsoEmail.mockResolvedValue(null); - }); - - it("should log error and return early", async () => { - await service.run(userId); - - expect(logService.error).toHaveBeenCalledWith("SSO login email not found."); - expect(ssoLoginService.updateSsoRequiredCache).not.toHaveBeenCalled(); - }); - }); - - describe("given SSO email is found", () => { - beforeEach(() => { - ssoLoginService.getSsoEmail.mockResolvedValue(testEmail); - }); - - it("should call updateSsoRequiredCache() and clearSsoEmail()", async () => { - await service.run(userId); - - expect(ssoLoginService.updateSsoRequiredCache).toHaveBeenCalledWith(testEmail, userId); - expect(ssoLoginService.clearSsoEmail).toHaveBeenCalled(); - }); + expect(ssoLoginService.updateSsoRequiredCache).toHaveBeenCalledWith(testEmail, userId); + expect(ssoLoginService.clearSsoEmail).toHaveBeenCalled(); }); }); }); diff --git a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts index 78003a4fca0..27d058c311a 100644 --- a/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts +++ b/libs/auth/src/common/services/login-success-handler/default-login-success-handler.service.ts @@ -1,5 +1,4 @@ import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; @@ -23,20 +22,14 @@ export class DefaultLoginSuccessHandlerService implements LoginSuccessHandlerSer await this.userAsymmetricKeysRegenerationService.regenerateIfNeeded(userId); await this.loginEmailService.clearLoginEmail(); - const disableAlternateLoginMethodsFlagEnabled = await this.configService.getFeatureFlag( - FeatureFlag.PM22110_DisableAlternateLoginMethods, - ); + const ssoLoginEmail = await this.ssoLoginService.getSsoEmail(); - if (disableAlternateLoginMethodsFlagEnabled) { - const ssoLoginEmail = await this.ssoLoginService.getSsoEmail(); - - if (!ssoLoginEmail) { - this.logService.error("SSO login email not found."); - return; - } - - await this.ssoLoginService.updateSsoRequiredCache(ssoLoginEmail, userId); - await this.ssoLoginService.clearSsoEmail(); + if (!ssoLoginEmail) { + this.logService.error("SSO login email not found."); + return; } + + await this.ssoLoginService.updateSsoRequiredCache(ssoLoginEmail, userId); + await this.ssoLoginService.clearSsoEmail(); } } diff --git a/libs/common/src/auth/abstractions/two-factor.service.ts b/libs/common/src/auth/abstractions/two-factor.service.ts deleted file mode 100644 index 528e52bf5da..00000000000 --- a/libs/common/src/auth/abstractions/two-factor.service.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { TwoFactorProviderType } from "../enums/two-factor-provider-type"; -import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response"; - -export interface TwoFactorProviderDetails { - type: TwoFactorProviderType; - name: string; - description: string; - priority: number; - sort: number; - premium: boolean; -} -export abstract class TwoFactorService { - /** - * Initializes the client-side's TwoFactorProviders const with translations. - */ - abstract init(): void; - - /** - * Gets a list of two-factor providers from state that are supported on the current client. - * E.g., WebAuthn and Duo are not available on all clients. - * @returns A list of supported two-factor providers or an empty list if none are stored in state. - */ - abstract getSupportedProviders(win: Window): Promise; - - /** - * Gets the previously selected two-factor provider or the default two factor provider based on priority. - * @param webAuthnSupported - Whether or not WebAuthn is supported by the client. Prevents WebAuthn from being the default provider if false. - */ - abstract getDefaultProvider(webAuthnSupported: boolean): Promise; - - /** - * Sets the selected two-factor provider in state. - * @param type - The type of two-factor provider to set as the selected provider. - */ - abstract setSelectedProvider(type: TwoFactorProviderType): Promise; - - /** - * Clears the selected two-factor provider from state. - */ - abstract clearSelectedProvider(): Promise; - - /** - * Sets the list of available two-factor providers in state. - * @param response - the response from Identity for when 2FA is required. Includes the list of available 2FA providers. - */ - abstract setProviders(response: IdentityTwoFactorResponse): Promise; - - /** - * Clears the list of available two-factor providers from state. - */ - abstract clearProviders(): Promise; - - /** - * Gets the list of two-factor providers from state. - * Note: no filtering is done here, so this will return all providers, including potentially - * unsupported ones for the current client. - * @returns A list of two-factor providers or null if none are stored in state. - */ - abstract getProviders(): Promise | null>; -} diff --git a/libs/common/src/auth/services/two-factor.service.ts b/libs/common/src/auth/services/two-factor.service.ts deleted file mode 100644 index 83e113268a2..00000000000 --- a/libs/common/src/auth/services/two-factor.service.ts +++ /dev/null @@ -1,212 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { firstValueFrom, map } from "rxjs"; - -import { I18nService } from "../../platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { Utils } from "../../platform/misc/utils"; -import { GlobalStateProvider, KeyDefinition, TWO_FACTOR_MEMORY } from "../../platform/state"; -import { - TwoFactorProviderDetails, - TwoFactorService as TwoFactorServiceAbstraction, -} from "../abstractions/two-factor.service"; -import { TwoFactorProviderType } from "../enums/two-factor-provider-type"; -import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response"; - -export const TwoFactorProviders: Partial> = - { - [TwoFactorProviderType.Authenticator]: { - type: TwoFactorProviderType.Authenticator, - name: null as string, - description: null as string, - priority: 1, - sort: 2, - premium: false, - }, - [TwoFactorProviderType.Yubikey]: { - type: TwoFactorProviderType.Yubikey, - name: null as string, - description: null as string, - priority: 3, - sort: 4, - premium: true, - }, - [TwoFactorProviderType.Duo]: { - type: TwoFactorProviderType.Duo, - name: "Duo", - description: null as string, - priority: 2, - sort: 5, - premium: true, - }, - [TwoFactorProviderType.OrganizationDuo]: { - type: TwoFactorProviderType.OrganizationDuo, - name: "Duo (Organization)", - description: null as string, - priority: 10, - sort: 6, - premium: false, - }, - [TwoFactorProviderType.Email]: { - type: TwoFactorProviderType.Email, - name: null as string, - description: null as string, - priority: 0, - sort: 1, - premium: false, - }, - [TwoFactorProviderType.WebAuthn]: { - type: TwoFactorProviderType.WebAuthn, - name: null as string, - description: null as string, - priority: 4, - sort: 3, - premium: false, - }, - }; - -// Memory storage as only required during authentication process -export const PROVIDERS = KeyDefinition.record, TwoFactorProviderType>( - TWO_FACTOR_MEMORY, - "providers", - { - deserializer: (obj) => obj, - }, -); - -// Memory storage as only required during authentication process -export const SELECTED_PROVIDER = new KeyDefinition( - TWO_FACTOR_MEMORY, - "selected", - { - deserializer: (obj) => obj, - }, -); - -export class TwoFactorService implements TwoFactorServiceAbstraction { - private providersState = this.globalStateProvider.get(PROVIDERS); - private selectedState = this.globalStateProvider.get(SELECTED_PROVIDER); - readonly providers$ = this.providersState.state$.pipe( - map((providers) => Utils.recordToMap(providers)), - ); - readonly selected$ = this.selectedState.state$; - - constructor( - private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, - private globalStateProvider: GlobalStateProvider, - ) {} - - init() { - TwoFactorProviders[TwoFactorProviderType.Email].name = this.i18nService.t("emailTitle"); - TwoFactorProviders[TwoFactorProviderType.Email].description = this.i18nService.t("emailDescV2"); - - TwoFactorProviders[TwoFactorProviderType.Authenticator].name = - this.i18nService.t("authenticatorAppTitle"); - TwoFactorProviders[TwoFactorProviderType.Authenticator].description = - this.i18nService.t("authenticatorAppDescV2"); - - TwoFactorProviders[TwoFactorProviderType.Duo].description = this.i18nService.t("duoDescV2"); - - TwoFactorProviders[TwoFactorProviderType.OrganizationDuo].name = - "Duo (" + this.i18nService.t("organization") + ")"; - TwoFactorProviders[TwoFactorProviderType.OrganizationDuo].description = - this.i18nService.t("duoOrganizationDesc"); - - TwoFactorProviders[TwoFactorProviderType.WebAuthn].name = this.i18nService.t("webAuthnTitle"); - TwoFactorProviders[TwoFactorProviderType.WebAuthn].description = - this.i18nService.t("webAuthnDesc"); - - TwoFactorProviders[TwoFactorProviderType.Yubikey].name = this.i18nService.t("yubiKeyTitleV2"); - TwoFactorProviders[TwoFactorProviderType.Yubikey].description = - this.i18nService.t("yubiKeyDesc"); - } - - async getSupportedProviders(win: Window): Promise { - const data = await firstValueFrom(this.providers$); - const providers: any[] = []; - if (data == null) { - return providers; - } - - if ( - data.has(TwoFactorProviderType.OrganizationDuo) && - this.platformUtilsService.supportsDuo() - ) { - providers.push(TwoFactorProviders[TwoFactorProviderType.OrganizationDuo]); - } - - if (data.has(TwoFactorProviderType.Authenticator)) { - providers.push(TwoFactorProviders[TwoFactorProviderType.Authenticator]); - } - - if (data.has(TwoFactorProviderType.Yubikey)) { - providers.push(TwoFactorProviders[TwoFactorProviderType.Yubikey]); - } - - if (data.has(TwoFactorProviderType.Duo) && this.platformUtilsService.supportsDuo()) { - providers.push(TwoFactorProviders[TwoFactorProviderType.Duo]); - } - - if ( - data.has(TwoFactorProviderType.WebAuthn) && - this.platformUtilsService.supportsWebAuthn(win) - ) { - providers.push(TwoFactorProviders[TwoFactorProviderType.WebAuthn]); - } - - if (data.has(TwoFactorProviderType.Email)) { - providers.push(TwoFactorProviders[TwoFactorProviderType.Email]); - } - - return providers; - } - - async getDefaultProvider(webAuthnSupported: boolean): Promise { - const data = await firstValueFrom(this.providers$); - const selected = await firstValueFrom(this.selected$); - if (data == null) { - return null; - } - - if (selected != null && data.has(selected)) { - return selected; - } - - let providerType: TwoFactorProviderType = null; - let providerPriority = -1; - data.forEach((_value, type) => { - const provider = (TwoFactorProviders as any)[type]; - if (provider != null && provider.priority > providerPriority) { - if (type === TwoFactorProviderType.WebAuthn && !webAuthnSupported) { - return; - } - - providerType = type; - providerPriority = provider.priority; - } - }); - - return providerType; - } - - async setSelectedProvider(type: TwoFactorProviderType): Promise { - await this.selectedState.update(() => type); - } - - async clearSelectedProvider(): Promise { - await this.selectedState.update(() => null); - } - - async setProviders(response: IdentityTwoFactorResponse): Promise { - await this.providersState.update(() => response.twoFactorProviders2); - } - - async clearProviders(): Promise { - await this.providersState.update(() => null); - } - - getProviders(): Promise | null> { - return firstValueFrom(this.providers$); - } -} diff --git a/libs/common/src/auth/two-factor/abstractions/index.ts b/libs/common/src/auth/two-factor/abstractions/index.ts new file mode 100644 index 00000000000..00789048ebe --- /dev/null +++ b/libs/common/src/auth/two-factor/abstractions/index.ts @@ -0,0 +1,2 @@ +export * from "./two-factor-api.service"; +export * from "./two-factor.service"; diff --git a/libs/common/src/auth/two-factor/two-factor-api.service.ts b/libs/common/src/auth/two-factor/abstractions/two-factor-api.service.ts similarity index 100% rename from libs/common/src/auth/two-factor/two-factor-api.service.ts rename to libs/common/src/auth/two-factor/abstractions/two-factor-api.service.ts diff --git a/libs/common/src/auth/two-factor/abstractions/two-factor.service.ts b/libs/common/src/auth/two-factor/abstractions/two-factor.service.ts new file mode 100644 index 00000000000..4cba40716e1 --- /dev/null +++ b/libs/common/src/auth/two-factor/abstractions/two-factor.service.ts @@ -0,0 +1,497 @@ +import { ListResponse } from "../../../models/response/list.response"; +import { KeyDefinition, TWO_FACTOR_MEMORY } from "../../../platform/state"; +import { TwoFactorProviderType } from "../../enums/two-factor-provider-type"; +import { DisableTwoFactorAuthenticatorRequest } from "../../models/request/disable-two-factor-authenticator.request"; +import { SecretVerificationRequest } from "../../models/request/secret-verification.request"; +import { TwoFactorEmailRequest } from "../../models/request/two-factor-email.request"; +import { TwoFactorProviderRequest } from "../../models/request/two-factor-provider.request"; +import { UpdateTwoFactorAuthenticatorRequest } from "../../models/request/update-two-factor-authenticator.request"; +import { UpdateTwoFactorDuoRequest } from "../../models/request/update-two-factor-duo.request"; +import { UpdateTwoFactorEmailRequest } from "../../models/request/update-two-factor-email.request"; +import { UpdateTwoFactorWebAuthnDeleteRequest } from "../../models/request/update-two-factor-web-authn-delete.request"; +import { UpdateTwoFactorWebAuthnRequest } from "../../models/request/update-two-factor-web-authn.request"; +import { UpdateTwoFactorYubikeyOtpRequest } from "../../models/request/update-two-factor-yubikey-otp.request"; +import { IdentityTwoFactorResponse } from "../../models/response/identity-two-factor.response"; +import { TwoFactorAuthenticatorResponse } from "../../models/response/two-factor-authenticator.response"; +import { TwoFactorDuoResponse } from "../../models/response/two-factor-duo.response"; +import { TwoFactorEmailResponse } from "../../models/response/two-factor-email.response"; +import { TwoFactorProviderResponse } from "../../models/response/two-factor-provider.response"; +import { TwoFactorRecoverResponse } from "../../models/response/two-factor-recover.response"; +import { + ChallengeResponse, + TwoFactorWebAuthnResponse, +} from "../../models/response/two-factor-web-authn.response"; +import { TwoFactorYubiKeyResponse } from "../../models/response/two-factor-yubi-key.response"; + +/** + * Metadata and display information for a two-factor authentication provider. + * Used by UI components to render provider selection and configuration screens. + */ +export interface TwoFactorProviderDetails { + /** The unique identifier for this provider type. */ + type: TwoFactorProviderType; + + /** + * Display name for the provider, localized via {@link TwoFactorService.init}. + * Examples: "Authenticator App", "Email", "YubiKey". + */ + name: string | null; + + /** + * User-facing description explaining what this provider is and how it works. + * Localized via {@link TwoFactorService.init}. + */ + description: string | null; + + /** + * Selection priority during login when multiple providers are available. + * Higher values are preferred. Used to determine the default provider. + * Range: 0 (lowest) to 10 (highest). + */ + priority: number; + + /** + * Display order in provider lists within settings UI. + * Lower values appear first (1 = first position). + */ + sort: number; + + /** + * Whether this provider requires an active premium subscription. + * Premium providers: Duo (personal), YubiKey. + * Organization providers (e.g., OrganizationDuo) do not require personal premium. + */ + premium: boolean; +} + +/** + * Registry of all supported two-factor authentication providers with their metadata. + * Strings (name, description) are initialized as null and populated with localized + * translations when {@link TwoFactorService.init} is called during application startup. + * + * @remarks + * This constant is mutated during initialization. Components should not access it before + * the service's init() method has been called. + * + * @example + * ```typescript + * // During app init + * twoFactorService.init(); + * + * // In components + * const authenticator = TwoFactorProviders[TwoFactorProviderType.Authenticator]; + * console.log(authenticator.name); // "Authenticator App" (localized) + * ``` + */ +export const TwoFactorProviders: Partial> = + { + [TwoFactorProviderType.Authenticator]: { + type: TwoFactorProviderType.Authenticator, + name: null, + description: null, + priority: 1, + sort: 2, + premium: false, + }, + [TwoFactorProviderType.Yubikey]: { + type: TwoFactorProviderType.Yubikey, + name: null, + description: null, + priority: 3, + sort: 4, + premium: true, + }, + [TwoFactorProviderType.Duo]: { + type: TwoFactorProviderType.Duo, + name: "Duo", + description: null, + priority: 2, + sort: 5, + premium: true, + }, + [TwoFactorProviderType.OrganizationDuo]: { + type: TwoFactorProviderType.OrganizationDuo, + name: "Duo (Organization)", + description: null, + priority: 10, + sort: 6, + premium: false, + }, + [TwoFactorProviderType.Email]: { + type: TwoFactorProviderType.Email, + name: null, + description: null, + priority: 0, + sort: 1, + premium: false, + }, + [TwoFactorProviderType.WebAuthn]: { + type: TwoFactorProviderType.WebAuthn, + name: null, + description: null, + priority: 4, + sort: 3, + premium: false, + }, + }; + +// Memory storage as only required during authentication process +export const PROVIDERS = KeyDefinition.record, TwoFactorProviderType>( + TWO_FACTOR_MEMORY, + "providers", + { + deserializer: (obj) => obj, + }, +); + +// Memory storage as only required during authentication process +export const SELECTED_PROVIDER = new KeyDefinition( + TWO_FACTOR_MEMORY, + "selected", + { + deserializer: (obj) => obj, + }, +); + +export abstract class TwoFactorService { + /** + * Initializes the client-side's TwoFactorProviders const with translations. + */ + abstract init(): void; + + /** + * Gets a list of two-factor providers from state that are supported on the current client. + * E.g., WebAuthn and Duo are not available on all clients. + * @returns A list of supported two-factor providers or an empty list if none are stored in state. + */ + abstract getSupportedProviders(win: Window): Promise; + + /** + * Gets the previously selected two-factor provider or the default two factor provider based on priority. + * @param webAuthnSupported - Whether or not WebAuthn is supported by the client. Prevents WebAuthn from being the default provider if false. + */ + abstract getDefaultProvider(webAuthnSupported: boolean): Promise; + + /** + * Sets the selected two-factor provider in state. + * @param type - The type of two-factor provider to set as the selected provider. + */ + abstract setSelectedProvider(type: TwoFactorProviderType): Promise; + + /** + * Clears the selected two-factor provider from state. + */ + abstract clearSelectedProvider(): Promise; + + /** + * Sets the list of available two-factor providers in state. + * @param response - the response from Identity for when 2FA is required. Includes the list of available 2FA providers. + */ + abstract setProviders(response: IdentityTwoFactorResponse): Promise; + + /** + * Clears the list of available two-factor providers from state. + */ + abstract clearProviders(): Promise; + + /** + * Gets the list of two-factor providers from state. + * Note: no filtering is done here, so this will return all providers, including potentially + * unsupported ones for the current client. + * @returns A list of two-factor providers or null if none are stored in state. + */ + abstract getProviders(): Promise | null>; + + /** + * Gets the enabled two-factor providers for the current user from the API. + * Used for settings management. + * @returns A promise that resolves to a list response containing enabled two-factor provider configurations. + */ + abstract getEnabledTwoFactorProviders(): Promise>; + + /** + * Gets the enabled two-factor providers for an organization from the API. + * Requires organization administrator permissions. + * Used for settings management. + * + * @param organizationId The ID of the organization. + * @returns A promise that resolves to a list response containing enabled two-factor provider configurations. + */ + abstract getTwoFactorOrganizationProviders( + organizationId: string, + ): Promise>; + + /** + * Gets the authenticator (TOTP) two-factor configuration for the current user from the API. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link SecretVerificationRequest} to prove authentication. + * @returns A promise that resolves to the authenticator configuration including the secret key. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorAuthenticator( + request: SecretVerificationRequest, + ): Promise; + + /** + * Gets the email two-factor configuration for the current user from the API. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link SecretVerificationRequest} to prove authentication. + * @returns A promise that resolves to the email two-factor configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorEmail(request: SecretVerificationRequest): Promise; + + /** + * Gets the Duo two-factor configuration for the current user from the API. + * Requires user verification and an active premium subscription. + * Used for settings management. + * + * @param request The {@link SecretVerificationRequest} to prove authentication. + * @returns A promise that resolves to the Duo configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorDuo(request: SecretVerificationRequest): Promise; + + /** + * Gets the Duo two-factor configuration for an organization from the API. + * Requires user verification and organization policy management permissions. + * Used for settings management. + * + * @param organizationId The ID of the organization. + * @param request The {@link SecretVerificationRequest} to prove authentication. + * @returns A promise that resolves to the organization Duo configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorOrganizationDuo( + organizationId: string, + request: SecretVerificationRequest, + ): Promise; + + /** + * Gets the YubiKey OTP two-factor configuration for the current user from the API. + * Requires user verification and an active premium subscription. + * Used for settings management. + * + * @param request The {@link SecretVerificationRequest} to prove authentication. + * @returns A promise that resolves to the YubiKey configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorYubiKey( + request: SecretVerificationRequest, + ): Promise; + + /** + * Gets the WebAuthn (FIDO2) two-factor configuration for the current user from the API. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link SecretVerificationRequest} to authentication. + * @returns A promise that resolves to the WebAuthn configuration including registered credentials. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorWebAuthn( + request: SecretVerificationRequest, + ): Promise; + + /** + * Gets a WebAuthn challenge for registering a new WebAuthn credential from the API. + * This must be called before putTwoFactorWebAuthn to obtain the cryptographic challenge + * required for credential creation. The challenge is used by the browser's WebAuthn API. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link SecretVerificationRequest} to prove authentication. + * @returns A promise that resolves to the credential creation options containing the challenge. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorWebAuthnChallenge( + request: SecretVerificationRequest, + ): Promise; + + /** + * Gets the recovery code configuration for the current user from the API. + * The recovery code should be stored securely by the user. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param verification The verification information to prove authentication. + * @returns A promise that resolves to the recovery code configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract getTwoFactorRecover( + request: SecretVerificationRequest, + ): Promise; + + /** + * Enables or updates the authenticator (TOTP) two-factor provider. + * Validates the provided token against the shared secret before enabling. + * The token must be generated by an authenticator app using the secret key. + * Used for settings management. + * + * @param request The {@link UpdateTwoFactorAuthenticatorRequest} to prove authentication. + * @returns A promise that resolves to the updated authenticator configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorAuthenticator( + request: UpdateTwoFactorAuthenticatorRequest, + ): Promise; + + /** + * Disables the authenticator (TOTP) two-factor provider for the current user. + * Requires user verification token to confirm the operation. + * Used for settings management. + * + * @param request The {@link DisableTwoFactorAuthenticatorRequest} to prove authentication. + * @returns A promise that resolves to the updated provider status. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract deleteTwoFactorAuthenticator( + request: DisableTwoFactorAuthenticatorRequest, + ): Promise; + + /** + * Enables or updates the email two-factor provider for the current user. + * Validates the email verification token sent via postTwoFactorEmailSetup before enabling. + * The token must match the code sent to the specified email address. + * Used for settings management. + * + * @param request The {@link UpdateTwoFactorEmailRequest} to prove authentication. + * @returns A promise that resolves to the updated email two-factor configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorEmail(request: UpdateTwoFactorEmailRequest): Promise; + + /** + * Enables or updates the Duo two-factor provider for the current user. + * Validates the Duo configuration (client ID, client secret, and host) before enabling. + * Requires user verification and an active premium subscription. + * Used for settings management. + * + * @param request The {@link UpdateTwoFactorDuoRequest} to prove authentication. + * @returns A promise that resolves to the updated Duo configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorDuo(request: UpdateTwoFactorDuoRequest): Promise; + + /** + * Enables or updates the Duo two-factor provider for an organization. + * Validates the Duo configuration (client ID, client secret, and host) before enabling. + * Requires user verification and organization policy management permissions. + * Used for settings management. + * + * @param organizationId The ID of the organization. + * @param request The {@link UpdateTwoFactorDuoRequest} to prove authentication. + * @returns A promise that resolves to the updated organization Duo configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorOrganizationDuo( + organizationId: string, + request: UpdateTwoFactorDuoRequest, + ): Promise; + + /** + * Enables or updates the YubiKey OTP two-factor provider for the current user. + * Validates each provided YubiKey by testing an OTP from the device. + * Supports up to 5 YubiKey devices. Empty key slots are allowed. + * Requires user verification and an active premium subscription. + * Used for settings management. + * + * @param request The {@link UpdateTwoFactorYubikeyOtpRequest} to prove authentication. + * @returns A promise that resolves to the updated YubiKey configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorYubiKey( + request: UpdateTwoFactorYubikeyOtpRequest, + ): Promise; + + /** + * Registers a new WebAuthn (FIDO2) credential for two-factor authentication for the current user. + * Must be called after getTwoFactorWebAuthnChallenge to complete the registration flow. + * The device response contains the signed challenge from the authenticator device. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link UpdateTwoFactorWebAuthnRequest} to prove authentication. + * @returns A promise that resolves to the updated WebAuthn configuration with the new credential. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorWebAuthn( + request: UpdateTwoFactorWebAuthnRequest, + ): Promise; + + /** + * Removes a specific WebAuthn (FIDO2) credential from the user's account. + * The credential will no longer be usable for two-factor authentication. + * Other registered WebAuthn credentials remain active. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link UpdateTwoFactorWebAuthnDeleteRequest} to prove authentication. + * @returns A promise that resolves to the updated WebAuthn configuration. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract deleteTwoFactorWebAuthn( + request: UpdateTwoFactorWebAuthnDeleteRequest, + ): Promise; + + /** + * Disables a specific two-factor provider for the current user. + * The provider will no longer be required or usable for authentication. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link TwoFactorProviderRequest} to prove authentication. + * @returns A promise that resolves to the updated provider status. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorDisable( + request: TwoFactorProviderRequest, + ): Promise; + + /** + * Disables a specific two-factor provider for an organization. + * The provider will no longer be available for organization members. + * Requires user verification and organization policy management permissions. + * Used for settings management. + * + * @param organizationId The ID of the organization. + * @param request The {@link TwoFactorProviderRequest} to prove authentication. + * @returns A promise that resolves to the updated provider status. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract putTwoFactorOrganizationDisable( + organizationId: string, + request: TwoFactorProviderRequest, + ): Promise; + + /** + * Initiates email two-factor setup by sending a verification code to the specified email address. + * This is the first step in enabling email two-factor authentication. + * The verification code must be provided to putTwoFactorEmail to complete setup. + * Only used during initial configuration, not during login flows. + * Requires user verification via master password or OTP. + * Used for settings management. + * + * @param request The {@link TwoFactorEmailRequest} to prove authentication. + * @returns A promise that resolves when the verification email has been sent. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract postTwoFactorEmailSetup(request: TwoFactorEmailRequest): Promise; + + /** + * Sends a two-factor authentication code via email during the login flow. + * Supports multiple authentication contexts including standard login, SSO, and passwordless flows. + * This is used to deliver codes during authentication, not during initial setup. + * May be called without authentication for login scenarios. + * Used during authentication flows. + * + * @param request The {@link TwoFactorEmailRequest} to prove authentication. + * @returns A promise that resolves when the authentication email has been sent. + * @remarks Use {@link UserVerificationService.buildRequest} to create the request object. + */ + abstract postTwoFactorEmail(request: TwoFactorEmailRequest): Promise; +} diff --git a/libs/common/src/auth/two-factor/index.ts b/libs/common/src/auth/two-factor/index.ts index 85e072403b7..fd6edf0ac3c 100644 --- a/libs/common/src/auth/two-factor/index.ts +++ b/libs/common/src/auth/two-factor/index.ts @@ -1,2 +1,2 @@ -export { TwoFactorApiService } from "./two-factor-api.service"; -export { DefaultTwoFactorApiService } from "./default-two-factor-api.service"; +export * from "./abstractions"; +export * from "./services"; diff --git a/libs/common/src/auth/two-factor/two-factor-api.service.spec.ts b/libs/common/src/auth/two-factor/services/default-two-factor-api.service.spec.ts similarity index 100% rename from libs/common/src/auth/two-factor/two-factor-api.service.spec.ts rename to libs/common/src/auth/two-factor/services/default-two-factor-api.service.spec.ts diff --git a/libs/common/src/auth/two-factor/default-two-factor-api.service.ts b/libs/common/src/auth/two-factor/services/default-two-factor-api.service.ts similarity index 99% rename from libs/common/src/auth/two-factor/default-two-factor-api.service.ts rename to libs/common/src/auth/two-factor/services/default-two-factor-api.service.ts index 93f7b207922..b9778e460ea 100644 --- a/libs/common/src/auth/two-factor/default-two-factor-api.service.ts +++ b/libs/common/src/auth/two-factor/services/default-two-factor-api.service.ts @@ -22,7 +22,7 @@ import { TwoFactorYubiKeyResponse } from "@bitwarden/common/auth/models/response import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { TwoFactorApiService } from "./two-factor-api.service"; +import { TwoFactorApiService } from "../abstractions/two-factor-api.service"; export class DefaultTwoFactorApiService implements TwoFactorApiService { constructor(private apiService: ApiService) {} diff --git a/libs/common/src/auth/two-factor/services/default-two-factor.service.ts b/libs/common/src/auth/two-factor/services/default-two-factor.service.ts new file mode 100644 index 00000000000..2acc4a7e939 --- /dev/null +++ b/libs/common/src/auth/two-factor/services/default-two-factor.service.ts @@ -0,0 +1,279 @@ +// FIXME: Update this file to be type safe and remove this and next line +// @ts-strict-ignore +import { firstValueFrom, map } from "rxjs"; + +import { TwoFactorApiService } from ".."; +import { ListResponse } from "../../../models/response/list.response"; +import { I18nService } from "../../../platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "../../../platform/abstractions/platform-utils.service"; +import { Utils } from "../../../platform/misc/utils"; +import { GlobalStateProvider } from "../../../platform/state"; +import { TwoFactorProviderType } from "../../enums/two-factor-provider-type"; +import { DisableTwoFactorAuthenticatorRequest } from "../../models/request/disable-two-factor-authenticator.request"; +import { SecretVerificationRequest } from "../../models/request/secret-verification.request"; +import { TwoFactorEmailRequest } from "../../models/request/two-factor-email.request"; +import { TwoFactorProviderRequest } from "../../models/request/two-factor-provider.request"; +import { UpdateTwoFactorAuthenticatorRequest } from "../../models/request/update-two-factor-authenticator.request"; +import { UpdateTwoFactorDuoRequest } from "../../models/request/update-two-factor-duo.request"; +import { UpdateTwoFactorEmailRequest } from "../../models/request/update-two-factor-email.request"; +import { UpdateTwoFactorWebAuthnDeleteRequest } from "../../models/request/update-two-factor-web-authn-delete.request"; +import { UpdateTwoFactorWebAuthnRequest } from "../../models/request/update-two-factor-web-authn.request"; +import { UpdateTwoFactorYubikeyOtpRequest } from "../../models/request/update-two-factor-yubikey-otp.request"; +import { IdentityTwoFactorResponse } from "../../models/response/identity-two-factor.response"; +import { TwoFactorAuthenticatorResponse } from "../../models/response/two-factor-authenticator.response"; +import { TwoFactorDuoResponse } from "../../models/response/two-factor-duo.response"; +import { TwoFactorEmailResponse } from "../../models/response/two-factor-email.response"; +import { TwoFactorProviderResponse } from "../../models/response/two-factor-provider.response"; +import { TwoFactorRecoverResponse } from "../../models/response/two-factor-recover.response"; +import { + TwoFactorWebAuthnResponse, + ChallengeResponse, +} from "../../models/response/two-factor-web-authn.response"; +import { TwoFactorYubiKeyResponse } from "../../models/response/two-factor-yubi-key.response"; +import { + PROVIDERS, + SELECTED_PROVIDER, + TwoFactorProviderDetails, + TwoFactorProviders, + TwoFactorService as TwoFactorServiceAbstraction, +} from "../abstractions/two-factor.service"; + +export class DefaultTwoFactorService implements TwoFactorServiceAbstraction { + private providersState = this.globalStateProvider.get(PROVIDERS); + private selectedState = this.globalStateProvider.get(SELECTED_PROVIDER); + readonly providers$ = this.providersState.state$.pipe( + map((providers) => Utils.recordToMap(providers)), + ); + readonly selected$ = this.selectedState.state$; + + constructor( + private i18nService: I18nService, + private platformUtilsService: PlatformUtilsService, + private globalStateProvider: GlobalStateProvider, + private twoFactorApiService: TwoFactorApiService, + ) {} + + init() { + TwoFactorProviders[TwoFactorProviderType.Email].name = this.i18nService.t("emailTitle"); + TwoFactorProviders[TwoFactorProviderType.Email].description = this.i18nService.t("emailDescV2"); + + TwoFactorProviders[TwoFactorProviderType.Authenticator].name = + this.i18nService.t("authenticatorAppTitle"); + TwoFactorProviders[TwoFactorProviderType.Authenticator].description = + this.i18nService.t("authenticatorAppDescV2"); + + TwoFactorProviders[TwoFactorProviderType.Duo].description = this.i18nService.t("duoDescV2"); + + TwoFactorProviders[TwoFactorProviderType.OrganizationDuo].name = + "Duo (" + this.i18nService.t("organization") + ")"; + TwoFactorProviders[TwoFactorProviderType.OrganizationDuo].description = + this.i18nService.t("duoOrganizationDesc"); + + TwoFactorProviders[TwoFactorProviderType.WebAuthn].name = this.i18nService.t("webAuthnTitle"); + TwoFactorProviders[TwoFactorProviderType.WebAuthn].description = + this.i18nService.t("webAuthnDesc"); + + TwoFactorProviders[TwoFactorProviderType.Yubikey].name = this.i18nService.t("yubiKeyTitleV2"); + TwoFactorProviders[TwoFactorProviderType.Yubikey].description = + this.i18nService.t("yubiKeyDesc"); + } + + async getSupportedProviders(win: Window): Promise { + const data = await firstValueFrom(this.providers$); + const providers: any[] = []; + if (data == null) { + return providers; + } + + if ( + data.has(TwoFactorProviderType.OrganizationDuo) && + this.platformUtilsService.supportsDuo() + ) { + providers.push(TwoFactorProviders[TwoFactorProviderType.OrganizationDuo]); + } + + if (data.has(TwoFactorProviderType.Authenticator)) { + providers.push(TwoFactorProviders[TwoFactorProviderType.Authenticator]); + } + + if (data.has(TwoFactorProviderType.Yubikey)) { + providers.push(TwoFactorProviders[TwoFactorProviderType.Yubikey]); + } + + if (data.has(TwoFactorProviderType.Duo) && this.platformUtilsService.supportsDuo()) { + providers.push(TwoFactorProviders[TwoFactorProviderType.Duo]); + } + + if ( + data.has(TwoFactorProviderType.WebAuthn) && + this.platformUtilsService.supportsWebAuthn(win) + ) { + providers.push(TwoFactorProviders[TwoFactorProviderType.WebAuthn]); + } + + if (data.has(TwoFactorProviderType.Email)) { + providers.push(TwoFactorProviders[TwoFactorProviderType.Email]); + } + + return providers; + } + + async getDefaultProvider(webAuthnSupported: boolean): Promise { + const data = await firstValueFrom(this.providers$); + const selected = await firstValueFrom(this.selected$); + if (data == null) { + return null; + } + + if (selected != null && data.has(selected)) { + return selected; + } + + let providerType: TwoFactorProviderType = null; + let providerPriority = -1; + data.forEach((_value, type) => { + const provider = (TwoFactorProviders as any)[type]; + if (provider != null && provider.priority > providerPriority) { + if (type === TwoFactorProviderType.WebAuthn && !webAuthnSupported) { + return; + } + + providerType = type; + providerPriority = provider.priority; + } + }); + + return providerType; + } + + async setSelectedProvider(type: TwoFactorProviderType): Promise { + await this.selectedState.update(() => type); + } + + async clearSelectedProvider(): Promise { + await this.selectedState.update(() => null); + } + + async setProviders(response: IdentityTwoFactorResponse): Promise { + await this.providersState.update(() => response.twoFactorProviders2); + } + + async clearProviders(): Promise { + await this.providersState.update(() => null); + } + + getProviders(): Promise | null> { + return firstValueFrom(this.providers$); + } + + getEnabledTwoFactorProviders(): Promise> { + return this.twoFactorApiService.getTwoFactorProviders(); + } + + getTwoFactorOrganizationProviders( + organizationId: string, + ): Promise> { + return this.twoFactorApiService.getTwoFactorOrganizationProviders(organizationId); + } + + getTwoFactorAuthenticator( + request: SecretVerificationRequest, + ): Promise { + return this.twoFactorApiService.getTwoFactorAuthenticator(request); + } + + getTwoFactorEmail(request: SecretVerificationRequest): Promise { + return this.twoFactorApiService.getTwoFactorEmail(request); + } + + getTwoFactorDuo(request: SecretVerificationRequest): Promise { + return this.twoFactorApiService.getTwoFactorDuo(request); + } + + getTwoFactorOrganizationDuo( + organizationId: string, + request: SecretVerificationRequest, + ): Promise { + return this.twoFactorApiService.getTwoFactorOrganizationDuo(organizationId, request); + } + + getTwoFactorYubiKey(request: SecretVerificationRequest): Promise { + return this.twoFactorApiService.getTwoFactorYubiKey(request); + } + + getTwoFactorWebAuthn(request: SecretVerificationRequest): Promise { + return this.twoFactorApiService.getTwoFactorWebAuthn(request); + } + + getTwoFactorWebAuthnChallenge(request: SecretVerificationRequest): Promise { + return this.twoFactorApiService.getTwoFactorWebAuthnChallenge(request); + } + + getTwoFactorRecover(request: SecretVerificationRequest): Promise { + return this.twoFactorApiService.getTwoFactorRecover(request); + } + + putTwoFactorAuthenticator( + request: UpdateTwoFactorAuthenticatorRequest, + ): Promise { + return this.twoFactorApiService.putTwoFactorAuthenticator(request); + } + + deleteTwoFactorAuthenticator( + request: DisableTwoFactorAuthenticatorRequest, + ): Promise { + return this.twoFactorApiService.deleteTwoFactorAuthenticator(request); + } + + putTwoFactorEmail(request: UpdateTwoFactorEmailRequest): Promise { + return this.twoFactorApiService.putTwoFactorEmail(request); + } + + putTwoFactorDuo(request: UpdateTwoFactorDuoRequest): Promise { + return this.twoFactorApiService.putTwoFactorDuo(request); + } + + putTwoFactorOrganizationDuo( + organizationId: string, + request: UpdateTwoFactorDuoRequest, + ): Promise { + return this.twoFactorApiService.putTwoFactorOrganizationDuo(organizationId, request); + } + + putTwoFactorYubiKey( + request: UpdateTwoFactorYubikeyOtpRequest, + ): Promise { + return this.twoFactorApiService.putTwoFactorYubiKey(request); + } + + putTwoFactorWebAuthn( + request: UpdateTwoFactorWebAuthnRequest, + ): Promise { + return this.twoFactorApiService.putTwoFactorWebAuthn(request); + } + + deleteTwoFactorWebAuthn( + request: UpdateTwoFactorWebAuthnDeleteRequest, + ): Promise { + return this.twoFactorApiService.deleteTwoFactorWebAuthn(request); + } + + putTwoFactorDisable(request: TwoFactorProviderRequest): Promise { + return this.twoFactorApiService.putTwoFactorDisable(request); + } + + putTwoFactorOrganizationDisable( + organizationId: string, + request: TwoFactorProviderRequest, + ): Promise { + return this.twoFactorApiService.putTwoFactorOrganizationDisable(organizationId, request); + } + + postTwoFactorEmailSetup(request: TwoFactorEmailRequest): Promise { + return this.twoFactorApiService.postTwoFactorEmailSetup(request); + } + + postTwoFactorEmail(request: TwoFactorEmailRequest): Promise { + return this.twoFactorApiService.postTwoFactorEmail(request); + } +} diff --git a/libs/common/src/auth/two-factor/services/index.ts b/libs/common/src/auth/two-factor/services/index.ts new file mode 100644 index 00000000000..283f7b34631 --- /dev/null +++ b/libs/common/src/auth/two-factor/services/index.ts @@ -0,0 +1,2 @@ +export * from "./default-two-factor-api.service"; +export * from "./default-two-factor.service"; diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index d06a14d242f..17d5f4e9df5 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -16,7 +16,6 @@ export enum FeatureFlag { BlockClaimedDomainAccountCreation = "block-claimed-domain-account-creation", /* Auth */ - PM22110_DisableAlternateLoginMethods = "pm-22110-disable-alternate-login-methods", PM23801_PrefetchPasswordPrelogin = "pm-23801-prefetch-password-prelogin", /* Autofill */ @@ -118,7 +117,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.VaultLoadingSkeletons]: FALSE, /* Auth */ - [FeatureFlag.PM22110_DisableAlternateLoginMethods]: FALSE, [FeatureFlag.PM23801_PrefetchPasswordPrelogin]: FALSE, /* Billing */ diff --git a/libs/components/src/button/button.component.ts b/libs/components/src/button/button.component.ts index 0e50ccbe87a..7cae8fe974d 100644 --- a/libs/components/src/button/button.component.ts +++ b/libs/components/src/button/button.component.ts @@ -54,6 +54,14 @@ const buttonStyles: Record = { "hover:!tw-text-contrast", ...focusRing, ], + dangerPrimary: [ + "tw-border-danger-600", + "tw-bg-danger-600", + "!tw-text-contrast", + "hover:tw-bg-danger-700", + "hover:tw-border-danger-700", + ...focusRing, + ], unstyled: [], }; diff --git a/libs/components/src/button/button.stories.ts b/libs/components/src/button/button.stories.ts index 7319b47bce5..29c4dea3088 100644 --- a/libs/components/src/button/button.stories.ts +++ b/libs/components/src/button/button.stories.ts @@ -62,6 +62,13 @@ export const Primary: Story = { }, }; +export const DangerPrimary: Story = { + ...Default, + args: { + buttonType: "dangerPrimary", + }, +}; + export const Danger: Story = { ...Default, args: { @@ -77,6 +84,7 @@ export const Small: Story = { + `, }), diff --git a/libs/components/src/form-control/form-control.module.ts b/libs/components/src/form-control/form-control.module.ts index 2646f36ecd3..d87284adbcd 100644 --- a/libs/components/src/form-control/form-control.module.ts +++ b/libs/components/src/form-control/form-control.module.ts @@ -1,11 +1,11 @@ import { NgModule } from "@angular/core"; import { FormControlComponent } from "./form-control.component"; -import { BitHintComponent } from "./hint.component"; +import { BitHintDirective } from "./hint.directive"; import { BitLabelComponent } from "./label.component"; @NgModule({ - imports: [BitLabelComponent, FormControlComponent, BitHintComponent], - exports: [FormControlComponent, BitLabelComponent, BitHintComponent], + imports: [BitLabelComponent, FormControlComponent, BitHintDirective], + exports: [FormControlComponent, BitLabelComponent, BitHintDirective], }) export class FormControlModule {} diff --git a/libs/components/src/form-control/hint.component.ts b/libs/components/src/form-control/hint.directive.ts similarity index 90% rename from libs/components/src/form-control/hint.component.ts rename to libs/components/src/form-control/hint.directive.ts index c1f21bf2545..110aefc30e7 100644 --- a/libs/components/src/form-control/hint.component.ts +++ b/libs/components/src/form-control/hint.directive.ts @@ -9,6 +9,6 @@ let nextId = 0; class: "tw-text-muted tw-font-normal tw-inline-block tw-mt-1 tw-text-xs", }, }) -export class BitHintComponent { +export class BitHintDirective { @HostBinding() id = `bit-hint-${nextId++}`; } diff --git a/libs/components/src/form-field/form-field.component.ts b/libs/components/src/form-field/form-field.component.ts index 3d49a58b1fc..10cf33b8257 100644 --- a/libs/components/src/form-field/form-field.component.ts +++ b/libs/components/src/form-field/form-field.component.ts @@ -15,7 +15,7 @@ import { import { I18nPipe } from "@bitwarden/ui-common"; -import { BitHintComponent } from "../form-control/hint.component"; +import { BitHintDirective } from "../form-control/hint.directive"; import { BitLabelComponent } from "../form-control/label.component"; import { inputBorderClasses } from "../input/input.directive"; @@ -31,7 +31,7 @@ import { BitFormFieldControl } from "./form-field-control"; }) export class BitFormFieldComponent implements AfterContentChecked { readonly input = contentChild.required(BitFormFieldControl); - readonly hint = contentChild(BitHintComponent); + readonly hint = contentChild(BitHintDirective); readonly label = contentChild(BitLabelComponent); readonly prefixContainer = viewChild>("prefixContainer"); diff --git a/libs/components/src/shared/button-like.abstraction.ts b/libs/components/src/shared/button-like.abstraction.ts index 63391743837..45a661b6ecb 100644 --- a/libs/components/src/shared/button-like.abstraction.ts +++ b/libs/components/src/shared/button-like.abstraction.ts @@ -1,6 +1,6 @@ import { ModelSignal } from "@angular/core"; -export type ButtonType = "primary" | "secondary" | "danger" | "unstyled"; +export type ButtonType = "primary" | "secondary" | "danger" | "dangerPrimary" | "unstyled"; export type ButtonSize = "default" | "small"; diff --git a/libs/components/src/switch/switch.component.ts b/libs/components/src/switch/switch.component.ts index 30e1ac59d48..a93e274e8bb 100644 --- a/libs/components/src/switch/switch.component.ts +++ b/libs/components/src/switch/switch.component.ts @@ -13,7 +13,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms"; import { AriaDisableDirective } from "../a11y"; import { FormControlModule } from "../form-control/form-control.module"; -import { BitHintComponent } from "../form-control/hint.component"; +import { BitHintDirective } from "../form-control/hint.directive"; import { BitLabelComponent } from "../form-control/label.component"; let nextId = 0; @@ -56,7 +56,7 @@ export class SwitchComponent implements ControlValueAccessor, AfterViewInit { protected readonly disabled = model(false); protected readonly disabledReasonText = input(null); - private readonly hintComponent = contentChild(BitHintComponent); + private readonly hintComponent = contentChild(BitHintDirective); protected readonly disabledReasonTextId = `bit-switch-disabled-text-${nextId++}`; diff --git a/libs/components/src/table/table-scroll.component.ts b/libs/components/src/table/table-scroll.component.ts index fcdd401a1a2..1ccb49a85e5 100644 --- a/libs/components/src/table/table-scroll.component.ts +++ b/libs/components/src/table/table-scroll.component.ts @@ -35,7 +35,7 @@ import { TableComponent } from "./table.component"; @Directive({ selector: "[bitRowDef]", }) -export class BitRowDef { +export class BitRowDefDirective { constructor(public template: TemplateRef) {} } @@ -69,7 +69,7 @@ export class TableScrollComponent /** Optional trackBy function. */ readonly trackBy = input | undefined>(); - protected readonly rowDef = contentChild(BitRowDef); + protected readonly rowDef = contentChild(BitRowDefDirective); /** * Height of the thead element (in pixels). diff --git a/libs/components/src/table/table.module.ts b/libs/components/src/table/table.module.ts index 68993612772..5e44f604481 100644 --- a/libs/components/src/table/table.module.ts +++ b/libs/components/src/table/table.module.ts @@ -5,14 +5,14 @@ import { NgModule } from "@angular/core"; import { CellDirective } from "./cell.directive"; import { RowDirective } from "./row.directive"; import { SortableComponent } from "./sortable.component"; -import { BitRowDef, TableScrollComponent } from "./table-scroll.component"; +import { BitRowDefDirective, TableScrollComponent } from "./table-scroll.component"; import { TableBodyDirective, TableComponent } from "./table.component"; @NgModule({ imports: [ CommonModule, ScrollingModule, - BitRowDef, + BitRowDefDirective, CellDirective, RowDirective, SortableComponent, @@ -21,7 +21,7 @@ import { TableBodyDirective, TableComponent } from "./table.component"; TableScrollComponent, ], exports: [ - BitRowDef, + BitRowDefDirective, CellDirective, RowDirective, SortableComponent, diff --git a/libs/eslint/platform/index.mjs b/libs/eslint/platform/index.mjs index c7ea3f1dd89..be78df43e3f 100644 --- a/libs/eslint/platform/index.mjs +++ b/libs/eslint/platform/index.mjs @@ -1,4 +1,11 @@ import requiredUsing from "./required-using.mjs"; import noEnums from "./no-enums.mjs"; +import noPageScriptUrlLeakage from "./no-page-script-url-leakage.mjs"; -export default { rules: { "required-using": requiredUsing, "no-enums": noEnums } }; +export default { + rules: { + "required-using": requiredUsing, + "no-enums": noEnums, + "no-page-script-url-leakage": noPageScriptUrlLeakage, + }, +}; diff --git a/libs/eslint/platform/no-page-script-url-leakage.mjs b/libs/eslint/platform/no-page-script-url-leakage.mjs new file mode 100644 index 00000000000..fe13c496a62 --- /dev/null +++ b/libs/eslint/platform/no-page-script-url-leakage.mjs @@ -0,0 +1,115 @@ +/** + * @fileoverview ESLint rule to prevent page script URL leakage vulnerabilities + * @description This rule detects the specific security vulnerability where DOM script elements + * receive extension URLs through chrome.runtime.getURL() or browser.runtime.getURL() calls. + * This pattern exposes predictable extension URLs to web pages, enabling fingerprinting attacks. + */ + +export const errorMessage = + "Script injection with extension URL exposes asset urls. Use secure page script registration instead."; + +/** + * Checks if a node is a call to chrome.runtime.getURL() or browser.runtime.getURL() + * @param {Object} node - The AST node to check + * @returns {boolean} True if the node is an extension URL call + */ +function isExtensionURLCall(node) { + return ( + node && + node.type === "CallExpression" && + node.callee && + node.callee.type === "MemberExpression" && + node.callee.object && + node.callee.object.type === "MemberExpression" && + node.callee.object.object && + ["chrome", "browser"].includes(node.callee.object.object.name) && + node.callee.object.property && + node.callee.object.property.name === "runtime" && + node.callee.property && + node.callee.property.name === "getURL" + ); +} + +/** + * Checks if a node is a call to createElement("script") + * @param {Object} node - The AST node to check + * @returns {boolean} True if the node creates a script element + */ +function isScriptCreation(node) { + return ( + node && + node.type === "CallExpression" && + node.callee && + node.callee.type === "MemberExpression" && + node.callee.property && + node.callee.property.name === "createElement" && + node.arguments && + node.arguments.length === 1 && + node.arguments[0] && + node.arguments[0].type === "Literal" && + node.arguments[0].value === "script" + ); +} + +export default { + meta: { + type: "problem", + docs: { + description: "Prevent page script URL leakage through extension runtime.getURL calls", + category: "Security", + recommended: true, + }, + schema: [], + messages: { + pageScriptUrlLeakage: errorMessage, + }, + }, + + create(context) { + const scriptVariables = new Set(); + + return { + // Track createElement("script") calls to identify script variables + VariableDeclarator(node) { + if (node.init && isScriptCreation(node.init) && node.id && node.id.name) { + scriptVariables.add(node.id.name); + } + }, + + // Track assignments where script elements are created + AssignmentExpression(node) { + // Track script element creation: variable = document.createElement("script") + if ( + node.operator === "=" && + node.left && + node.left.type === "Identifier" && + isScriptCreation(node.right) + ) { + scriptVariables.add(node.left.name); + } + + // Check for script.src = extension URL pattern + if ( + node.operator === "=" && + node.left && + node.left.type === "MemberExpression" && + node.left.property && + node.left.property.name === "src" && + isExtensionURLCall(node.right) + ) { + // Only flag if this is a script element assignment + if ( + node.left.object && + node.left.object.type === "Identifier" && + scriptVariables.has(node.left.object.name) + ) { + context.report({ + node: node.right, + messageId: "pageScriptUrlLeakage", + }); + } + } + }, + }; + }, +}; diff --git a/libs/eslint/platform/no-page-script-url-leakage.spec.mjs b/libs/eslint/platform/no-page-script-url-leakage.spec.mjs new file mode 100644 index 00000000000..77e1c4d1697 --- /dev/null +++ b/libs/eslint/platform/no-page-script-url-leakage.spec.mjs @@ -0,0 +1,151 @@ +import { RuleTester } from "@typescript-eslint/rule-tester"; + +import rule, { errorMessage } from "./no-page-script-url-leakage.mjs"; + +const ruleTester = new RuleTester({ + languageOptions: { + parserOptions: { + project: [__dirname + "/../tsconfig.spec.json"], + projectService: { + allowDefaultProject: ["*.ts*"], + }, + tsconfigRootDir: __dirname + "/..", + }, + }, +}); + +ruleTester.run("no-page-script-url-leakage", rule.default, { + valid: [ + { + name: "Non-script element with extension URL (iframe)", + code: ` + const iframe = document.createElement("iframe"); + iframe.src = chrome.runtime.getURL("popup.html"); + `, + }, + { + name: "Non-script element with extension URL (img)", + code: ` + const img = document.createElement("img"); + img.src = chrome.runtime.getURL("icon.png"); + `, + }, + { + name: "Script element with non-extension URL", + code: ` + const script = document.createElement("script"); + script.src = "https://example.com/script.js"; + `, + }, + { + name: "Extension URL call without DOM assignment", + code: ` + const url = chrome.runtime.getURL("assets/icon.png"); + console.log(url); + `, + }, + { + name: "Browser runtime call without DOM assignment", + code: ` + const url = browser.runtime.getURL("content/style.css"); + fetch(url); + `, + }, + { + name: "Script assignment with variable not from createElement", + code: ` + const script = getSomeScriptElement(); + script.src = chrome.runtime.getURL("script.js"); + `, + }, + { + name: "Assignment to different property", + code: ` + const script = document.createElement("script"); + script.type = "text/javascript"; + `, + }, + ], + invalid: [ + { + name: "Script element with chrome.runtime.getURL - variable declaration", + code: ` + const script = document.createElement("script"); + script.src = chrome.runtime.getURL("content/script.js"); + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + { + name: "Script element with browser.runtime.getURL - variable declaration", + code: ` + const script = document.createElement("script"); + script.src = browser.runtime.getURL("content/script.js"); + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + { + name: "Script element with chrome.runtime.getURL - assignment expression", + code: ` + let script; + script = document.createElement("script"); + script.src = chrome.runtime.getURL("page-script.js"); + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + { + name: "Script element with browser.runtime.getURL - assignment expression", + code: ` + let element; + element = document.createElement("script"); + element.src = browser.runtime.getURL("fido2-page-script.js"); + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + { + name: "Multiple script elements with different variable names", + code: ` + const scriptA = document.createElement("script"); + const scriptB = document.createElement("script"); + scriptA.src = chrome.runtime.getURL("script-a.js"); + scriptB.src = browser.runtime.getURL("script-b.js"); + `, + errors: [ + { + message: errorMessage, + }, + { + message: errorMessage, + }, + ], + }, + { + name: "Real-world pattern that prompted creation of this lint rule", + code: ` + const script = globalThis.document.createElement("script"); + script.src = chrome.runtime.getURL("content/fido2-page-script.js"); + script.async = false; + `, + errors: [ + { + message: errorMessage, + }, + ], + }, + ], +}); diff --git a/libs/vault/src/directives/readonly-textarea.directive.ts b/libs/vault/src/directives/readonly-textarea.directive.ts index 65bd9d6e353..17c5f865fb3 100644 --- a/libs/vault/src/directives/readonly-textarea.directive.ts +++ b/libs/vault/src/directives/readonly-textarea.directive.ts @@ -8,6 +8,8 @@ import { firstValueFrom } from "rxjs"; providers: [TextFieldModule], hostDirectives: [CdkTextareaAutosize], }) +// FIXME(https://bitwarden.atlassian.net/browse/PM-28232): Use Directive suffix +// eslint-disable-next-line @angular-eslint/directive-class-suffix export class VaultAutosizeReadOnlyTextArea implements AfterViewInit { constructor( @Host() private autosize: CdkTextareaAutosize, diff --git a/package-lock.json b/package-lock.json index dbb3fdb7e2d..9ec580e3a5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,13 +32,13 @@ "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", "@ng-select/ng-select": "14.9.0", - "@nx/devkit": "21.3.11", - "@nx/eslint": "21.3.11", - "@nx/jest": "21.3.11", - "@nx/js": "21.3.11", - "@nx/webpack": "21.3.11", + "@nx/devkit": "21.6.8", + "@nx/eslint": "21.6.8", + "@nx/jest": "21.6.8", + "@nx/js": "21.6.8", + "@nx/webpack": "21.6.8", "big-integer": "1.6.52", - "braintree-web-drop-in": "1.44.0", + "braintree-web-drop-in": "1.46.0", "buffer": "6.0.3", "bufferutil": "4.0.9", "chalk": "4.1.2", @@ -49,7 +49,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.2", + "koa": "2.16.3", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lit": "3.3.0", @@ -159,7 +159,7 @@ "json5": "2.2.3", "lint-staged": "16.0.0", "mini-css-extract-plugin": "2.9.2", - "nx": "21.3.11", + "nx": "21.6.8", "postcss": "8.5.3", "postcss-loader": "8.1.1", "prettier": "3.6.2", @@ -213,7 +213,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.2", + "koa": "2.16.3", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lowdb": "1.0.0", @@ -2906,14 +2906,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -3025,9 +3025,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3057,25 +3057,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.0" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -4535,17 +4535,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -4553,13 +4553,13 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -4569,13 +4569,13 @@ } }, "node_modules/@babel/types": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -4798,15 +4798,15 @@ "link": true }, "node_modules/@braintree/asset-loader": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@braintree/asset-loader/-/asset-loader-2.0.1.tgz", - "integrity": "sha512-OGAoBA5MRVsr5qg0sXM6NMJbqHnYZhBudtM6WGgpQnoX42fjUYbE6Y6qFuuerD5z3lsOAjnu80DooBs1VBuh5Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@braintree/asset-loader/-/asset-loader-2.0.3.tgz", + "integrity": "sha512-uREap1j30wKRlC0mK99nNPMpEp77NtB6XixpDfFJPZHmkrmw7IB4skKe+26LZBK1H6oSainFhAyKoP7x3eyOKA==", "license": "MIT" }, "node_modules/@braintree/browser-detection": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@braintree/browser-detection/-/browser-detection-2.0.1.tgz", - "integrity": "sha512-wpRI7AXEUh6o3ILrJbpNOYE7ItfjX/S8JZP7Z5FF66ULngBGYOqE8SeLlLKXG69Nc07HtlL/6nk/h539iz9hcQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@braintree/browser-detection/-/browser-detection-2.0.2.tgz", + "integrity": "sha512-Zrv/pyodvwv/hsjsBKXKVcwHZOkx4A/5Cy2hViXtqghAhLd3483bYUIfHZJE5JKTrd018ny1FI5pN1PHFtW7vw==", "license": "MIT" }, "node_modules/@braintree/event-emitter": { @@ -4822,9 +4822,9 @@ "license": "MIT" }, "node_modules/@braintree/iframer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@braintree/iframer/-/iframer-2.0.0.tgz", - "integrity": "sha512-x1kHOyIJNDvi4P1s6pVBZhqhBa1hqDG9+yzcsCR1oNVC0LxH9CAP8bKxioT8/auY1sUyy+D8T4Vp/jv7QqSqLQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@braintree/iframer/-/iframer-2.0.1.tgz", + "integrity": "sha512-t1zJX5+f1yxHAzBJPaQT/XVMocKodUqjTE+hYvuxxWjqEZIbH8/eT5b5n767jY16mYw3+XiDkKHqcp4Pclq1wg==", "license": "MIT" }, "node_modules/@braintree/sanitize-url": { @@ -4834,9 +4834,9 @@ "license": "MIT" }, "node_modules/@braintree/uuid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@braintree/uuid/-/uuid-1.0.0.tgz", - "integrity": "sha512-AtI5hfttWSuWAgcwLUZdcZ7Fp/8jCCUf9JTs7+Xow9ditU28zuoBovqq083yph2m3SxPYb84lGjOq+cXlXBvJg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@braintree/uuid/-/uuid-1.0.1.tgz", + "integrity": "sha512-Tgu5GoODkf4oj4aLlVIapEPEfjitIHrg5ftqY6pa5Ghr4ZUA9XtZIIZ6ZPdP9x8/X0lt/FB8tRq83QuCQCwOrA==", "license": "ISC" }, "node_modules/@braintree/wrap-promise": { @@ -7679,9 +7679,9 @@ } }, "node_modules/@jest/get-type": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.0.1.tgz", - "integrity": "sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -7828,12 +7828,12 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.0.5.tgz", - "integrity": "sha512-XcCQ5qWHLvi29UUrowgDFvV4t7ETxX91CbDczMnoqXPOIcZOxyNdSjm6kV5XMc8+HkxfRegU/MUmnTbJRzGrUQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -7855,9 +7855,9 @@ } }, "node_modules/@jest/snapshot-utils/node_modules/@jest/types": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz", - "integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -7873,9 +7873,9 @@ } }, "node_modules/@jest/snapshot-utils/node_modules/@sinclair/typebox": { - "version": "0.34.38", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.38.tgz", - "integrity": "sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA==", + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", "license": "MIT" }, "node_modules/@jest/source-map": { @@ -7986,6 +7986,16 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -9393,9 +9403,9 @@ } }, "node_modules/@nx/devkit": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-21.3.11.tgz", - "integrity": "sha512-JOV8TAa9K5+ZwTA/EUi0g5qcKEg5vmi0AyOUsrNUHlv3BgQnwZtPLDDTPPZ+ezq24o6YzgwueZWj3CLEdMHEDg==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-21.6.8.tgz", + "integrity": "sha512-N0cj0NqdxY2pcI0IJV+fAu362B6tppdv2ohSBNGacNeSqxfAlJxO5TFZePDmxX5nt0t9hAqT+iasfu4BSYGfZw==", "license": "MIT", "dependencies": { "ejs": "^3.1.7", @@ -9403,12 +9413,11 @@ "ignore": "^5.0.4", "minimatch": "9.0.3", "semver": "^7.5.3", - "tmp": "~0.2.1", "tslib": "^2.3.0", "yargs-parser": "21.1.1" }, "peerDependencies": { - "nx": "21.3.11" + "nx": ">= 20 <= 22" } }, "node_modules/@nx/devkit/node_modules/ignore": { @@ -9421,16 +9430,16 @@ } }, "node_modules/@nx/eslint": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-21.3.11.tgz", - "integrity": "sha512-9jeD8QuU3OMcItjtw0QHl5cwohLeA9R+lajNJoOjS2tUGXTHWb8NOcEZBXWMcML+eV1iloIDW8/P4jV4BYqP2w==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-21.6.8.tgz", + "integrity": "sha512-dloTsg1n1zlAyP2Ohwiw9vhoUrF5XYo5pdmxAmnpE/P+e4ihWQfGtlu3JvEQNBp9Wwk4E7XkJVmVhJOm47PIww==", "license": "MIT", "dependencies": { - "@nx/devkit": "21.3.11", - "@nx/js": "21.3.11", + "@nx/devkit": "21.6.8", + "@nx/js": "21.6.8", "semver": "^7.5.3", "tslib": "^2.3.0", - "typescript": "~5.8.2" + "typescript": "~5.9.2" }, "peerDependencies": { "@zkochan/js-yaml": "0.0.7", @@ -9442,16 +9451,29 @@ } } }, + "node_modules/@nx/eslint/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@nx/jest": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-21.3.11.tgz", - "integrity": "sha512-PkdNWeoUY81zr+jtUapBdvvh26lWYIhDNyUwTjIBFajX8EAlhJpvShKHs7QObmrwOMLMXwLHKINiSCw9rueOBQ==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-21.6.8.tgz", + "integrity": "sha512-2RpDTbh6Q/sp0ryxJmi4oY8xOaR4Us6gc91BzTFYSrzG0cX4Q/lFTiIAbV8bXY1UTJ5HMgJobHAy5Sbcfo6TeQ==", "license": "MIT", "dependencies": { "@jest/reporters": "^30.0.2", "@jest/test-result": "^30.0.2", - "@nx/devkit": "21.3.11", - "@nx/js": "21.3.11", + "@nx/devkit": "21.6.8", + "@nx/js": "21.6.8", "@phenomnomnominal/tsquery": "~5.0.1", "identity-obj-proxy": "3.0.0", "jest-config": "^30.0.2", @@ -9466,21 +9488,21 @@ } }, "node_modules/@nx/jest/node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -9505,13 +9527,13 @@ } }, "node_modules/@nx/jest/node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -9521,16 +9543,16 @@ } }, "node_modules/@nx/jest/node_modules/@jest/console": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.0.5.tgz", - "integrity": "sha512-xY6b0XiL0Nav3ReresUarwl2oIz1gTnxGbGpho9/rbUWsLH0f1OD/VT84xs8c7VmH7MChnLb0pag6PhZhAdDiA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", - "jest-message-util": "30.0.5", - "jest-util": "30.0.5", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", "slash": "^3.0.0" }, "engines": { @@ -9538,88 +9560,88 @@ } }, "node_modules/@nx/jest/node_modules/@jest/environment": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.0.5.tgz", - "integrity": "sha512-aRX7WoaWx1oaOkDQvCWImVQ8XNtdv5sEWgk4gxR6NXb7WBUnL5sRak4WRzIQRZ1VTWPvV4VI4mgGjNL9TeKMYA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.0.5", - "@jest/types": "30.0.5", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-mock": "30.0.5" + "jest-mock": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/@jest/expect": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.0.5.tgz", - "integrity": "sha512-6udac8KKrtTtC+AXZ2iUN/R7dp7Ydry+Fo6FPFnDG54wjVMnb6vW/XNlf7Xj8UDjAE3aAVAsR4KFyKk3TCXmTA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", "license": "MIT", "dependencies": { - "expect": "30.0.5", - "jest-snapshot": "30.0.5" + "expect": "30.2.0", + "jest-snapshot": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/@jest/expect-utils": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.5.tgz", - "integrity": "sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", "license": "MIT", "dependencies": { - "@jest/get-type": "30.0.1" + "@jest/get-type": "30.1.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/@jest/fake-timers": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.0.5.tgz", - "integrity": "sha512-ZO5DHfNV+kgEAeP3gK3XlpJLL4U3Sz6ebl/n68Uwt64qFFs5bv4bfEEjyRGK5uM0C90ewooNgFuKMdkbEoMEXw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", - "jest-message-util": "30.0.5", - "jest-mock": "30.0.5", - "jest-util": "30.0.5" + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/@jest/globals": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.0.5.tgz", - "integrity": "sha512-7oEJT19WW4oe6HR7oLRvHxwlJk2gev0U9px3ufs8sX9PoD1Eza68KF0/tlN7X0dq/WVsBScXQGgCldA1V9Y/jA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", "license": "MIT", "dependencies": { - "@jest/environment": "30.0.5", - "@jest/expect": "30.0.5", - "@jest/types": "30.0.5", - "jest-mock": "30.0.5" + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/@jest/reporters": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.0.5.tgz", - "integrity": "sha512-mafft7VBX4jzED1FwGC1o/9QUM2xebzavImZMeqnsklgcyxBto8mV4HzNSzUrryJ+8R9MFOM3HgYuDradWR+4g==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.0.5", - "@jest/test-result": "30.0.5", - "@jest/transform": "30.0.5", - "@jest/types": "30.0.5", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", "chalk": "^4.1.2", @@ -9632,9 +9654,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.0.5", - "jest-util": "30.0.5", - "jest-worker": "30.0.5", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" @@ -9678,13 +9700,13 @@ } }, "node_modules/@nx/jest/node_modules/@jest/test-result": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.0.5.tgz", - "integrity": "sha512-wPyztnK0gbDMQAJZ43tdMro+qblDHH1Ru/ylzUo21TBKqt88ZqnKKK2m30LKmLLoKtR2lxdpCC/P3g1vfKcawQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", "license": "MIT", "dependencies": { - "@jest/console": "30.0.5", - "@jest/types": "30.0.5", + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -9693,14 +9715,14 @@ } }, "node_modules/@nx/jest/node_modules/@jest/test-sequencer": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.0.5.tgz", - "integrity": "sha512-Aea/G1egWoIIozmDD7PBXUOxkekXl7ueGzrsGGi1SbeKgQqCYCIf+wfbflEbf2LiPxL8j2JZGLyrzZagjvW4YQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", "license": "MIT", "dependencies": { - "@jest/test-result": "30.0.5", + "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.0.5", + "jest-haste-map": "30.2.0", "slash": "^3.0.0" }, "engines": { @@ -9708,22 +9730,22 @@ } }, "node_modules/@nx/jest/node_modules/@jest/transform": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz", - "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.0", + "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.0.5", + "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", @@ -9734,9 +9756,9 @@ } }, "node_modules/@nx/jest/node_modules/@jest/types": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz", - "integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -9752,9 +9774,9 @@ } }, "node_modules/@nx/jest/node_modules/@sinclair/typebox": { - "version": "0.34.38", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.38.tgz", - "integrity": "sha512-HpkxMmc2XmZKhvaKIZZThlHmx1L0I/V1hWK1NubtlFnr6ZqdiOpV72TKudZUNQjZNsyDBay72qFEhEvb+bcwcA==", + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", "license": "MIT" }, "node_modules/@nx/jest/node_modules/@sinonjs/fake-timers": { @@ -9779,15 +9801,15 @@ } }, "node_modules/@nx/jest/node_modules/babel-jest": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.0.5.tgz", - "integrity": "sha512-mRijnKimhGDMsizTvBTWotwNpzrkHr+VvZUQBof2AufXKB8NXrL1W69TG20EvOz7aevx6FTJIaBuBkYxS8zolg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", "license": "MIT", "dependencies": { - "@jest/transform": "30.0.5", + "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", - "babel-plugin-istanbul": "^7.0.0", - "babel-preset-jest": "30.0.1", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -9796,14 +9818,17 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.11.0" + "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "node_modules/@nx/jest/node_modules/babel-plugin-istanbul": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz", - "integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -9816,13 +9841,11 @@ } }, "node_modules/@nx/jest/node_modules/babel-plugin-jest-hoist": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz", - "integrity": "sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", "@types/babel__core": "^7.20.5" }, "engines": { @@ -9830,19 +9853,19 @@ } }, "node_modules/@nx/jest/node_modules/babel-preset-jest": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz", - "integrity": "sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.0.1", - "babel-preset-current-node-syntax": "^1.1.0" + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.11.0" + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, "node_modules/@nx/jest/node_modules/camelcase": { @@ -9858,9 +9881,9 @@ } }, "node_modules/@nx/jest/node_modules/ci-info": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz", - "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "funding": [ { "type": "github", @@ -9873,9 +9896,9 @@ } }, "node_modules/@nx/jest/node_modules/cjs-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", - "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", + "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", "license": "MIT" }, "node_modules/@nx/jest/node_modules/convert-source-map": { @@ -9885,26 +9908,26 @@ "license": "MIT" }, "node_modules/@nx/jest/node_modules/expect": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.0.5.tgz", - "integrity": "sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.0.5", - "@jest/get-type": "30.0.1", - "jest-matcher-utils": "30.0.5", - "jest-message-util": "30.0.5", - "jest-mock": "30.0.5", - "jest-util": "30.0.5" + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -9966,28 +9989,28 @@ } }, "node_modules/@nx/jest/node_modules/jest-circus": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.0.5.tgz", - "integrity": "sha512-h/sjXEs4GS+NFFfqBDYT7y5Msfxh04EwWLhQi0F8kuWpe+J/7tICSlswU8qvBqumR3kFgHbfu7vU6qruWWBPug==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", "license": "MIT", "dependencies": { - "@jest/environment": "30.0.5", - "@jest/expect": "30.0.5", - "@jest/test-result": "30.0.5", - "@jest/types": "30.0.5", + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", - "jest-each": "30.0.5", - "jest-matcher-utils": "30.0.5", - "jest-message-util": "30.0.5", - "jest-runtime": "30.0.5", - "jest-snapshot": "30.0.5", - "jest-util": "30.0.5", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", "p-limit": "^3.1.0", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" @@ -9997,33 +10020,33 @@ } }, "node_modules/@nx/jest/node_modules/jest-config": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.0.5.tgz", - "integrity": "sha512-aIVh+JNOOpzUgzUnPn5FLtyVnqc3TQHVMupYtyeURSb//iLColiMIR8TxCIDKyx9ZgjKnXGucuW68hCxgbrwmA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/get-type": "30.0.1", + "@jest/get-type": "30.1.0", "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.0.5", - "@jest/types": "30.0.5", - "babel-jest": "30.0.5", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", "glob": "^10.3.10", "graceful-fs": "^4.2.11", - "jest-circus": "30.0.5", - "jest-docblock": "30.0.1", - "jest-environment-node": "30.0.5", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", "jest-regex-util": "30.0.1", - "jest-resolve": "30.0.5", - "jest-runner": "30.0.5", - "jest-util": "30.0.5", - "jest-validate": "30.0.5", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", "micromatch": "^4.0.8", "parse-json": "^5.2.0", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -10047,25 +10070,10 @@ } } }, - "node_modules/@nx/jest/node_modules/jest-diff": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.5.tgz", - "integrity": "sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A==", - "license": "MIT", - "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.0.1", - "chalk": "^4.1.2", - "pretty-format": "30.0.5" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@nx/jest/node_modules/jest-docblock": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.0.1.tgz", - "integrity": "sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", "license": "MIT", "dependencies": { "detect-newline": "^3.1.0" @@ -10075,53 +10083,53 @@ } }, "node_modules/@nx/jest/node_modules/jest-each": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.0.5.tgz", - "integrity": "sha512-dKjRsx1uZ96TVyejD3/aAWcNKy6ajMaN531CwWIsrazIqIoXI9TnnpPlkrEYku/8rkS3dh2rbH+kMOyiEIv0xQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", "license": "MIT", "dependencies": { - "@jest/get-type": "30.0.1", - "@jest/types": "30.0.5", + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", "chalk": "^4.1.2", - "jest-util": "30.0.5", - "pretty-format": "30.0.5" + "jest-util": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/jest-environment-node": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.0.5.tgz", - "integrity": "sha512-ppYizXdLMSvciGsRsMEnv/5EFpvOdXBaXRBzFUDPWrsfmog4kYrOGWXarLllz6AXan6ZAA/kYokgDWuos1IKDA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", "license": "MIT", "dependencies": { - "@jest/environment": "30.0.5", - "@jest/fake-timers": "30.0.5", - "@jest/types": "30.0.5", + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-mock": "30.0.5", - "jest-util": "30.0.5", - "jest-validate": "30.0.5" + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/jest-haste-map": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz", - "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", - "jest-util": "30.0.5", - "jest-worker": "30.0.5", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, @@ -10133,46 +10141,46 @@ } }, "node_modules/@nx/jest/node_modules/jest-leak-detector": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.0.5.tgz", - "integrity": "sha512-3Uxr5uP8jmHMcsOtYMRB/zf1gXN3yUIc+iPorhNETG54gErFIiUhLvyY/OggYpSMOEYqsmRxmuU4ZOoX5jpRFg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", "license": "MIT", "dependencies": { - "@jest/get-type": "30.0.1", - "pretty-format": "30.0.5" + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/jest-matcher-utils": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz", - "integrity": "sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "license": "MIT", "dependencies": { - "@jest/get-type": "30.0.1", + "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.0.5", - "pretty-format": "30.0.5" + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/jest-message-util": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz", - "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -10181,14 +10189,14 @@ } }, "node_modules/@nx/jest/node_modules/jest-mock": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.5.tgz", - "integrity": "sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-util": "30.0.5" + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -10204,17 +10212,17 @@ } }, "node_modules/@nx/jest/node_modules/jest-resolve": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.0.5.tgz", - "integrity": "sha512-d+DjBQ1tIhdz91B79mywH5yYu76bZuE96sSbxj8MkjWVx5WNdt1deEFRONVL4UkKLSrAbMkdhb24XN691yDRHg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", "license": "MIT", "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.0.5", + "jest-haste-map": "30.2.0", "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.0.5", - "jest-validate": "30.0.5", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" }, @@ -10223,31 +10231,31 @@ } }, "node_modules/@nx/jest/node_modules/jest-runner": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.0.5.tgz", - "integrity": "sha512-JcCOucZmgp+YuGgLAXHNy7ualBx4wYSgJVWrYMRBnb79j9PD0Jxh0EHvR5Cx/r0Ce+ZBC4hCdz2AzFFLl9hCiw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", "license": "MIT", "dependencies": { - "@jest/console": "30.0.5", - "@jest/environment": "30.0.5", - "@jest/test-result": "30.0.5", - "@jest/transform": "30.0.5", - "@jest/types": "30.0.5", + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-docblock": "30.0.1", - "jest-environment-node": "30.0.5", - "jest-haste-map": "30.0.5", - "jest-leak-detector": "30.0.5", - "jest-message-util": "30.0.5", - "jest-resolve": "30.0.5", - "jest-runtime": "30.0.5", - "jest-util": "30.0.5", - "jest-watcher": "30.0.5", - "jest-worker": "30.0.5", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -10256,31 +10264,31 @@ } }, "node_modules/@nx/jest/node_modules/jest-runtime": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.0.5.tgz", - "integrity": "sha512-7oySNDkqpe4xpX5PPiJTe5vEa+Ak/NnNz2bGYZrA1ftG3RL3EFlHaUkA1Cjx+R8IhK0Vg43RML5mJedGTPNz3A==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", "license": "MIT", "dependencies": { - "@jest/environment": "30.0.5", - "@jest/fake-timers": "30.0.5", - "@jest/globals": "30.0.5", + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", "@jest/source-map": "30.0.1", - "@jest/test-result": "30.0.5", - "@jest/transform": "30.0.5", - "@jest/types": "30.0.5", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", "glob": "^10.3.10", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.0.5", - "jest-message-util": "30.0.5", - "jest-mock": "30.0.5", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", "jest-regex-util": "30.0.1", - "jest-resolve": "30.0.5", - "jest-snapshot": "30.0.5", - "jest-util": "30.0.5", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -10289,9 +10297,9 @@ } }, "node_modules/@nx/jest/node_modules/jest-snapshot": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.0.5.tgz", - "integrity": "sha512-T00dWU/Ek3LqTp4+DcW6PraVxjk28WY5Ua/s+3zUKSERZSNyxTqhDXCWKG5p2HAJ+crVQ3WJ2P9YVHpj1tkW+g==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -10299,20 +10307,20 @@ "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.0.5", - "@jest/get-type": "30.0.1", - "@jest/snapshot-utils": "30.0.5", - "@jest/transform": "30.0.5", - "@jest/types": "30.0.5", - "babel-preset-current-node-syntax": "^1.1.0", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "expect": "30.0.5", + "expect": "30.2.0", "graceful-fs": "^4.2.11", - "jest-diff": "30.0.5", - "jest-matcher-utils": "30.0.5", - "jest-message-util": "30.0.5", - "jest-util": "30.0.5", - "pretty-format": "30.0.5", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" }, @@ -10321,12 +10329,12 @@ } }, "node_modules/@nx/jest/node_modules/jest-util": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz", - "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -10338,35 +10346,35 @@ } }, "node_modules/@nx/jest/node_modules/jest-validate": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.0.5.tgz", - "integrity": "sha512-ouTm6VFHaS2boyl+k4u+Qip4TSH7Uld5tyD8psQ8abGgt2uYYB8VwVfAHWHjHc0NWmGGbwO5h0sCPOGHHevefw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", "license": "MIT", "dependencies": { - "@jest/get-type": "30.0.1", - "@jest/types": "30.0.5", + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "30.0.5" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@nx/jest/node_modules/jest-watcher": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.0.5.tgz", - "integrity": "sha512-z9slj/0vOwBDBjN3L4z4ZYaA+pG56d6p3kTUhFRYGvXbXMWhXmb/FIxREZCD06DYUwDKKnj2T80+Pb71CQ0KEg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", "license": "MIT", "dependencies": { - "@jest/test-result": "30.0.5", - "@jest/types": "30.0.5", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "string-length": "^4.0.2" }, "engines": { @@ -10374,14 +10382,14 @@ } }, "node_modules/@nx/jest/node_modules/jest-worker": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz", - "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", "license": "MIT", "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" }, @@ -10412,9 +10420,9 @@ } }, "node_modules/@nx/jest/node_modules/pretty-format": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz", - "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -10495,9 +10503,9 @@ } }, "node_modules/@nx/js": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/js/-/js-21.3.11.tgz", - "integrity": "sha512-aN8g1TP3FMN6MFLvMrZNaoqSwAkBFH1PunKQV17w4nlPkimWICaCP2DhY5W3VoOpjQBbhQoqrRt4mVfgnEpyvA==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/js/-/js-21.6.8.tgz", + "integrity": "sha512-I9Wu//28DXiSIFoW1IGbLRRfULITkYMOKGMnityQ71iJ8+9vi90a8xFyCWt4VzNxpMEreaoNynWJTf+I8UTGaw==", "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", @@ -10507,8 +10515,8 @@ "@babel/preset-env": "^7.23.2", "@babel/preset-typescript": "^7.22.5", "@babel/runtime": "^7.22.6", - "@nx/devkit": "21.3.11", - "@nx/workspace": "21.3.11", + "@nx/devkit": "21.6.8", + "@nx/workspace": "21.6.8", "@zkochan/js-yaml": "0.0.7", "babel-plugin-const-enum": "^1.0.1", "babel-plugin-macros": "^3.1.0", @@ -10647,9 +10655,9 @@ } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-21.3.11.tgz", - "integrity": "sha512-qXZrW6kfsfGG9n4cWugR2v8ys7P1SsbQuFahlbNSTd7g+ZxozaOnc7tyxW9XuY84KQ35HwP/QSu1E13fK5CXwQ==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-21.6.8.tgz", + "integrity": "sha512-MG5bhSYhG49r+e0mLuztQVHz1sEy7cs8BvZJ56mm7JNQ1VfbaTyLAR7VcNw8O/1mJA8jYcg9fmxOIZOUnY1cEQ==", "cpu": [ "arm64" ], @@ -10660,9 +10668,9 @@ ] }, "node_modules/@nx/nx-darwin-x64": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-21.3.11.tgz", - "integrity": "sha512-6NJEIGRITpFZYptJtr/wdnVuidAS/wONMMSwX5rgAqh5A9teI0vxZVOgG6n5f6NQyqEDvZ9ytcIvLsQWA4kJFg==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-21.6.8.tgz", + "integrity": "sha512-e9oXVTd6U6RFEc3k22PGoe5OSy40fyyytl+svSJQmK+5rxZalvAUna/mXtFcQC9m6No2daqqpfAZlyN5nG6WHw==", "cpu": [ "x64" ], @@ -10673,9 +10681,9 @@ ] }, "node_modules/@nx/nx-freebsd-x64": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-21.3.11.tgz", - "integrity": "sha512-9VZOM9mutzuZCUgijHXrIl3NgKt2CWuH/awLqDS8ijhLs6WfI5TYTa+mFwx90dfZZ4y/jy6XWXa2Ee3OShf7Hg==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-21.6.8.tgz", + "integrity": "sha512-gK3rsTXQj0hHCyaAvZmPZeCPkb3jzesgtkXuZf+7pCm5b4wiEA1i22ufp1UzwaTmWgbub/6NVMEDOGsVcay8mA==", "cpu": [ "x64" ], @@ -10686,9 +10694,9 @@ ] }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-21.3.11.tgz", - "integrity": "sha512-a05tAySKDEWt0TGoSnWp/l5+HL/CDJQkHfI9pXho85oDSkVRzhOInAn1EeZB/F+Q3PnJFsMHMhbuu2/nm3uYJA==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-21.6.8.tgz", + "integrity": "sha512-TXt3HTFhM4kuL9larxBuo3XpSngoA1JCtHavfYLRC3A8knACi7LwNQwnF5RWAcYgKMVE3/8IAhV8LuemXrPKKw==", "cpu": [ "arm" ], @@ -10699,9 +10707,9 @@ ] }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-21.3.11.tgz", - "integrity": "sha512-MPeivf0ptNpzQYvww6zHIqVbE5dTT2isl/WqzGyy7NgSeYDpFXmouDCQaeKxo5WytMVRCvCw/NnWTQuCK6TjnA==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-21.6.8.tgz", + "integrity": "sha512-QwZREYIhqhDVEIf+KAv2VFipxMUoULXXS3qyLX3/q/4u8Y32fyM5wd+FXpv89cRCiveVsZp8io2W178R6lfKng==", "cpu": [ "arm64" ], @@ -10712,9 +10720,9 @@ ] }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-21.3.11.tgz", - "integrity": "sha512-/hJpc4VJsbxDEreXt5Ka9HJ3TBEHgIa9y/i+H9MmWOeapCdH1Edhx58Heuv9OaX7kK8Y8q0cSicv0dJCghiTjA==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-21.6.8.tgz", + "integrity": "sha512-UZJyrZ6utU8g1W7E31iHDhWj1SjMidmDNyrVP4xK6IUrotx6qGrwfwWqzqvphhc1cA7w4Zz9N/rCCPQkdHzjLw==", "cpu": [ "arm64" ], @@ -10725,9 +10733,9 @@ ] }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-21.3.11.tgz", - "integrity": "sha512-pTBHuloqTxpTHa/fdKjHkFFsfW16mEcTp37HDtoQpjPfcd9nO8CYO8OClaewr9khNqCnSbCLfSoIg/alnb7BWw==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-21.6.8.tgz", + "integrity": "sha512-HXINTg4P0/Yj76vsvqBAb7MNlLpkH1pl9JF2blXScOFXWzNoStd7b6xyrpCROdmi0Hk8y3UEwc8OIyLFIfixJg==", "cpu": [ "x64" ], @@ -10738,9 +10746,9 @@ ] }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-21.3.11.tgz", - "integrity": "sha512-OhFjURB68rd6xld8t8fiNpopF2E7v+8/jfbpsku9c0gdV2UhzoxCeZwooe7qhQjCcjVO8JNOs4dAf7qs1VtpMw==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-21.6.8.tgz", + "integrity": "sha512-2YbXLhuSlElCtQTR1Ib94O3T4fX9uzSIkUMYGL3n04agG0HemXoxJa91TWwwOUMbEZffkhcPsJBOh2S5l47s9Q==", "cpu": [ "x64" ], @@ -10751,9 +10759,9 @@ ] }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-21.3.11.tgz", - "integrity": "sha512-pGE2Td13oEj7aeogwCL+2fjmpabQVSduKfGOTlt4YoMlM0w0bXYSWqwiGBMKbMA50qkhnVapwwkuWF38PgCIxg==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-21.6.8.tgz", + "integrity": "sha512-/VSGtqa1oGHo5n24R39ZuGxMrGyf7pxFuCtL5hAzBHdTxFg/VZomPGd7BeV5VN5SbIw+fie+nTGkC5q3TOPGXw==", "cpu": [ "arm64" ], @@ -10764,9 +10772,9 @@ ] }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-21.3.11.tgz", - "integrity": "sha512-KJqLL/Zyx96hs+7pKbo/fsU7ZTFSLeZLnYQu05o6fvJJ5I1+p85t212/7vkbKKWJncyMospQdzLr3zLG3A/u8A==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-21.6.8.tgz", + "integrity": "sha512-xeBL7PcDqHH/Zw4d2A2qP7eLImzzcMO3hiKs5G42Wi92ACejAdUqpIduTL4RpArsXIHm5VEbE4KvHNii1mMU1A==", "cpu": [ "x64" ], @@ -10777,14 +10785,14 @@ ] }, "node_modules/@nx/webpack": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-21.3.11.tgz", - "integrity": "sha512-GAqA9yHLro4zDf2z27uWseUSLiZZh2IZ3Eh5Kb9l/LA4ujT3whkpNoIo/K2LxzmmOG8k2SkJ7wBntCPk2O1e8g==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-21.6.8.tgz", + "integrity": "sha512-lVJJRqtNPbdSrbEws3/pty077kwlY3m7XDQZTzStCf9ZGE5tZR8LDe49DKlUZ6dLIO7RmHjW8laehXsvi9ZtHw==", "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", - "@nx/devkit": "21.3.11", - "@nx/js": "21.3.11", + "@nx/devkit": "21.6.8", + "@nx/js": "21.6.8", "@phenomnomnominal/tsquery": "~5.0.1", "ajv": "^8.12.0", "autoprefixer": "^10.4.9", @@ -10812,9 +10820,9 @@ "style-loader": "^3.3.0", "terser-webpack-plugin": "^5.3.3", "ts-loader": "^9.3.1", - "tsconfig-paths-webpack-plugin": "4.0.0", + "tsconfig-paths-webpack-plugin": "4.2.0", "tslib": "^2.3.0", - "webpack": "~5.99.0", + "webpack": "^5.101.3", "webpack-dev-server": "^5.2.1", "webpack-node-externals": "^3.0.0", "webpack-subresource-integrity": "^5.1.0" @@ -10842,6 +10850,39 @@ "concat-map": "0.0.1" } }, + "node_modules/@nx/webpack/node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/@nx/webpack/node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -10953,6 +10994,28 @@ } } }, + "node_modules/@nx/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nx/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nx/webpack/node_modules/fork-ts-checker-webpack-plugin": { "version": "7.2.13", "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz", @@ -11073,6 +11136,12 @@ "node": ">= 4" } }, + "node_modules/@nx/webpack/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, "node_modules/@nx/webpack/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -11110,6 +11179,27 @@ "node": ">=8.9.0" } }, + "node_modules/@nx/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@nx/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@nx/webpack/node_modules/mini-css-extract-plugin": { "version": "2.4.7", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.7.tgz", @@ -11225,15 +11315,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@nx/webpack/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@nx/webpack/node_modules/style-loader": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", @@ -11250,34 +11331,67 @@ "webpack": "^5.0.0" } }, - "node_modules/@nx/webpack/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "node_modules/@nx/webpack/node_modules/watchpack": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "license": "MIT", "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@nx/webpack/node_modules/tsconfig-paths-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-fw/7265mIWukrSHd0i+wSwx64kYUSAKPfxRDksjKIYTxSAp9W9/xcZVBF4Kl0eqQd5eBpAQ/oQrc5RyM/0c1GQ==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.7.0", - "tsconfig-paths": "^4.0.0" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, "engines": { "node": ">=10.13.0" } }, + "node_modules/@nx/webpack/node_modules/webpack": { + "version": "5.103.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz", + "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.26.3", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.3", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "node_modules/@nx/webpack/node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -11288,17 +11402,18 @@ } }, "node_modules/@nx/workspace": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-21.3.11.tgz", - "integrity": "sha512-DD2iu9Ip/faNQ5MXZk+UbbBxGofYKjzHsXKRvMNQ/OAVzP/u9z2CPXEmRKlRAEQoy1lInmyopwfEUWwK1v4x0g==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-21.6.8.tgz", + "integrity": "sha512-X2DgtqxFJwwte4GxancLZ2GFMc+9waRaLPL6goR/HAtIvKriqZAVMkywNMk1mnhrpo0M7UXmfbM51kf+nsS+bg==", "license": "MIT", "dependencies": { - "@nx/devkit": "21.3.11", + "@nx/devkit": "21.6.8", "@zkochan/js-yaml": "0.0.7", "chalk": "^4.1.0", "enquirer": "~2.3.6", - "nx": "21.3.11", + "nx": "21.6.8", "picomatch": "4.0.2", + "semver": "^7.6.3", "tslib": "^2.3.0", "yargs-parser": "21.1.1" } @@ -16133,6 +16248,18 @@ "acorn-walk": "^8.0.2" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -17236,9 +17363,9 @@ } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -17258,7 +17385,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "node_modules/babel-preset-jest": { @@ -17322,6 +17449,15 @@ "dev": true, "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.30", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.30.tgz", + "integrity": "sha512-aTUKW4ptQhS64+v2d6IkPzymEzzhw+G0bA1g3uBRV3+ntkH+svttKseW5IOR4Ed6NUVKqnY7qT3dKvzQ7io4AA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -17626,40 +17762,40 @@ } }, "node_modules/braintree-web": { - "version": "3.113.0", - "resolved": "https://registry.npmjs.org/braintree-web/-/braintree-web-3.113.0.tgz", - "integrity": "sha512-qykYxZyld4X1tRNgXZQ3ZGzmhDGTBTRQ6Q24KaG9PuYqo+P2TVDEDOVC6tRbkx2RUIdXLv2M6WpkG7oLqEia9Q==", + "version": "3.123.2", + "resolved": "https://registry.npmjs.org/braintree-web/-/braintree-web-3.123.2.tgz", + "integrity": "sha512-N4IH75vKY67eONc0Ao4e7F+XagFW+3ok+Nfs/eOjw5D/TUt03diMAQ8woOwJghi2ql6/yjqNzZi2zE/sTWXmJg==", "license": "MIT", "dependencies": { - "@braintree/asset-loader": "2.0.1", - "@braintree/browser-detection": "2.0.1", + "@braintree/asset-loader": "2.0.3", + "@braintree/browser-detection": "2.0.2", "@braintree/event-emitter": "0.4.1", "@braintree/extended-promise": "1.0.0", - "@braintree/iframer": "2.0.0", + "@braintree/iframer": "2.0.1", "@braintree/sanitize-url": "7.0.4", - "@braintree/uuid": "1.0.0", + "@braintree/uuid": "1.0.1", "@braintree/wrap-promise": "2.1.0", "@paypal/accelerated-checkout-loader": "1.1.0", - "card-validator": "10.0.0", - "credit-card-type": "10.0.1", - "framebus": "6.0.0", - "inject-stylesheet": "6.0.1", + "card-validator": "10.0.3", + "credit-card-type": "10.0.2", + "framebus": "6.0.3", + "inject-stylesheet": "6.0.2", "promise-polyfill": "8.2.3", - "restricted-input": "3.0.5" + "restricted-input": "4.0.3" } }, "node_modules/braintree-web-drop-in": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/braintree-web-drop-in/-/braintree-web-drop-in-1.44.0.tgz", - "integrity": "sha512-maOq9SwiXztIzixJhOras7K44x4UIqqnkyQMYAJqxQ8WkADv9AkflCu2j3IeVYCus/Th9gWWFHcBugn3C4sZGw==", + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/braintree-web-drop-in/-/braintree-web-drop-in-1.46.0.tgz", + "integrity": "sha512-KxCjJpaigoMajYD/iIA+ohXaI6Olt2Bj/Yu45WpJOjolKO9n1UmXl9bsq9UIiGOFIGqi/JWva1wI4cIHHvcI1A==", "license": "MIT", "dependencies": { - "@braintree/asset-loader": "2.0.1", - "@braintree/browser-detection": "2.0.1", + "@braintree/asset-loader": "2.0.3", + "@braintree/browser-detection": "2.0.2", "@braintree/event-emitter": "0.4.1", - "@braintree/uuid": "1.0.0", + "@braintree/uuid": "1.0.1", "@braintree/wrap-promise": "2.1.0", - "braintree-web": "3.113.0" + "braintree-web": "3.123.2" } }, "node_modules/browser-assert": { @@ -18288,9 +18424,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001724", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz", - "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==", + "version": "1.0.30001756", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz", + "integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==", "funding": [ { "type": "opencollective", @@ -18308,20 +18444,14 @@ "license": "CC-BY-4.0" }, "node_modules/card-validator": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/card-validator/-/card-validator-10.0.0.tgz", - "integrity": "sha512-2fLyCBOxO7/b56sxoYav8FeJqv9bWpZSyKq8sXKxnpxTGXHnM/0c8WEKG+ZJ+OXFcabnl98pD0EKBtTn+Tql0g==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/card-validator/-/card-validator-10.0.3.tgz", + "integrity": "sha512-xOEDsK3hojV0OIpmrR64eZGpngnOqRDEP20O+WSRtvjLSW6nyekW4i2N9SzYg679uFO3RyHcFHxb+mml5tXc4A==", "license": "MIT", "dependencies": { - "credit-card-type": "^9.1.0" + "credit-card-type": "^10.0.2" } }, - "node_modules/card-validator/node_modules/credit-card-type": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/credit-card-type/-/credit-card-type-9.1.0.tgz", - "integrity": "sha512-CpNFuLxiPFxuZqhSKml3M+t0K/484pMAnfYWH14JoD7OZMnmC0Lmo+P7JX9SobqFpRoo7ifA18kOHdxJywYPEA==", - "license": "MIT" - }, "node_modules/case-sensitive-paths-webpack-plugin": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", @@ -19556,9 +19686,9 @@ "license": "MIT" }, "node_modules/credit-card-type": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/credit-card-type/-/credit-card-type-10.0.1.tgz", - "integrity": "sha512-vQOuWmBgsgG1ovGeDi8m6Zeu1JaqH/JncrxKmaqMbv/LunyOQdLiQhPHtOsNlbUI05TocR5nod/Mbs3HYtr6sQ==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/credit-card-type/-/credit-card-type-10.0.2.tgz", + "integrity": "sha512-vt/iQokU0mtrT7ceRU75FSmWnIh5JFpLsUUUWYRmztYekOGm0ZbCuzwFTbNkq41k92y+0B8ChscFhRN9DhVZEA==", "license": "MIT" }, "node_modules/cross-dirname": { @@ -21081,9 +21211,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.172", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.172.tgz", - "integrity": "sha512-fnKW9dGgmBfsebbYognQSv0CGGLFH1a5iV9EDYTBwmAQn+whbzHbLFlC+3XbHc8xaNtpO0etm8LOcRXs1qMRkQ==", + "version": "1.5.259", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.259.tgz", + "integrity": "sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==", "license": "ISC" }, "node_modules/electron-updater": { @@ -23274,20 +23404,14 @@ } }, "node_modules/framebus": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/framebus/-/framebus-6.0.0.tgz", - "integrity": "sha512-bL9V68hVaVBCY9rveoWbPFFI9hAXIJtESs51B+9XmzvMt38+wP8b4VdiJsavjMS6NfPZ/afQ/jc2qaHmSGI1kQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/framebus/-/framebus-6.0.3.tgz", + "integrity": "sha512-G/N2p+kFZ1xPBge7tbtTq2KcTR1kSKs1rVbTqH//WdtvJSexS33fsTTOq3yfUWvUczqhujyaFc+omawC9YyRBg==", "license": "MIT", "dependencies": { - "@braintree/uuid": "^0.1.0" + "@braintree/uuid": "^1.0.0" } }, - "node_modules/framebus/node_modules/@braintree/uuid": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@braintree/uuid/-/uuid-0.1.0.tgz", - "integrity": "sha512-YvZJdlNcK5EnR+7M8AjgEAf4Qx696+FOSYlPfy5ePn80vODtVAUU0FxHnzKZC0og1VbDNQDDiwhthR65D4Na0g==", - "license": "ISC" - }, "node_modules/fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", @@ -24851,9 +24975,9 @@ } }, "node_modules/inject-stylesheet": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/inject-stylesheet/-/inject-stylesheet-6.0.1.tgz", - "integrity": "sha512-2fvune1D4+8mvJoLVo95ncY4HrDkIaYIReRzXv8tkWFgdG9iuc5QuX57gtSDPWTWQI/f5BGwwtH85wxHouzucg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/inject-stylesheet/-/inject-stylesheet-6.0.2.tgz", + "integrity": "sha512-sswMueya1LXEfwcy7KXPuq3zAW6HvgAeViApEhIaCviCkP4XYoKrQj8ftEmxPmIHn88X4R3xOAsnN/QCPvVKWw==", "license": "MIT" }, "node_modules/inquirer": { @@ -26163,15 +26287,6 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/jest-diff/node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "license": "MIT", - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/jest-diff/node_modules/@jest/schemas": { "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", @@ -27947,9 +28062,9 @@ } }, "node_modules/koa": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.2.tgz", - "integrity": "sha512-+CCssgnrWKx9aI3OeZwroa/ckG4JICxvIFnSiOUyl2Uv+UTI+xIw0FfFrWS7cQFpoePpr9o8csss7KzsTzNL8Q==", + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.16.3.tgz", + "integrity": "sha512-zPPuIt+ku1iCpFBRwseMcPYQ1cJL8l60rSmKeOuGfOXyE6YnTBmf2aEFNL2HQGrD0cPcLO/t+v9RTgC+fwEh/g==", "license": "MIT", "dependencies": { "accepts": "^1.3.5", @@ -28829,12 +28944,16 @@ "optional": true }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/loader-utils": { @@ -31644,9 +31763,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/nopt": { @@ -32168,9 +32287,9 @@ "license": "MIT" }, "node_modules/nx": { - "version": "21.3.11", - "resolved": "https://registry.npmjs.org/nx/-/nx-21.3.11.tgz", - "integrity": "sha512-nj2snZ3mHZnbHcoB3NUdxbch9L1sQKV1XccLs1B79fmI/N5oOgWgctm/bWoZH2UH5b4A8ZLAMTsC6YnSJGbcaw==", + "version": "21.6.8", + "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.8.tgz", + "integrity": "sha512-NilGEk1Cngs3Se9JW+f9cDeN6RBvmABhpEtgMvOK8RAAZszq6B380oCzKcQljhnrbQ6+v6j/Vb7hBPTCvXb0Ng==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -32178,7 +32297,7 @@ "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.2", "@zkochan/js-yaml": "0.0.7", - "axios": "^1.8.3", + "axios": "^1.12.0", "chalk": "^4.1.0", "cli-cursor": "3.1.0", "cli-spinners": "2.6.1", @@ -32215,16 +32334,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "21.3.11", - "@nx/nx-darwin-x64": "21.3.11", - "@nx/nx-freebsd-x64": "21.3.11", - "@nx/nx-linux-arm-gnueabihf": "21.3.11", - "@nx/nx-linux-arm64-gnu": "21.3.11", - "@nx/nx-linux-arm64-musl": "21.3.11", - "@nx/nx-linux-x64-gnu": "21.3.11", - "@nx/nx-linux-x64-musl": "21.3.11", - "@nx/nx-win32-arm64-msvc": "21.3.11", - "@nx/nx-win32-x64-msvc": "21.3.11" + "@nx/nx-darwin-arm64": "21.6.8", + "@nx/nx-darwin-x64": "21.6.8", + "@nx/nx-freebsd-x64": "21.6.8", + "@nx/nx-linux-arm-gnueabihf": "21.6.8", + "@nx/nx-linux-arm64-gnu": "21.6.8", + "@nx/nx-linux-arm64-musl": "21.6.8", + "@nx/nx-linux-x64-gnu": "21.6.8", + "@nx/nx-linux-x64-musl": "21.6.8", + "@nx/nx-win32-arm64-msvc": "21.6.8", + "@nx/nx-win32-x64-msvc": "21.6.8" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -36023,12 +36142,12 @@ "license": "ISC" }, "node_modules/restricted-input": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/restricted-input/-/restricted-input-3.0.5.tgz", - "integrity": "sha512-lUuXZ3wUnHURRarj5/0C8vomWIfWJO+p7T6RYwB46v7Oyuyr3yyupU+i7SjqUv4S6RAeAAZt1C/QCLJ9xhQBow==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/restricted-input/-/restricted-input-4.0.3.tgz", + "integrity": "sha512-VpkwT5Fr3DhvoRZfPnmHDhnYAYETjjNzDlvA4NlW0iknFS47C5X4OCHEpOOxaPjvmka5V8d1ty1jVVoorZKvHg==", "license": "MIT", "dependencies": { - "@braintree/browser-detection": "^1.12.1" + "@braintree/browser-detection": "^1.17.2" } }, "node_modules/restricted-input/node_modules/@braintree/browser-detection": { @@ -36861,9 +36980,9 @@ } }, "node_modules/schema-utils": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", - "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", @@ -38640,12 +38759,16 @@ } }, "node_modules/tapable": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", - "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/tar": { @@ -39477,7 +39600,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", - "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -39493,7 +39615,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -39503,7 +39624,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, "license": "MIT", "dependencies": { "json5": "^2.2.2", @@ -40533,9 +40653,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", "funding": [ { "type": "opencollective", diff --git a/package.json b/package.json index 5d23d6b9938..87a78a30796 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "json5": "2.2.3", "lint-staged": "16.0.0", "mini-css-extract-plugin": "2.9.2", - "nx": "21.3.11", + "nx": "21.6.8", "postcss": "8.5.3", "postcss-loader": "8.1.1", "prettier": "3.6.2", @@ -169,13 +169,13 @@ "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", "@ng-select/ng-select": "14.9.0", - "@nx/devkit": "21.3.11", - "@nx/eslint": "21.3.11", - "@nx/jest": "21.3.11", - "@nx/js": "21.3.11", - "@nx/webpack": "21.3.11", + "@nx/devkit": "21.6.8", + "@nx/eslint": "21.6.8", + "@nx/jest": "21.6.8", + "@nx/js": "21.6.8", + "@nx/webpack": "21.6.8", "big-integer": "1.6.52", - "braintree-web-drop-in": "1.44.0", + "braintree-web-drop-in": "1.46.0", "buffer": "6.0.3", "bufferutil": "4.0.9", "chalk": "4.1.2", @@ -186,7 +186,7 @@ "inquirer": "8.2.6", "jsdom": "26.1.0", "jszip": "3.10.1", - "koa": "2.16.2", + "koa": "2.16.3", "koa-bodyparser": "4.4.1", "koa-json": "2.0.2", "lit": "3.3.0",