From 534e42b9f0692b55d026dda71908ee27e4a5343f Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Mon, 6 Jan 2025 16:31:16 +0100 Subject: [PATCH 01/18] [PM-16432] Remove v1 account security settings (#12578) * Remove v1 account security settings Delete v1 component Remove conditional routing based on extension refresh feature flag * Remove unused import --------- Co-authored-by: Daniel James Smith --- .../account-security-v1.component.html | 140 ----- .../settings/account-security-v1.component.ts | 499 ------------------ .../settings/account-security.component.ts | 2 - apps/browser/src/popup/app-routing.module.ts | 6 +- apps/browser/src/popup/app.module.ts | 2 - 5 files changed, 3 insertions(+), 646 deletions(-) delete mode 100644 apps/browser/src/auth/popup/settings/account-security-v1.component.html delete mode 100644 apps/browser/src/auth/popup/settings/account-security-v1.component.ts diff --git a/apps/browser/src/auth/popup/settings/account-security-v1.component.html b/apps/browser/src/auth/popup/settings/account-security-v1.component.html deleted file mode 100644 index dff9675743f..00000000000 --- a/apps/browser/src/auth/popup/settings/account-security-v1.component.html +++ /dev/null @@ -1,140 +0,0 @@ - -
- -
-

- {{ "accountSecurity" | i18n }} -

-
- -
-
-
-
-

{{ "unlockMethods" | i18n }}

-
-
- - -
-
- - -
-
- - -
-
-
-
-

{{ "sessionTimeoutHeader" | i18n }}

-
- - - {{ - "vaultTimeoutPolicyWithActionInEffect" - | i18n: policy.timeout.hours : policy.timeout.minutes : (policy.action | i18n) - }} - - - {{ "vaultTimeoutPolicyInEffect" | i18n: policy.timeout.hours : policy.timeout.minutes }} - - - {{ "vaultTimeoutActionPolicyInEffect" | i18n: (policy.action | i18n) }} - - - - -
- - -
- -
-
-
-

{{ "otherOptions" | i18n }}

-
- - - - - -
-
-
diff --git a/apps/browser/src/auth/popup/settings/account-security-v1.component.ts b/apps/browser/src/auth/popup/settings/account-security-v1.component.ts deleted file mode 100644 index d06724bf657..00000000000 --- a/apps/browser/src/auth/popup/settings/account-security-v1.component.ts +++ /dev/null @@ -1,499 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from "@angular/core"; -import { FormBuilder } from "@angular/forms"; -import { - BehaviorSubject, - combineLatest, - concatMap, - distinctUntilChanged, - filter, - firstValueFrom, - map, - Observable, - pairwise, - startWith, - Subject, - switchMap, - takeUntil, -} from "rxjs"; - -import { FingerprintDialogComponent } from "@bitwarden/auth/angular"; -import { PinServiceAbstraction } from "@bitwarden/auth/common"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; -import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { PolicyType } from "@bitwarden/common/admin-console/enums"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { - VaultTimeout, - VaultTimeoutOption, - VaultTimeoutStringType, -} from "@bitwarden/common/types/vault-timeout.type"; -import { DialogService } from "@bitwarden/components"; -import { KeyService, BiometricStateService, BiometricsService } from "@bitwarden/key-management"; - -import { BiometricErrors, BiometricErrorTypes } from "../../../models/biometricErrors"; -import { BrowserApi } from "../../../platform/browser/browser-api"; -import { enableAccountSwitching } from "../../../platform/flags"; -import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; -import { SetPinComponent } from "../components/set-pin.component"; - -import { AwaitDesktopDialogComponent } from "./await-desktop-dialog.component"; - -@Component({ - selector: "auth-account-security", - templateUrl: "account-security-v1.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class AccountSecurityComponent implements OnInit, OnDestroy { - protected readonly VaultTimeoutAction = VaultTimeoutAction; - - availableVaultTimeoutActions: VaultTimeoutAction[] = []; - vaultTimeoutOptions: VaultTimeoutOption[]; - vaultTimeoutPolicyCallout: Observable<{ - timeout: { hours: string; minutes: string }; - action: VaultTimeoutAction; - }>; - supportsBiometric: boolean; - showChangeMasterPass = true; - accountSwitcherEnabled = false; - - form = this.formBuilder.group({ - vaultTimeout: [null as VaultTimeout | null], - vaultTimeoutAction: [VaultTimeoutAction.Lock], - pin: [null as boolean | null], - biometric: false, - enableAutoBiometricsPrompt: true, - }); - - private refreshTimeoutSettings$ = new BehaviorSubject(undefined); - private destroy$ = new Subject(); - - constructor( - private accountService: AccountService, - private pinService: PinServiceAbstraction, - private policyService: PolicyService, - private formBuilder: FormBuilder, - private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService, - private vaultTimeoutService: VaultTimeoutService, - private vaultTimeoutSettingsService: VaultTimeoutSettingsService, - public messagingService: MessagingService, - private environmentService: EnvironmentService, - private keyService: KeyService, - private stateService: StateService, - private userVerificationService: UserVerificationService, - private dialogService: DialogService, - private changeDetectorRef: ChangeDetectorRef, - private biometricStateService: BiometricStateService, - private biometricsService: BiometricsService, - ) { - this.accountSwitcherEnabled = enableAccountSwitching(); - } - - async ngOnInit() { - const maximumVaultTimeoutPolicy = this.policyService.get$(PolicyType.MaximumVaultTimeout); - this.vaultTimeoutPolicyCallout = maximumVaultTimeoutPolicy.pipe( - filter((policy) => policy != null), - map((policy) => { - let timeout; - if (policy.data?.minutes) { - timeout = { - hours: Math.floor(policy.data?.minutes / 60).toString(), - minutes: (policy.data?.minutes % 60).toString(), - }; - } - return { timeout: timeout, action: policy.data?.action }; - }), - ); - - const showOnLocked = - !this.platformUtilsService.isFirefox() && !this.platformUtilsService.isSafari(); - - this.vaultTimeoutOptions = [ - { name: this.i18nService.t("immediately"), value: 0 }, - { name: this.i18nService.t("oneMinute"), value: 1 }, - { name: this.i18nService.t("fiveMinutes"), value: 5 }, - { name: this.i18nService.t("fifteenMinutes"), value: 15 }, - { name: this.i18nService.t("thirtyMinutes"), value: 30 }, - { name: this.i18nService.t("oneHour"), value: 60 }, - { name: this.i18nService.t("fourHours"), value: 240 }, - ]; - - if (showOnLocked) { - this.vaultTimeoutOptions.push({ - name: this.i18nService.t("onLocked"), - value: VaultTimeoutStringType.OnLocked, - }); - } - - this.vaultTimeoutOptions.push({ - name: this.i18nService.t("onRestart"), - value: VaultTimeoutStringType.OnRestart, - }); - this.vaultTimeoutOptions.push({ - name: this.i18nService.t("never"), - value: VaultTimeoutStringType.Never, - }); - - const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - - let timeout = await firstValueFrom( - this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(activeAccount.id), - ); - if (timeout === VaultTimeoutStringType.OnLocked && !showOnLocked) { - timeout = VaultTimeoutStringType.OnRestart; - } - - const initialValues = { - vaultTimeout: timeout, - vaultTimeoutAction: await firstValueFrom( - this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id), - ), - pin: await this.pinService.isPinSet(activeAccount.id), - biometric: await this.vaultTimeoutSettingsService.isBiometricLockSet(), - enableAutoBiometricsPrompt: await firstValueFrom( - this.biometricStateService.promptAutomatically$, - ), - }; - this.form.patchValue(initialValues, { emitEvent: false }); - - this.supportsBiometric = await this.biometricsService.supportsBiometric(); - this.showChangeMasterPass = await this.userVerificationService.hasMasterPassword(); - - this.form.controls.vaultTimeout.valueChanges - .pipe( - startWith(initialValues.vaultTimeout), // emit to init pairwise - pairwise(), - concatMap(async ([previousValue, newValue]) => { - await this.saveVaultTimeout(previousValue, newValue); - }), - takeUntil(this.destroy$), - ) - .subscribe(); - - this.form.controls.vaultTimeoutAction.valueChanges - .pipe( - startWith(initialValues.vaultTimeoutAction), // emit to init pairwise - pairwise(), - concatMap(async ([previousValue, newValue]) => { - await this.saveVaultTimeoutAction(previousValue, newValue); - }), - takeUntil(this.destroy$), - ) - .subscribe(); - - this.form.controls.pin.valueChanges - .pipe( - concatMap(async (value) => { - await this.updatePin(value); - this.refreshTimeoutSettings$.next(); - }), - takeUntil(this.destroy$), - ) - .subscribe(); - - this.form.controls.biometric.valueChanges - .pipe( - distinctUntilChanged(), - concatMap(async (enabled) => { - await this.updateBiometric(enabled); - if (enabled) { - this.form.controls.enableAutoBiometricsPrompt.enable(); - } else { - this.form.controls.enableAutoBiometricsPrompt.disable(); - } - this.refreshTimeoutSettings$.next(); - }), - takeUntil(this.destroy$), - ) - .subscribe(); - - this.refreshTimeoutSettings$ - .pipe( - switchMap(() => - combineLatest([ - this.vaultTimeoutSettingsService.availableVaultTimeoutActions$(), - this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id), - ]), - ), - takeUntil(this.destroy$), - ) - .subscribe(([availableActions, action]) => { - this.availableVaultTimeoutActions = availableActions; - this.form.controls.vaultTimeoutAction.setValue(action, { emitEvent: false }); - // NOTE: The UI doesn't properly update without detect changes. - // I've even tried using an async pipe, but it still doesn't work. I'm not sure why. - // Using an async pipe means that we can't call `detectChanges` AFTER the data has change - // meaning that we are forced to use regular class variables instead of observables. - this.changeDetectorRef.detectChanges(); - }); - - this.refreshTimeoutSettings$ - .pipe( - switchMap(() => - combineLatest([ - this.vaultTimeoutSettingsService.availableVaultTimeoutActions$(), - maximumVaultTimeoutPolicy, - ]), - ), - takeUntil(this.destroy$), - ) - .subscribe(([availableActions, policy]) => { - if (policy?.data?.action || availableActions.length <= 1) { - this.form.controls.vaultTimeoutAction.disable({ emitEvent: false }); - } else { - this.form.controls.vaultTimeoutAction.enable({ emitEvent: false }); - } - }); - } - - async saveVaultTimeout(previousValue: VaultTimeout, newValue: VaultTimeout) { - if (newValue === VaultTimeoutStringType.Never) { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "warning" }, - content: { key: "neverLockWarning" }, - type: "warning", - }); - - if (!confirmed) { - this.form.controls.vaultTimeout.setValue(previousValue, { emitEvent: false }); - return; - } - } - - // The minTimeoutError does not apply to browser because it supports Immediately - // So only check for the policyError - if (this.form.controls.vaultTimeout.hasError("policyError")) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("vaultTimeoutTooLarge"), - ); - return; - } - - const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - - const vaultTimeoutAction = await firstValueFrom( - this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id), - ); - - await this.vaultTimeoutSettingsService.setVaultTimeoutOptions( - activeAccount.id, - newValue, - vaultTimeoutAction, - ); - if (newValue === VaultTimeoutStringType.Never) { - this.messagingService.send("bgReseedStorage"); - } - } - - async saveVaultTimeoutAction(previousValue: VaultTimeoutAction, newValue: VaultTimeoutAction) { - if (newValue === VaultTimeoutAction.LogOut) { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "vaultTimeoutLogOutConfirmationTitle" }, - content: { key: "vaultTimeoutLogOutConfirmation" }, - type: "warning", - }); - - if (!confirmed) { - this.form.controls.vaultTimeoutAction.setValue(previousValue, { - emitEvent: false, - }); - return; - } - } - - if (this.form.controls.vaultTimeout.hasError("policyError")) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("vaultTimeoutTooLarge"), - ); - return; - } - - const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - - await this.vaultTimeoutSettingsService.setVaultTimeoutOptions( - activeAccount.id, - this.form.value.vaultTimeout, - newValue, - ); - this.refreshTimeoutSettings$.next(); - } - - async updatePin(value: boolean) { - if (value) { - const dialogRef = SetPinComponent.open(this.dialogService); - - if (dialogRef == null) { - this.form.controls.pin.setValue(false, { emitEvent: false }); - return; - } - - const userHasPinSet = await firstValueFrom(dialogRef.closed); - this.form.controls.pin.setValue(userHasPinSet, { emitEvent: false }); - } else { - await this.vaultTimeoutSettingsService.clear(); - } - } - - async updateBiometric(enabled: boolean) { - if (enabled && this.supportsBiometric) { - let granted; - try { - granted = await BrowserApi.requestPermission({ permissions: ["nativeMessaging"] }); - } catch (e) { - // eslint-disable-next-line - console.error(e); - - if (this.platformUtilsService.isFirefox() && BrowserPopupUtils.inSidebar(window)) { - await this.dialogService.openSimpleDialog({ - title: { key: "nativeMessaginPermissionSidebarTitle" }, - content: { key: "nativeMessaginPermissionSidebarDesc" }, - acceptButtonText: { key: "ok" }, - cancelButtonText: null, - type: "info", - }); - - this.form.controls.biometric.setValue(false); - return; - } - } - - if (!granted) { - await this.dialogService.openSimpleDialog({ - title: { key: "nativeMessaginPermissionErrorTitle" }, - content: { key: "nativeMessaginPermissionErrorDesc" }, - acceptButtonText: { key: "ok" }, - cancelButtonText: null, - type: "danger", - }); - - this.form.controls.biometric.setValue(false); - return; - } - - const awaitDesktopDialogRef = AwaitDesktopDialogComponent.open(this.dialogService); - const awaitDesktopDialogClosed = firstValueFrom(awaitDesktopDialogRef.closed); - - await this.keyService.refreshAdditionalKeys(); - - await Promise.race([ - awaitDesktopDialogClosed.then(async (result) => { - if (result !== true) { - this.form.controls.biometric.setValue(false); - } - }), - this.biometricsService - .authenticateBiometric() - .then((result) => { - this.form.controls.biometric.setValue(result); - if (!result) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorEnableBiometricTitle"), - this.i18nService.t("errorEnableBiometricDesc"), - ); - } - }) - .catch((e) => { - // Handle connection errors - this.form.controls.biometric.setValue(false); - - const error = BiometricErrors[e.message as BiometricErrorTypes]; - - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.dialogService.openSimpleDialog({ - title: { key: error.title }, - content: { key: error.description }, - acceptButtonText: { key: "ok" }, - cancelButtonText: null, - type: "danger", - }); - }) - .finally(() => { - awaitDesktopDialogRef.close(true); - }), - ]); - } else { - await this.biometricStateService.setBiometricUnlockEnabled(false); - await this.biometricStateService.setFingerprintValidated(false); - } - } - - async updateAutoBiometricsPrompt() { - await this.biometricStateService.setPromptAutomatically( - this.form.value.enableAutoBiometricsPrompt, - ); - } - - async changePassword() { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "continueToWebApp" }, - content: { key: "changeMasterPasswordOnWebConfirmation" }, - type: "info", - acceptButtonText: { key: "continue" }, - }); - if (confirmed) { - const env = await firstValueFrom(this.environmentService.environment$); - await BrowserApi.createNewTab(env.getWebVaultUrl()); - } - } - - async twoStep() { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "twoStepLogin" }, - content: { key: "twoStepLoginConfirmation" }, - type: "info", - }); - if (confirmed) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab("https://bitwarden.com/help/setup-two-step-login/"); - } - } - - async fingerprint() { - const fingerprint = await this.keyService.getFingerprint(await this.stateService.getUserId()); - - const dialogRef = FingerprintDialogComponent.open(this.dialogService, { - fingerprint, - }); - - return firstValueFrom(dialogRef.closed); - } - - async lock() { - await this.vaultTimeoutService.lock(); - } - - async logOut() { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "logOut" }, - content: { key: "logOutConfirmation" }, - type: "info", - }); - - const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; - if (confirmed) { - this.messagingService.send("logout", { userId: userId }); - } - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } -} diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts index cf923ac74b5..86eea889fdd 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -60,7 +60,6 @@ import { BrowserApi } from "../../../platform/browser/browser-api"; import { enableAccountSwitching } from "../../../platform/flags"; import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; -import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; import { SetPinComponent } from "../components/set-pin.component"; @@ -82,7 +81,6 @@ import { AwaitDesktopDialogComponent } from "./await-desktop-dialog.component"; JslibModule, LinkModule, PopOutComponent, - PopupFooterComponent, PopupHeaderComponent, PopupPageComponent, RouterModule, diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index b7bc5643ac4..49d680cd752 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -65,7 +65,6 @@ import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-req import { RegisterComponent } from "../auth/popup/register.component"; import { RemovePasswordComponent } from "../auth/popup/remove-password.component"; import { SetPasswordComponent } from "../auth/popup/set-password.component"; -import { AccountSecurityComponent as AccountSecurityV1Component } from "../auth/popup/settings/account-security-v1.component"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; import { SsoComponentV1 } from "../auth/popup/sso-v1.component"; import { TwoFactorAuthComponent } from "../auth/popup/two-factor-auth.component"; @@ -351,11 +350,12 @@ const routes: Routes = [ canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }), - ...extensionRefreshSwap(AccountSecurityV1Component, AccountSecurityComponent, { + { path: "account-security", + component: AccountSecurityComponent, canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, - }), + }, ...extensionRefreshSwap(NotificationsSettingsV1Component, NotificationsSettingsComponent, { path: "notifications", canActivate: [authGuard], diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 04d681812fe..83475a661c9 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -29,7 +29,6 @@ import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-req import { RegisterComponent } from "../auth/popup/register.component"; import { RemovePasswordComponent } from "../auth/popup/remove-password.component"; import { SetPasswordComponent } from "../auth/popup/set-password.component"; -import { AccountSecurityComponent as AccountSecurityComponentV1 } from "../auth/popup/settings/account-security-v1.component"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; import { VaultTimeoutInputComponent } from "../auth/popup/settings/vault-timeout-input.component"; import { SsoComponentV1 } from "../auth/popup/sso-v1.component"; @@ -165,7 +164,6 @@ import "../platform/popup/locales"; TwoFactorOptionsComponent, UpdateTempPasswordComponent, UserVerificationComponent, - AccountSecurityComponentV1, VaultTimeoutInputComponent, ViewComponent, ViewCustomFieldsComponent, From 9f670c68208b24a886add9ea97f14aca3dd35e67 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:34:03 +0000 Subject: [PATCH 02/18] Autosync the updated translations (#12673) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/ar/messages.json | 6 +- apps/desktop/src/locales/fi/messages.json | 4 +- apps/desktop/src/locales/fr/messages.json | 24 +-- apps/desktop/src/locales/it/messages.json | 140 +++++++++--------- apps/desktop/src/locales/ja/messages.json | 148 +++++++++---------- apps/desktop/src/locales/nl/messages.json | 14 +- apps/desktop/src/locales/sk/messages.json | 2 +- apps/desktop/src/locales/sr/messages.json | 52 +++---- apps/desktop/src/locales/tr/messages.json | 4 +- apps/desktop/src/locales/zh_CN/messages.json | 26 ++-- 10 files changed, 210 insertions(+), 210 deletions(-) diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index d9c702b19d8..a15dbb5f078 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -3399,10 +3399,10 @@ "message": "ملاحظة هامة" }, "setupTwoStepLogin": { - "message": "إعداد المصادقة الثنائية" + "message": "إعداد تسجيل الدخول بخطوتين" }, "newDeviceVerificationNoticeContentPage1": { - "message": "سيقوم Bitwarden بإرسال رمز إلى البريد الإلكتروني الخاص بحسابك للتحقق من تسجيلات الدخول من الأجهزة الجديدة ابتداء من فبراير 2025." + "message": "سيقوم Bitwarden بإرسال رمز إلى البريد الإلكتروني الخاص بحسابك للتحقق من تسجيلات الدخول من الأجهزة الجديدة ابتداءً من فبراير 2025." }, "newDeviceVerificationNoticeContentPage2": { "message": "يمكنك إعداد المصادقة الثنائية كطريقة بديلة لحماية حسابك أو تغيير بريدك الإلكتروني إلى بريد يمكنك الوصول إليه." @@ -3426,7 +3426,7 @@ "message": "نعم، يمكنني الوصول بشكل موثوق إلى بريدي الإلكتروني" }, "turnOnTwoStepLogin": { - "message": "تفعيل المصادقة الثنائية" + "message": "تشغيل تسجيل الدخول بخطوتين" }, "changeAcctEmail": { "message": "تغيير البريد الإلكتروني الخاص بالحساب" diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index 226c44bc352..69092054f28 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -2729,7 +2729,7 @@ "message": "Laitteeseesi lähetettiin ilmoitus" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "Varmista, että vahvistavan laitteen holvi on avattu ja että se näyttää saman tunnistelausekkeen" }, "needAnotherOptionV1": { "message": "Tarvitsetko toisen vaihtoehdon?" @@ -3402,7 +3402,7 @@ "message": "Määritä kaksivaiheinen kirjautuminen" }, "newDeviceVerificationNoticeContentPage1": { - "message": "Bitwarden will send a code to your account email to verify logins from new devices starting in February 2025." + "message": "Bitwarden lähettää tilisi sähköpostiosoitteeseen koodin, jolla voit vahvistaa kirjautumiset uusista laitteista helmikuusta 2025 alkaen." }, "newDeviceVerificationNoticeContentPage2": { "message": "You can set up two-step login as an alternative way to protect your account or change your email to one you can access." diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index d387cbb20a0..a353653e1e3 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -323,7 +323,7 @@ "message": "Générer un mot de passe" }, "generatePassphrase": { - "message": "Generate passphrase" + "message": "Générer une phrase de passe" }, "type": { "message": "Type" @@ -467,7 +467,7 @@ "message": "Copier la clé privée SSH" }, "copyPassphrase": { - "message": "Copy passphrase", + "message": "Copier la phrase de passe", "description": "Copy passphrase to clipboard" }, "copyUri": { @@ -926,7 +926,7 @@ "message": "La session d'authentification a expiré. Veuillez redémarrer le processus de connexion." }, "selfHostBaseUrl": { - "message": "Self-host server URL", + "message": "URL du serveur auto-hébergé", "description": "Label for field requesting a self-hosted integration service URL" }, "apiUrl": { @@ -1951,7 +1951,7 @@ "message": "Votre nouveau mot de passe principal ne répond pas aux exigences de politique de sécurité." }, "receiveMarketingEmailsV2": { - "message": "Get advice, announcements, and research opportunities from Bitwarden in your inbox." + "message": "Obtenez des conseils, des annonces et des opportunités de recherche de la part de Bitwarden dans votre boîte de réception." }, "unsubscribe": { "message": "Se désabonner" @@ -2478,10 +2478,10 @@ "message": "Générer le nom d'utilisateur" }, "generateEmail": { - "message": "Generate email" + "message": "Générer un courriel" }, "spinboxBoundariesHint": { - "message": "Value must be between $MIN$ and $MAX$.", + "message": "La valeur doit être comprise entre $MIN$ et $MAX$.", "description": "Explains spin box minimum and maximum values to the user", "placeholders": { "min": { @@ -2495,7 +2495,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Use $RECOMMENDED$ characters or more to generate a strong password.", + "message": " Utilisez $RECOMMENDED$ caractères ou plus pour générer un mot de passe fort.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2505,7 +2505,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Use $RECOMMENDED$ words or more to generate a strong passphrase.", + "message": " Utilisez $RECOMMENDED$ mots ou plus pour générer une phrase de passe forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2729,10 +2729,10 @@ "message": "A notification was sent to your device" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "Assurez-vous que votre compte est déverrouillé et que la phrase d'empreinte digitale correspond à celle de l'autre appareil" }, "needAnotherOptionV1": { - "message": "Need another option?" + "message": "Besoin d'une autre option ?" }, "fingerprintMatchInfo": { "message": "Veuillez vous assurer que votre coffre est déverrouillé et que la phrase d'empreinte correspond à celle de l'autre appareil." @@ -2741,13 +2741,13 @@ "message": "Phrase d'empreinte" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "You will be notified once the request is approved" + "message": "Vous serez notifié une fois que la demande sera approuvée" }, "needAnotherOption": { "message": "La connexion avec l'appareil doit être configurée dans les paramètres de l'application Bitwarden. Besoin d'une autre option ?" }, "viewAllLogInOptions": { - "message": "View all log in options" + "message": "Afficher toutes les options de connexion" }, "viewAllLoginOptions": { "message": "Afficher toutes les options de connexion" diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index e8c0a3d1a39..e035a13606d 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -27,7 +27,7 @@ "message": "Nota sicura" }, "typeSshKey": { - "message": "SSH key" + "message": "Chiave SSH" }, "folders": { "message": "Cartelle" @@ -64,7 +64,7 @@ } }, "welcomeBack": { - "message": "Welcome back" + "message": "Bentornato" }, "moveToOrgDesc": { "message": "Scegli un'organizzazione in cui vuoi spostare questo elemento. Spostarlo in un'organizzazione trasferisce la proprietà dell'elemento all'organizzazione. Una volta spostato, non sarai più il proprietario diretto di questo elemento." @@ -181,61 +181,61 @@ "message": "Indirizzo" }, "sshPrivateKey": { - "message": "Private key" + "message": "Chiave privata" }, "sshPublicKey": { - "message": "Public key" + "message": "Chiave pubblica" }, "sshFingerprint": { - "message": "Fingerprint" + "message": "Impronta digitale" }, "sshKeyAlgorithm": { - "message": "Key type" + "message": "Tipo di chiave" }, "sshKeyAlgorithmED25519": { "message": "ED25519" }, "sshKeyAlgorithmRSA2048": { - "message": "RSA 2048-Bit" + "message": "RSA a 2048 bit" }, "sshKeyAlgorithmRSA3072": { - "message": "RSA 3072-Bit" + "message": "RSA a 3072 bit" }, "sshKeyAlgorithmRSA4096": { - "message": "RSA 4096-Bit" + "message": "RSA a 4096 bit" }, "sshKeyGenerated": { - "message": "A new SSH key was generated" + "message": "È stata generata una nuova chiave SSH" }, "sshKeyWrongPassword": { - "message": "The password you entered is incorrect." + "message": "La password inserita non è corretta." }, "importSshKey": { - "message": "Import" + "message": "Importa" }, "confirmSshKeyPassword": { - "message": "Confirm password" + "message": "Conferma password" }, "enterSshKeyPasswordDesc": { - "message": "Enter the password for the SSH key." + "message": "Inserisci la password per la chiave SSH." }, "enterSshKeyPassword": { - "message": "Enter password" + "message": "Inserisci password" }, "sshAgentUnlockRequired": { - "message": "Please unlock your vault to approve the SSH key request." + "message": "Sbloccare la cassaforte per approvare la richiesta di chiave SSH." }, "sshAgentUnlockTimeout": { - "message": "SSH key request timed out." + "message": "Richiesta chiave SSH scaduta." }, "enableSshAgent": { - "message": "Enable SSH agent" + "message": "Abilita agente SSH" }, "enableSshAgentDesc": { - "message": "Enable the SSH agent to sign SSH requests right from your Bitwarden vault." + "message": "Abilita l'agente SSH per firmare le richieste SSH direttamente dalla tua cassaforte Bitwarden." }, "enableSshAgentHelp": { - "message": "The SSH agent is a service targeted at developers that allows you to sign SSH requests directly from your Bitwarden vault." + "message": "L'agente SSH è un servizio rivolto agli sviluppatori che consente di firmare le richieste SSH direttamente dalla tua cassaforte Bitwarden." }, "premiumRequired": { "message": "Premium necessario" @@ -461,10 +461,10 @@ "message": "Copia password" }, "regenerateSshKey": { - "message": "Regenerate SSH key" + "message": "Rigenera la chiave SSH" }, "copySshPrivateKey": { - "message": "Copy SSH private key" + "message": "Copia chiave privata SSH" }, "copyPassphrase": { "message": "Copia passphrase", @@ -624,7 +624,7 @@ "message": "Crea account" }, "newToBitwarden": { - "message": "New to Bitwarden?" + "message": "Nuovo in Bitwarden?" }, "setAStrongPassword": { "message": "Imposta una password robusta" @@ -636,16 +636,16 @@ "message": "Accedi" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Accedi a Bitwarden" }, "logInWithPasskey": { - "message": "Log in with passkey" + "message": "Accedi con passkey" }, "loginWithDevice": { - "message": "Log in with device" + "message": "Accedi con dispositivo" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "Usa il Single Sign-On" }, "submit": { "message": "Invia" @@ -920,10 +920,10 @@ "message": "URL del server" }, "authenticationTimeout": { - "message": "Authentication timeout" + "message": "Timeout autenticazione" }, "authenticationSessionTimedOut": { - "message": "The authentication session timed out. Please restart the login process." + "message": "La sessione di autenticazione è scaduta. Accedi di nuovo." }, "selfHostBaseUrl": { "message": "URL server autogestito", @@ -1393,13 +1393,13 @@ "message": "Cronologia delle password" }, "generatorHistory": { - "message": "Generator history" + "message": "Cronologia generatore" }, "clearGeneratorHistoryTitle": { - "message": "Clear generator history" + "message": "Cancella cronologia generatore" }, "cleargGeneratorHistoryDescription": { - "message": "If you continue, all entries will be permanently deleted from generator's history. Are you sure you want to continue?" + "message": "Se continui, tutte le voci verranno eliminate definitivamente dalla cronologia del generatore. Vuoi continuare?" }, "clear": { "message": "Cancella", @@ -1409,13 +1409,13 @@ "message": "Non ci sono password da mostrare." }, "clearHistory": { - "message": "Clear history" + "message": "Cancella cronologia" }, "nothingToShow": { - "message": "Nothing to show" + "message": "Niente da mostrare" }, "nothingGeneratedRecently": { - "message": "You haven't generated anything recently" + "message": "Non hai generato niente di recente" }, "undo": { "message": "Annulla" @@ -1771,10 +1771,10 @@ "message": "L'eliminazione del tuo account è permanente. Non può essere annullata." }, "cannotDeleteAccount": { - "message": "Cannot delete account" + "message": "Impossibile eliminare account" }, "cannotDeleteAccountDesc": { - "message": "This action cannot be completed because your account is owned by an organization. Contact your organization administrator for additional details." + "message": "Questa azione non può essere completata perché il tuo account è di proprietà di un'organizzazione. Contatta l'amministratore della tua organizzazione per dettagli." }, "accountDeleted": { "message": "Account eliminato" @@ -2481,7 +2481,7 @@ "message": "Genera e-mail" }, "spinboxBoundariesHint": { - "message": "Value must be between $MIN$ and $MAX$.", + "message": "Il valore deve essere compreso tra $MIN$ e $MAX$.", "description": "Explains spin box minimum and maximum values to the user", "placeholders": { "min": { @@ -2495,7 +2495,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Use $RECOMMENDED$ characters or more to generate a strong password.", + "message": " Usa $RECOMMENDED$ caratteri o più per generare una password forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2505,7 +2505,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Use $RECOMMENDED$ words or more to generate a strong passphrase.", + "message": " Usa $RECOMMENDED$ parole o più per generare una passphrase forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2726,13 +2726,13 @@ "message": "Una notifica è stata inviata al tuo dispositivo." }, "aNotificationWasSentToYourDevice": { - "message": "A notification was sent to your device" + "message": "Una notifica è stata inviata al tuo dispositivo" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "Assicurati che il tuo account sia sbloccato e che la frase dell'impronta digitale corrisponda nell'altro dispositivo" }, "needAnotherOptionV1": { - "message": "Need another option?" + "message": "Bisogno di un'altra opzione?" }, "fingerprintMatchInfo": { "message": "Assicurati che la tua cassaforte sia sbloccata e che la frase impronta corrisponda sull'altro dispositivo." @@ -2741,13 +2741,13 @@ "message": "Frase impronta" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "You will be notified once the request is approved" + "message": "Sarai notificato una volta che la richiesta sarà approvata" }, "needAnotherOption": { "message": "L'accesso con dispositivo deve essere abilitato nelle impostazioni dell'app Bitwarden. Ti serve un'altra opzione?" }, "viewAllLogInOptions": { - "message": "View all log in options" + "message": "Visualizza tutte le opzioni di accesso" }, "viewAllLoginOptions": { "message": "Visualizza tutte le opzioni di accesso" @@ -2869,7 +2869,7 @@ "message": "Controlla se la tua password è presente in una violazione dei dati" }, "loggedInExclamation": { - "message": "Logged in!" + "message": "Accesso effettuato!" }, "important": { "message": "Importante:" @@ -2902,16 +2902,16 @@ "message": "Aggiornamento delle impostazioni consigliato" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Remember this device to make future logins seamless" + "message": "Ricorda questo dispositivo per rendere immediati i futuri accessi" }, "deviceApprovalRequired": { "message": "Approvazione del dispositivo obbligatoria. Seleziona un'opzione di approvazione:" }, "deviceApprovalRequiredV2": { - "message": "Device approval required" + "message": "Approvazione dispositivo richiesta" }, "selectAnApprovalOptionBelow": { - "message": "Select an approval option below" + "message": "Seleziona un'opzione di approvazione sotto" }, "rememberThisDevice": { "message": "Ricorda questo dispositivo" @@ -2966,7 +2966,7 @@ "message": "Email utente mancante" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "Email utente attiva non trovata. Logout in corso." }, "deviceTrusted": { "message": "Dispositivo fidato" @@ -3363,55 +3363,55 @@ "message": "Non è stato possibile trovare nessuna porta libera per il login Sso." }, "authorize": { - "message": "Authorize" + "message": "Autorizza" }, "deny": { - "message": "Deny" + "message": "Nega" }, "sshkeyApprovalTitle": { - "message": "Confirm SSH key usage" + "message": "Conferma l'uso della chiave SSH" }, "sshkeyApprovalMessageInfix": { - "message": "is requesting access to" + "message": "richiede l'accesso a" }, "unknownApplication": { - "message": "An application" + "message": "Un'applicazione" }, "sshKeyPasswordUnsupported": { - "message": "Importing password protected SSH keys is not yet supported" + "message": "L'importazione di chiavi SSH protette da password non è ancora supportata" }, "invalidSshKey": { - "message": "The SSH key is invalid" + "message": "La chiave SSH non è valida" }, "sshKeyTypeUnsupported": { - "message": "The SSH key type is not supported" + "message": "Il tipo di chiave SSH non è supportato" }, "importSshKeyFromClipboard": { - "message": "Import key from clipboard" + "message": "Importa chiave dagli Appunti" }, "sshKeyPasted": { - "message": "SSH key imported successfully" + "message": "Chiave SSH importata correttamente" }, "fileSavedToDevice": { "message": "File salvato sul dispositivo. Gestisci dai download del dispositivo." }, "importantNotice": { - "message": "Important notice" + "message": "Notifica importante" }, "setupTwoStepLogin": { - "message": "Set up two-step login" + "message": "Imposta accesso in due passaggi" }, "newDeviceVerificationNoticeContentPage1": { - "message": "Bitwarden will send a code to your account email to verify logins from new devices starting in February 2025." + "message": "Bitwarden invierà un codice all'e-mail del tuo account per verificare gli accessi da nuovi dispositivi a partire da febbraio 2025." }, "newDeviceVerificationNoticeContentPage2": { - "message": "You can set up two-step login as an alternative way to protect your account or change your email to one you can access." + "message": "Puoi impostare l'accesso in due passaggi come modo alternativo per proteggere il tuo account, o cambiare la tua e-mail in una alla quale puoi accedere." }, "remindMeLater": { - "message": "Remind me later" + "message": "Ricordamelo più tardi" }, "newDeviceVerificationNoticePageOneFormContent": { - "message": "Do you have reliable access to your email, $EMAIL$?", + "message": "Hai accesso affidabile alla tua e-mail, $EMAIL$?", "placeholders": { "email": { "content": "$1", @@ -3420,15 +3420,15 @@ } }, "newDeviceVerificationNoticePageOneEmailAccessNo": { - "message": "No, I do not" + "message": "No, non ce l'ho" }, "newDeviceVerificationNoticePageOneEmailAccessYes": { - "message": "Yes, I can reliably access my email" + "message": "Sì, posso accedere in modo affidabile alla mia e-mail" }, "turnOnTwoStepLogin": { - "message": "Turn on two-step login" + "message": "Attiva accesso in due passaggi" }, "changeAcctEmail": { - "message": "Change account email" + "message": "Cambia l'e-mail dell'account" } } diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index c146fb2404c..7315d74a70f 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -27,7 +27,7 @@ "message": "セキュアメモ" }, "typeSshKey": { - "message": "SSH key" + "message": "SSH キー" }, "folders": { "message": "フォルダー" @@ -64,7 +64,7 @@ } }, "welcomeBack": { - "message": "Welcome back" + "message": "ようこそ" }, "moveToOrgDesc": { "message": "このアイテムを移動する組織を選択してください。組織に移動すると、アイテムの所有権がその組織に移行します。 このアイテムが移動された後、あなたはこのアイテムの直接の所有者にはなりません。" @@ -181,16 +181,16 @@ "message": "住所" }, "sshPrivateKey": { - "message": "Private key" + "message": "秘密鍵" }, "sshPublicKey": { - "message": "Public key" + "message": "公開鍵" }, "sshFingerprint": { - "message": "Fingerprint" + "message": "フィンガープリント" }, "sshKeyAlgorithm": { - "message": "Key type" + "message": "キーの種類" }, "sshKeyAlgorithmED25519": { "message": "ED25519" @@ -205,37 +205,37 @@ "message": "RSA 4096-Bit" }, "sshKeyGenerated": { - "message": "A new SSH key was generated" + "message": "新しい SSH 鍵が生成されました" }, "sshKeyWrongPassword": { - "message": "The password you entered is incorrect." + "message": "入力されたパスワードが間違っています。" }, "importSshKey": { - "message": "Import" + "message": "インポート" }, "confirmSshKeyPassword": { - "message": "Confirm password" + "message": "パスワードを確認" }, "enterSshKeyPasswordDesc": { - "message": "Enter the password for the SSH key." + "message": "SSH キーのパスワードを入力します。" }, "enterSshKeyPassword": { - "message": "Enter password" + "message": "パスワードを入力" }, "sshAgentUnlockRequired": { - "message": "Please unlock your vault to approve the SSH key request." + "message": "SSH キーリクエストを承認するには、保管庫のロックを解除してください。" }, "sshAgentUnlockTimeout": { - "message": "SSH key request timed out." + "message": "SSH キーの要求がタイムアウトしました。" }, "enableSshAgent": { - "message": "Enable SSH agent" + "message": "SSH エージェントを有効にする" }, "enableSshAgentDesc": { - "message": "Enable the SSH agent to sign SSH requests right from your Bitwarden vault." + "message": "Bitwarden 保管庫から直接 SSH 要求に署名するために SSH エージェントを有効にします。" }, "enableSshAgentHelp": { - "message": "The SSH agent is a service targeted at developers that allows you to sign SSH requests directly from your Bitwarden vault." + "message": "SSH エージェントとは、Bitwarden 保管庫から直接 SSH リクエストに署名できる、開発者を対象としたサービスです。" }, "premiumRequired": { "message": "プレミアム会員専用" @@ -323,7 +323,7 @@ "message": "パスワードの自動生成" }, "generatePassphrase": { - "message": "Generate passphrase" + "message": "パスフレーズを生成" }, "type": { "message": "タイプ" @@ -461,13 +461,13 @@ "message": "パスワードのコピー" }, "regenerateSshKey": { - "message": "Regenerate SSH key" + "message": "SSH キーを再生成" }, "copySshPrivateKey": { - "message": "Copy SSH private key" + "message": "SSH 秘密鍵をコピー" }, "copyPassphrase": { - "message": "Copy passphrase", + "message": "パスフレーズをコピー", "description": "Copy passphrase to clipboard" }, "copyUri": { @@ -624,7 +624,7 @@ "message": "アカウントの作成" }, "newToBitwarden": { - "message": "New to Bitwarden?" + "message": "Bitwarden は初めてですか?" }, "setAStrongPassword": { "message": "強力なパスワードを設定する" @@ -636,16 +636,16 @@ "message": "ログイン" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Bitwarden にログイン" }, "logInWithPasskey": { - "message": "Log in with passkey" + "message": "パスキーでログイン" }, "loginWithDevice": { - "message": "Log in with device" + "message": "デバイスでログイン" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "シングルサインオンを使用する" }, "submit": { "message": "送信" @@ -920,13 +920,13 @@ "message": "サーバー URL" }, "authenticationTimeout": { - "message": "Authentication timeout" + "message": "認証のタイムアウト" }, "authenticationSessionTimedOut": { - "message": "The authentication session timed out. Please restart the login process." + "message": "認証セッションの有効期限が切れました。ログイン操作を最初からやり直してください。" }, "selfHostBaseUrl": { - "message": "Self-host server URL", + "message": "自己ホスト型サーバーの URL", "description": "Label for field requesting a self-hosted integration service URL" }, "apiUrl": { @@ -1320,7 +1320,7 @@ "description": "Copy credit card number" }, "copyEmail": { - "message": "Copy email" + "message": "メールアドレスをコピー" }, "copySecurityCode": { "message": "セキュリティコードのコピー", @@ -1393,13 +1393,13 @@ "message": "パスワードの履歴" }, "generatorHistory": { - "message": "Generator history" + "message": "生成履歴" }, "clearGeneratorHistoryTitle": { - "message": "Clear generator history" + "message": "生成履歴を消去" }, "cleargGeneratorHistoryDescription": { - "message": "If you continue, all entries will be permanently deleted from generator's history. Are you sure you want to continue?" + "message": "続行すると、すべてのエントリは生成履歴から完全に削除されます。続行してもよろしいですか?" }, "clear": { "message": "消去する", @@ -1409,13 +1409,13 @@ "message": "表示するパスワードがありません" }, "clearHistory": { - "message": "Clear history" + "message": "履歴を消去" }, "nothingToShow": { - "message": "Nothing to show" + "message": "表示するものがありません" }, "nothingGeneratedRecently": { - "message": "You haven't generated anything recently" + "message": "最近生成したものはありません" }, "undo": { "message": "元に戻す" @@ -1771,10 +1771,10 @@ "message": "アカウントを恒久的に削除します。元に戻すことはできません。" }, "cannotDeleteAccount": { - "message": "Cannot delete account" + "message": "アカウントを削除できません" }, "cannotDeleteAccountDesc": { - "message": "This action cannot be completed because your account is owned by an organization. Contact your organization administrator for additional details." + "message": "このアカウントは組織が所有しているため、操作を完了できません。詳しくは組織の管理者へご確認ください。" }, "accountDeleted": { "message": "アカウントが削除されました" @@ -2478,10 +2478,10 @@ "message": "ユーザー名を生成" }, "generateEmail": { - "message": "Generate email" + "message": "メールアドレスを生成" }, "spinboxBoundariesHint": { - "message": "Value must be between $MIN$ and $MAX$.", + "message": "値は $MIN$ から $MAX$ の間でなければなりません。", "description": "Explains spin box minimum and maximum values to the user", "placeholders": { "min": { @@ -2495,7 +2495,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Use $RECOMMENDED$ characters or more to generate a strong password.", + "message": " 強力なパスワードを生成するには、 $RECOMMENDED$ 文字以上を使用してください。", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2505,7 +2505,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Use $RECOMMENDED$ words or more to generate a strong passphrase.", + "message": " 強力なパスフレーズを生成するには、 $RECOMMENDED$ 単語以上を使用してください。", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2558,11 +2558,11 @@ "message": "外部転送サービスを使用してメールエイリアスを生成します。" }, "forwarderDomainName": { - "message": "Email domain", + "message": "メールアドレスのドメイン", "description": "Labels the domain name email forwarder service option" }, "forwarderDomainNameHint": { - "message": "Choose a domain that is supported by the selected service", + "message": "選択したサービスでサポートされているドメインを選択してください", "description": "Guidance provided for email forwarding services that support multiple email domains." }, "forwarderError": { @@ -2726,13 +2726,13 @@ "message": "デバイスに通知を送信しました。" }, "aNotificationWasSentToYourDevice": { - "message": "A notification was sent to your device" + "message": "お使いのデバイスに通知が送信されました" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "アカウントがロック解除されていることと、フィンガープリントフレーズが他の端末と一致していることを確認してください" }, "needAnotherOptionV1": { - "message": "Need another option?" + "message": "別の選択肢が必要ですか?" }, "fingerprintMatchInfo": { "message": "保管庫がロックされていることと、パスフレーズが他のデバイスと一致していることを確認してください。" @@ -2741,13 +2741,13 @@ "message": "パスフレーズ" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "You will be notified once the request is approved" + "message": "リクエストが承認されると通知されます" }, "needAnotherOption": { "message": "Bitwarden アプリの設定でデバイスでログインする必要があります。別のオプションが必要ですか?" }, "viewAllLogInOptions": { - "message": "View all log in options" + "message": "すべてのログインオプションを表示" }, "viewAllLoginOptions": { "message": "すべてのログインオプションを表示" @@ -2869,7 +2869,7 @@ "message": "このパスワードの既知のデータ流出を確認" }, "loggedInExclamation": { - "message": "Logged in!" + "message": "ログインしました!" }, "important": { "message": "重要" @@ -2902,16 +2902,16 @@ "message": "設定の更新を推奨" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Remember this device to make future logins seamless" + "message": "このデバイスを記憶して今後のログインをシームレスにする" }, "deviceApprovalRequired": { "message": "デバイスの承認が必要です。以下から承認オプションを選択してください:" }, "deviceApprovalRequiredV2": { - "message": "Device approval required" + "message": "デバイスの承認が必要です" }, "selectAnApprovalOptionBelow": { - "message": "Select an approval option below" + "message": "以下の承認オプションを選択してください" }, "rememberThisDevice": { "message": "このデバイスを記憶する" @@ -2966,7 +2966,7 @@ "message": "ユーザーのメールアドレスがありません" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "アクティブなユーザーメールアドレスが見つかりません。ログアウトします。" }, "deviceTrusted": { "message": "信頼されたデバイス" @@ -3363,55 +3363,55 @@ "message": "SSO ログインのための空きポートが見つかりませんでした。" }, "authorize": { - "message": "Authorize" + "message": "認可" }, "deny": { - "message": "Deny" + "message": "拒否" }, "sshkeyApprovalTitle": { - "message": "Confirm SSH key usage" + "message": "SSH 鍵の使用を確認します" }, "sshkeyApprovalMessageInfix": { - "message": "is requesting access to" + "message": "がアクセスを要求しています: " }, "unknownApplication": { - "message": "An application" + "message": "アプリ" }, "sshKeyPasswordUnsupported": { - "message": "Importing password protected SSH keys is not yet supported" + "message": "パスワードで保護された SSH キーのインポートはまだサポートされていません" }, "invalidSshKey": { - "message": "The SSH key is invalid" + "message": "SSH キーが無効です" }, "sshKeyTypeUnsupported": { - "message": "The SSH key type is not supported" + "message": "サポートされていない種類の SSH キーです" }, "importSshKeyFromClipboard": { - "message": "Import key from clipboard" + "message": "クリップボードからキーをインポート" }, "sshKeyPasted": { - "message": "SSH key imported successfully" + "message": "SSH キーのインポートに成功しました" }, "fileSavedToDevice": { "message": "ファイルをデバイスに保存しました。デバイスのダウンロードで管理できます。" }, "importantNotice": { - "message": "Important notice" + "message": "重要なお知らせ" }, "setupTwoStepLogin": { - "message": "Set up two-step login" + "message": "2段階認証によるログインを設定する" }, "newDeviceVerificationNoticeContentPage1": { - "message": "Bitwarden will send a code to your account email to verify logins from new devices starting in February 2025." + "message": "Bitwarden は2025年2月以降、新しいデバイスからのログイン時にアカウントのメールアドレスに確認コードを送信します。" }, "newDeviceVerificationNoticeContentPage2": { - "message": "You can set up two-step login as an alternative way to protect your account or change your email to one you can access." + "message": "代わりに2段階認証によるログインでアカウントを保護するか、メールアドレスをあなたがアクセスできるものに変更できます。" }, "remindMeLater": { - "message": "Remind me later" + "message": "後で再通知" }, "newDeviceVerificationNoticePageOneFormContent": { - "message": "Do you have reliable access to your email, $EMAIL$?", + "message": "新しいメールアドレス $EMAIL$ はあなたが管理しているものですか?", "placeholders": { "email": { "content": "$1", @@ -3420,15 +3420,15 @@ } }, "newDeviceVerificationNoticePageOneEmailAccessNo": { - "message": "No, I do not" + "message": "いいえ、違います" }, "newDeviceVerificationNoticePageOneEmailAccessYes": { - "message": "Yes, I can reliably access my email" + "message": "はい、メールアドレスには私が確実にアクセスできます" }, "turnOnTwoStepLogin": { - "message": "Turn on two-step login" + "message": "2段階認証によるログインを有効にする" }, "changeAcctEmail": { - "message": "Change account email" + "message": "アカウントのメールアドレスを変更する" } } diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 2cd0232e5d4..a23ef820ab7 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -945,7 +945,7 @@ "message": "Pictogrammenserver-URL" }, "environmentSaved": { - "message": "De omgevings-URL's zijn opgeslagen." + "message": "Omgevings-URL's opgeslagen" }, "ok": { "message": "Ok" @@ -1002,7 +1002,7 @@ "message": "Nieuwe map toevoegen" }, "view": { - "message": "Beeld" + "message": "Weergeven" }, "account": { "message": "Account" @@ -1268,7 +1268,7 @@ "description": "Copy to clipboard" }, "checkForUpdates": { - "message": "Controleren op updates" + "message": "Controleren op updates…" }, "version": { "message": "Versie $VERSION_NUM$", @@ -3026,7 +3026,7 @@ } }, "multipleInputEmails": { - "message": "Een of meer e-mailadressen zijn ongeldig" + "message": "Eén of meer e-mailadressen zijn ongeldig" }, "inputTrimValidator": { "message": "Invoer mag niet alleen witruimte bevatten.", @@ -3051,7 +3051,7 @@ "message": "-- Type om te filteren --" }, "multiSelectLoading": { - "message": "Opties ophalen..." + "message": "Opties ophalen…" }, "multiSelectNotFound": { "message": "Geen items gevonden" @@ -3243,7 +3243,7 @@ "message": "LastPass Email" }, "importingYourAccount": { - "message": "Account impoteren..." + "message": "Account impoteren…" }, "lastPassMFARequired": { "message": "LastPass multifactor-authenticatie vereist" @@ -3396,7 +3396,7 @@ "message": "Bestand op apparaat opgeslagen. Beheer vanaf de downloads op je apparaat." }, "importantNotice": { - "message": "Belangrijke mededeling" + "message": "Belangrijke melding" }, "setupTwoStepLogin": { "message": "Tweestapsaanmelding instellen" diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 6013b9b61e0..cec06c3c028 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -3399,7 +3399,7 @@ "message": "Dôležité upozornenie" }, "setupTwoStepLogin": { - "message": "Nastavenie dvojstupňového prihlásenia" + "message": "Nastaviť dvojstupňové prihlásenie" }, "newDeviceVerificationNoticeContentPage1": { "message": "Bitwarden vám od februára 2025 pošle na e-mail vášho účtu kód na overenie prihlásenia z nových zariadení." diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 3196f2c208b..9f9dec2dd68 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -208,19 +208,19 @@ "message": "Генерисан је нови SSH кључ" }, "sshKeyWrongPassword": { - "message": "The password you entered is incorrect." + "message": "Лозинка коју сте унели није тачна." }, "importSshKey": { - "message": "Import" + "message": "Увоз" }, "confirmSshKeyPassword": { - "message": "Confirm password" + "message": "Потврда лозинке" }, "enterSshKeyPasswordDesc": { - "message": "Enter the password for the SSH key." + "message": "Унети лозинку за SSH кључ." }, "enterSshKeyPassword": { - "message": "Enter password" + "message": "Унесите лозинку" }, "sshAgentUnlockRequired": { "message": "Откључајте свој сеф да бисте одобрили захтев за SSH кључ." @@ -920,10 +920,10 @@ "message": "УРЛ Сервера" }, "authenticationTimeout": { - "message": "Authentication timeout" + "message": "Истекло је време аутентификације" }, "authenticationSessionTimedOut": { - "message": "The authentication session timed out. Please restart the login process." + "message": "Истекло је време сесије за аутентификацију. Молим вас покрените процес пријаве поново." }, "selfHostBaseUrl": { "message": "УРЛ сервера који се самостално хостује", @@ -1393,13 +1393,13 @@ "message": "Историја Лозинке" }, "generatorHistory": { - "message": "Generator history" + "message": "Генератор историје" }, "clearGeneratorHistoryTitle": { - "message": "Clear generator history" + "message": "Испразнити генератор историје" }, "cleargGeneratorHistoryDescription": { - "message": "If you continue, all entries will be permanently deleted from generator's history. Are you sure you want to continue?" + "message": "Ако наставите, сви уноси ће бити трајно избрисани из генератора историје. Да ли сте сигурни да желите да наставите?" }, "clear": { "message": "Очисти", @@ -1409,13 +1409,13 @@ "message": "Нема лозинки за приказивање." }, "clearHistory": { - "message": "Clear history" + "message": "Обриши историју" }, "nothingToShow": { - "message": "Nothing to show" + "message": "Ништа за приказ" }, "nothingGeneratedRecently": { - "message": "You haven't generated anything recently" + "message": "Недавно нисте ништа генерисали" }, "undo": { "message": "Опозови" @@ -2481,7 +2481,7 @@ "message": "Генеришите имејл" }, "spinboxBoundariesHint": { - "message": "Value must be between $MIN$ and $MAX$.", + "message": "Вредност мора бити између $MIN$ и $MAX$.", "description": "Explains spin box minimum and maximum values to the user", "placeholders": { "min": { @@ -2495,7 +2495,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Use $RECOMMENDED$ characters or more to generate a strong password.", + "message": " Употребити $RECOMMENDED$ знакова или више да бисте генерисали јаку лозинку.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2505,7 +2505,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Use $RECOMMENDED$ words or more to generate a strong passphrase.", + "message": " Употребити $RECOMMENDED$ речи или више да бисте генерисали јаку приступну фразу.", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2726,13 +2726,13 @@ "message": "Обавештење је послато на ваш уређај." }, "aNotificationWasSentToYourDevice": { - "message": "A notification was sent to your device" + "message": "Обавештење је послато на ваш уређај" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "Уверите се да је ваш налог откључан и да се фраза отиска подудара на другом уређају" }, "needAnotherOptionV1": { - "message": "Need another option?" + "message": "Треба Вам друга опција?" }, "fingerprintMatchInfo": { "message": "Уверите се да је ваш сеф откључан и да се фраза отиска прста подудара на другом уређају." @@ -2741,13 +2741,13 @@ "message": "Сигурносна фраза сефа" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "You will be notified once the request is approved" + "message": "Бићете обавештени када захтев буде одобрен" }, "needAnotherOption": { "message": "Пријава помоћу уређаја мора бити подешена у подешавањима Bitwarden апликације. Потребна је друга опција?" }, "viewAllLogInOptions": { - "message": "View all log in options" + "message": "Погледајте сав извештај у опције" }, "viewAllLoginOptions": { "message": "Погредајте све опције пријављивања" @@ -2869,7 +2869,7 @@ "message": "Проверите познате упада података за ову лозинку" }, "loggedInExclamation": { - "message": "Logged in!" + "message": "Пријављено!" }, "important": { "message": "Важно:" @@ -2902,16 +2902,16 @@ "message": "Препоручено ажурирање поставки" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Remember this device to make future logins seamless" + "message": "Запамтити овај уређај да би будуће пријаве биле беспрекорне" }, "deviceApprovalRequired": { "message": "Потребно је одобрење уређаја. Изаберите опцију одобрења испод:" }, "deviceApprovalRequiredV2": { - "message": "Device approval required" + "message": "Потребно је одобрење уређаја" }, "selectAnApprovalOptionBelow": { - "message": "Select an approval option below" + "message": "Изаберите опцију одобрења у наставку" }, "rememberThisDevice": { "message": "Запамти овај уређај" @@ -2966,7 +2966,7 @@ "message": "Недостаје имејл корисника" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "Имејл активног корисника није пронађен. Одјављивање." }, "deviceTrusted": { "message": "Уређај поуздан" diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 9ff0efe6854..8357f8616bc 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -3363,10 +3363,10 @@ "message": "SSO girişi için açık port bulunamadı." }, "authorize": { - "message": "Authorize" + "message": "Yetkilendir" }, "deny": { - "message": "Deny" + "message": "Reddet" }, "sshkeyApprovalTitle": { "message": "Confirm SSH key usage" diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index dfcd104cf53..9bff79aa857 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -742,7 +742,7 @@ "message": "必须填写确认主密码。" }, "masterPasswordMinlength": { - "message": "主密码必须至少 $VALUE$ 个字符长度。", + "message": "主密码长度必须至少为 $VALUE$ 个字符。", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -1044,7 +1044,7 @@ "message": "前往网页 App 吗?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "您可以在 Bitwarden 网页应用上更改您的主密码。" + "message": "您可以在 Bitwarden 网页 App 上更改您的主密码。" }, "fingerprintPhrase": { "message": "指纹短语", @@ -1058,7 +1058,7 @@ "message": "转到网页版密码库" }, "getMobileApp": { - "message": "获取移动应用程序" + "message": "获取移动 App" }, "getBrowserExtension": { "message": "获取浏览器扩展" @@ -1247,13 +1247,13 @@ "message": "语言" }, "languageDesc": { - "message": "更改应用程序所使用的语言。重新启动后生效。" + "message": "更改应用程序所使用的语言。重启后生效。" }, "theme": { "message": "主题" }, "themeDesc": { - "message": "更改本应用程序的颜色主题。" + "message": "更改应用程序的颜色主题。" }, "dark": { "message": "深色", @@ -1665,7 +1665,7 @@ "message": "确认密码库导出" }, "exportWarningDesc": { - "message": "导出的密码库数据包含未加密格式。您不应该通过不安全的渠道(例如电子邮件)来存储或发送导出的文件。用完后请立即将其删除。" + "message": "此导出包含未加密格式的密码库数据。您不应该通过不安全的渠道(例如电子邮件)来存储或发送此导出文件。使用完后请立即将其删除。" }, "encExportKeyWarningDesc": { "message": "此导出将使用您账户的加密密钥来加密您的数据。如果您曾经轮换过账户的加密密钥,您应将其重新导出,否则您将无法解密导出的文件。" @@ -1711,7 +1711,7 @@ "message": "使用 PIN 码解锁" }, "setYourPinCode": { - "message": "设定您用来解锁 Bitwarden 的 PIN 码。您的 PIN 设置将在您完全注销本应用程序时被重置。" + "message": "设置用于解锁 Bitwarden 的 PIN 码。您的 PIN 设置将在您完全注销应用程序时被重置。" }, "pinRequired": { "message": "需要 PIN 码。" @@ -1753,7 +1753,7 @@ "message": "应用程序启动时要求使用触控 ID" }, "requirePasswordOnStart": { - "message": "应用程序启动时要求输入密码或 PIN 码" + "message": "App 启动时要求输入密码或 PIN 码" }, "recommendedForSecurity": { "message": "安全起见,推荐设置。" @@ -2402,7 +2402,7 @@ "message": "偏好设置" }, "appPreferences": { - "message": "应用设置(所有账户)" + "message": "应用程序设置(所有账户)" }, "accountSwitcherLimitReached": { "message": "已达到账户上限。请注销一个账户后再添加其他账户。" @@ -3369,7 +3369,7 @@ "message": "拒绝" }, "sshkeyApprovalTitle": { - "message": "确认 SSH 密钥的使用方式" + "message": "确认 SSH 密钥的使用" }, "sshkeyApprovalMessageInfix": { "message": "正在请求访问" @@ -3402,7 +3402,7 @@ "message": "设置两步登录" }, "newDeviceVerificationNoticeContentPage1": { - "message": "从 2025 年 02 月开始,Bitwarden 将向您的账户电子邮箱发送一个代码,以验证来自新设备的登录。" + "message": "从 2025 年 02 月起,当有来自新设备的登录时,Bitwarden 将向您的账户电子邮箱发送验证码。" }, "newDeviceVerificationNoticeContentPage2": { "message": "您可以设置两步登录作为保护账户的替代方法,或将您的电子邮箱更改为您可以访问的电子邮箱。" @@ -3411,7 +3411,7 @@ "message": "稍后提醒我" }, "newDeviceVerificationNoticePageOneFormContent": { - "message": "您能可靠地访问您的电子邮箱 $EMAIL$ 吗?", + "message": "您能可正常访问您的电子邮箱 $EMAIL$ 吗?", "placeholders": { "email": { "content": "$1", @@ -3423,7 +3423,7 @@ "message": "不,我不能" }, "newDeviceVerificationNoticePageOneEmailAccessYes": { - "message": "是的,我可以可靠地访问我的电子邮箱" + "message": "是的,我可以正常访问我的电子邮箱" }, "turnOnTwoStepLogin": { "message": "开启两步登录" From 860711337e461dc3c69c7444c32628c443ae3df5 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:34:23 +0000 Subject: [PATCH 03/18] Autosync the updated translations (#12712) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/fi/messages.json | 6 +- apps/browser/src/_locales/it/messages.json | 310 +++++++++--------- apps/browser/src/_locales/ja/messages.json | 12 +- apps/browser/src/_locales/tr/messages.json | 2 +- apps/browser/src/_locales/zh_CN/messages.json | 8 +- 5 files changed, 169 insertions(+), 169 deletions(-) diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 2c621dc4621..718c0631156 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -2105,7 +2105,7 @@ "message": "Aikakatkaisutoiminnon vahvistus" }, "autoFillAndSave": { - "message": "Täytä automaattisesti ja tallenna" + "message": "Automaattitäytä ja tallenna" }, "fillAndSave": { "message": "Täytä ja tallenna" @@ -3482,7 +3482,7 @@ "description": "Aria label for the totp code displayed in the inline menu for autofill" }, "totpSecondsSpanAria": { - "message": "Time remaining before current TOTP expires", + "message": "Aika jäljellä, ennen kuin nykyinen TOTP vanhenee", "description": "Aria label for the totp seconds displayed in the inline menu for autofill" }, "fillCredentialsFor": { @@ -4810,7 +4810,7 @@ "message": "Määritä kaksivaiheinen kirjautuminen" }, "newDeviceVerificationNoticeContentPage1": { - "message": "Bitwarden will send a code to your account email to verify logins from new devices starting in February 2025." + "message": "Bitwarden lähettää tilisi sähköpostiosoitteeseen koodin, jolla voit vahvistaa kirjautumiset uusista laitteista helmikuusta 2025 alkaen." }, "newDeviceVerificationNoticeContentPage2": { "message": "You can set up two-step login as an alternative way to protect your account or change your email to one you can access." diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 711f62f4dea..6490a441832 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -20,16 +20,16 @@ "message": "Crea account" }, "newToBitwarden": { - "message": "New to Bitwarden?" + "message": "Nuovo in Bitwarden?" }, "logInWithPasskey": { - "message": "Log in with passkey" + "message": "Accedi con passkey" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "Usa il Single Sign-On" }, "welcomeBack": { - "message": "Welcome back" + "message": "Bentornato" }, "setAStrongPassword": { "message": "Imposta una password robusta" @@ -120,7 +120,7 @@ "message": "Copia password" }, "copyPassphrase": { - "message": "Copy passphrase" + "message": "Copia passphrase" }, "copyNote": { "message": "Copia nota" @@ -153,13 +153,13 @@ "message": "Copia numero licenza" }, "copyPrivateKey": { - "message": "Copy private key" + "message": "Copia chiave privata" }, "copyPublicKey": { - "message": "Copy public key" + "message": "Copia chiave pubblica" }, "copyFingerprint": { - "message": "Copy fingerprint" + "message": "Copia impronta" }, "copyCustomField": { "message": "Copia $FIELD$", @@ -177,7 +177,7 @@ "message": "Copia note" }, "fill": { - "message": "Fill", + "message": "Riempi", "description": "This string is used on the vault page to indicate autofilling. Horizontal space is limited in the interface here so try and keep translations as concise as possible." }, "autoFill": { @@ -193,10 +193,10 @@ "message": "Riempi automaticamente identità" }, "fillVerificationCode": { - "message": "Fill verification code" + "message": "Riempi codice di verifica" }, "fillVerificationCodeAria": { - "message": "Fill Verification Code", + "message": "Riempi Codice di Verifica", "description": "Aria label for the heading displayed the inline menu for totp code autofill" }, "generatePasswordCopied": { @@ -239,7 +239,7 @@ "message": "Aggiungi elemento" }, "accountEmail": { - "message": "Account email" + "message": "Email dell'account" }, "requestHint": { "message": "Richiedi suggerimento" @@ -443,7 +443,7 @@ "message": "Genera password" }, "generatePassphrase": { - "message": "Generate passphrase" + "message": "Genera passphrase" }, "regeneratePassword": { "message": "Rigenera password" @@ -530,7 +530,7 @@ "description": "Label for the avoid ambiguous characters checkbox." }, "generatorPolicyInEffect": { - "message": "Enterprise policy requirements have been applied to your generator options.", + "message": "I requisiti di politica aziendale sono stati applicati alle opzioni del generatore.", "description": "Indicates that a policy limits the credential generator screen." }, "searchVault": { @@ -576,7 +576,7 @@ "message": "Note" }, "privateNote": { - "message": "Private note" + "message": "Nota privata" }, "note": { "message": "Nota" @@ -600,7 +600,7 @@ "message": "Avvia il sito web" }, "launchWebsiteName": { - "message": "Launch website $ITEMNAME$", + "message": "Apri sito web $ITEMNAME$", "placeholders": { "itemname": { "content": "$1", @@ -633,7 +633,7 @@ "message": "Timeout della sessione" }, "vaultTimeoutHeader": { - "message": "Vault timeout" + "message": "Timeout cassaforte" }, "otherOptions": { "message": "Altre opzioni" @@ -651,13 +651,13 @@ "message": "La tua cassaforte è bloccata. Verifica la tua identità per continuare." }, "yourVaultIsLockedV2": { - "message": "Your vault is locked" + "message": "Cassaforte bloccata" }, "yourAccountIsLocked": { - "message": "Your account is locked" + "message": "Il tuo account è bloccato" }, "or": { - "message": "or" + "message": "o" }, "unlock": { "message": "Sblocca" @@ -852,7 +852,7 @@ "message": "Accedi" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Accedi a Bitwarden" }, "restartRegistration": { "message": "Riprova la registrazione" @@ -888,10 +888,10 @@ "message": "La verifica in due passaggi rende il tuo account più sicuro richiedendoti di verificare il tuo login usando un altro dispositivo come una chiave di sicurezza, app di autenticazione, SMS, telefonata, o email. Può essere abilitata nella cassaforte web su bitwarden.com. Vuoi visitare il sito?" }, "twoStepLoginConfirmationContent": { - "message": "Make your account more secure by setting up two-step login in the Bitwarden web app." + "message": "Rendi il tuo account più sicuro impostando l'autenticazione a due fattori nell'app web di Bitwarden." }, "twoStepLoginConfirmationTitle": { - "message": "Continue to web app?" + "message": "Aprire web app?" }, "editedFolder": { "message": "Cartella salvata" @@ -1005,7 +1005,7 @@ "message": "Mostra le identità nella sezione Scheda per riempirle automaticamente." }, "clickToAutofillOnVault": { - "message": "Click items to autofill on Vault view" + "message": "Clicca gli oggetti da riempire dalla sezione Cassaforte" }, "clearClipboard": { "message": "Cancella appunti", @@ -1126,7 +1126,7 @@ "description": "WARNING (should stay in capitalized letters if the language permits)" }, "warningCapitalized": { - "message": "Warning", + "message": "Attenzione", "description": "Warning (should maintain locale-relevant capitalization)" }, "confirmVaultExport": { @@ -1206,7 +1206,7 @@ "message": "File" }, "fileToShare": { - "message": "File to share" + "message": "File da condividere" }, "selectFile": { "message": "Seleziona un file" @@ -1317,10 +1317,10 @@ "message": "Inserisci il codice di verifica a 6 cifre dalla tua app di autenticazione." }, "authenticationTimeout": { - "message": "Authentication timeout" + "message": "Timeout autenticazione" }, "authenticationSessionTimedOut": { - "message": "The authentication session timed out. Please restart the login process." + "message": "La sessione di autenticazione è scaduta. Accedi di nuovo." }, "enterVerificationCodeEmail": { "message": "Inserisci il codice di verifica a 6 cifre inviato a $EMAIL$.", @@ -1440,7 +1440,7 @@ "message": "URL del server" }, "selfHostBaseUrl": { - "message": "Self-host server URL", + "message": "URL server autogestito", "description": "Label for field requesting a self-hosted integration service URL" }, "apiUrl": { @@ -1472,10 +1472,10 @@ "message": "Mostra suggerimenti di riempimento automatico nei campi del modulo" }, "showInlineMenuIdentitiesLabel": { - "message": "Display identities as suggestions" + "message": "Mostra identità come consigli" }, "showInlineMenuCardsLabel": { - "message": "Display cards as suggestions" + "message": "Mostra carte come consigli" }, "showInlineMenuOnIconSelectionLabel": { "message": "Mostra suggerimenti quando l'icona è selezionata" @@ -1768,7 +1768,7 @@ "message": "Identità" }, "typeSshKey": { - "message": "SSH key" + "message": "Chiave SSH" }, "newItemHeader": { "message": "Nuovo $TYPE$", @@ -1801,13 +1801,13 @@ "message": "Cronologia delle password" }, "generatorHistory": { - "message": "Generator history" + "message": "Cronologia generatore" }, "clearGeneratorHistoryTitle": { - "message": "Clear generator history" + "message": "Cancella cronologia generatore" }, "cleargGeneratorHistoryDescription": { - "message": "If you continue, all entries will be permanently deleted from generator's history. Are you sure you want to continue?" + "message": "Se continui, tutte le voci verranno eliminate definitivamente dalla cronologia del generatore. Vuoi continuare?" }, "back": { "message": "Indietro" @@ -1846,7 +1846,7 @@ "message": "Note sicure" }, "sshKeys": { - "message": "SSH Keys" + "message": "Chiavi SSH" }, "clear": { "message": "Cancella", @@ -1929,10 +1929,10 @@ "message": "Cancella cronologia" }, "nothingToShow": { - "message": "Nothing to show" + "message": "Niente da mostrare" }, "nothingGeneratedRecently": { - "message": "You haven't generated anything recently" + "message": "Non hai generato niente di recente" }, "remove": { "message": "Rimuovi" @@ -1993,16 +1993,16 @@ "message": "Sblocca con PIN" }, "setYourPinTitle": { - "message": "Set PIN" + "message": "Imposta PIN" }, "setYourPinButton": { - "message": "Set PIN" + "message": "Imposta PIN" }, "setYourPinCode": { "message": "Imposta il tuo codice PIN per sbloccare Bitwarden. Le tue impostazioni PIN saranno resettate se esci completamente dall'app." }, "setYourPinCode1": { - "message": "Your PIN will be used to unlock Bitwarden instead of your master password. Your PIN will reset if you ever fully log out of Bitwarden." + "message": "Il tuo PIN sarà usato per sbloccare Bitwarden invece della password principale. Il PIN sarà ripristinato se ti disconnetterai completamente da Bitwarden." }, "pinRequired": { "message": "Codice PIN obbligatorio." @@ -2017,7 +2017,7 @@ "message": "Sblocca con i dati biometrici" }, "unlockWithMasterPassword": { - "message": "Unlock with master password" + "message": "Sblocca con password principale" }, "awaitDesktop": { "message": "In attesa di conferma dal desktop" @@ -2029,7 +2029,7 @@ "message": "Blocca con la password principale al riavvio del browser" }, "lockWithMasterPassOnRestart1": { - "message": "Require master password on browser restart" + "message": "Richiedi password principale al riavvio del browser" }, "selectOneCollection": { "message": "Devi selezionare almeno una raccolta." @@ -2067,7 +2067,7 @@ "message": "Azione timeout cassaforte" }, "vaultTimeoutAction1": { - "message": "Timeout action" + "message": "Azione al timeout" }, "lock": { "message": "Blocca", @@ -2355,14 +2355,14 @@ "message": "Modifiche del dominio escluso salvate" }, "limitSendViews": { - "message": "Limit views" + "message": "Limita visualizzazioni" }, "limitSendViewsHint": { - "message": "No one can view this Send after the limit is reached.", + "message": "Nessuno potrà vedere questo Send al raggiungimento del limite.", "description": "Displayed under the limit views field on Send" }, "limitSendViewsCount": { - "message": "$ACCESSCOUNT$ views left", + "message": "$ACCESSCOUNT$ visualizzazioni rimaste", "description": "Displayed under the limit views field on Send", "placeholders": { "accessCount": { @@ -2376,14 +2376,14 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDetails": { - "message": "Send details", + "message": "Dettagli Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeText": { "message": "Testo" }, "sendTypeTextToShare": { - "message": "Text to share" + "message": "Testo da condividere" }, "sendTypeFile": { "message": "File" @@ -2393,7 +2393,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "hideTextByDefault": { - "message": "Hide text by default" + "message": "Nascondi testo come default" }, "expired": { "message": "Scaduto" @@ -2440,7 +2440,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deleteSendPermanentConfirmation": { - "message": "Are you sure you want to permanently delete this Send?", + "message": "Sicuro di voler eliminare definitivamente questo Send?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { @@ -2451,7 +2451,7 @@ "message": "Data di eliminazione" }, "deletionDateDescV2": { - "message": "The Send will be permanently deleted on this date.", + "message": "Il Send sarà cancellato definitivamente in questa data.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { @@ -2473,7 +2473,7 @@ "message": "Personalizzato" }, "sendPasswordDescV3": { - "message": "Add an optional password for recipients to access this Send.", + "message": "Richiedi ai destinatari una password opzionale per aprire questo Send.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createSend": { @@ -2500,11 +2500,11 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendExpiresInHoursSingle": { - "message": "The Send will be available to anyone with the link for the next 1 hour.", + "message": "Il Send sarà disponibile a chiunque con il link per la prossima ora.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendExpiresInHours": { - "message": "The Send will be available to anyone with the link for the next $HOURS$ hours.", + "message": "Il Send sarà disponibile a chiunque con il link per le prossime $HOURS$ ore.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", "placeholders": { "hours": { @@ -2514,11 +2514,11 @@ } }, "sendExpiresInDaysSingle": { - "message": "The Send will be available to anyone with the link for the next 1 day.", + "message": "Il Send sarà disponibile a chiunque con il link per il prossimo giorno.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendExpiresInDays": { - "message": "The Send will be available to anyone with the link for the next $DAYS$ days.", + "message": "Il Send sarà disponibile a chiunque con il link per i prossimi $DAYS$ giorni.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.", "placeholders": { "days": { @@ -2536,11 +2536,11 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendFilePopoutDialogText": { - "message": "Pop out extension?", + "message": "Scollegare estensione?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendFilePopoutDialogDesc": { - "message": "To create a file Send, you need to pop out the extension to a new window.", + "message": "Per creare un file Send, devi scollegare l'estensione in una nuova finestra.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { @@ -2553,7 +2553,7 @@ "message": "Per scegliere un file usando Safari, apri una nuova finestra cliccando questo banner." }, "popOut": { - "message": "Pop out" + "message": "Scollega" }, "sendFileCalloutHeader": { "message": "Prima di iniziare" @@ -2574,7 +2574,7 @@ "message": "Si è verificato un errore durante il salvataggio delle date di eliminazione e scadenza." }, "hideYourEmail": { - "message": "Hide your email address from viewers." + "message": "Nascondi il tuo indirizzo email ai visualizzatori." }, "passwordPrompt": { "message": "Richiedi di inserire la password principale di nuovo per visualizzare questo elemento" @@ -2631,7 +2631,7 @@ "description": "Used as a card title description on the set password page to explain why the user is there" }, "cardMetrics": { - "message": "out of $TOTAL$", + "message": "di $TOTAL$", "placeholders": { "total": { "content": "$1", @@ -2650,7 +2650,7 @@ "message": "Minuti" }, "vaultTimeoutPolicyAffectingOptions": { - "message": "Enterprise policy requirements have been applied to your timeout options" + "message": "I requisiti di politica aziendale sono stati applicati alle opzioni di timeout" }, "vaultTimeoutPolicyInEffect": { "message": "Le politiche della tua organizzazione hanno impostato il timeout massimo consentito della tua cassaforte su $HOURS$ ore e $MINUTES$ minuti.", @@ -2666,7 +2666,7 @@ } }, "vaultTimeoutPolicyInEffect1": { - "message": "$HOURS$ hour(s) and $MINUTES$ minute(s) maximum.", + "message": "Al massimo $HOURS$ ora/e e $MINUTES$ minuto/i.", "placeholders": { "hours": { "content": "$1", @@ -2679,7 +2679,7 @@ } }, "vaultTimeoutPolicyMaximumError": { - "message": "Timeout exceeds the restriction set by your organization: $HOURS$ hour(s) and $MINUTES$ minute(s) maximum", + "message": "Il timeout supera la restrizione impostata dalla tua organizzazione: massimo $HOURS$ ora/e e $MINUTES$ minuto/i", "placeholders": { "hours": { "content": "$1", @@ -2793,10 +2793,10 @@ "message": "Genera nome utente" }, "generateEmail": { - "message": "Generate email" + "message": "Genera email" }, "spinboxBoundariesHint": { - "message": "Value must be between $MIN$ and $MAX$.", + "message": "Il valore deve essere compreso tra $MIN$ e $MAX$.", "description": "Explains spin box minimum and maximum values to the user", "placeholders": { "min": { @@ -2810,7 +2810,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Use $RECOMMENDED$ characters or more to generate a strong password.", + "message": " Usa $RECOMMENDED$ caratteri o più per generare una password forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2820,7 +2820,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Use $RECOMMENDED$ words or more to generate a strong passphrase.", + "message": " Usa $RECOMMENDED$ parole o più per generare una passphrase forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2861,11 +2861,11 @@ "message": "Genera un alias email con un servizio di inoltro esterno." }, "forwarderDomainName": { - "message": "Email domain", + "message": "Dominio email", "description": "Labels the domain name email forwarder service option" }, "forwarderDomainNameHint": { - "message": "Choose a domain that is supported by the selected service", + "message": "Scegli un dominio supportato dal servizio selezionato", "description": "Guidance provided for email forwarding services that support multiple email domains." }, "forwarderError": { @@ -3068,25 +3068,25 @@ "message": "Invia notifica di nuovo" }, "viewAllLogInOptions": { - "message": "View all log in options" + "message": "Visualizza tutte le opzioni di accesso" }, "viewAllLoginOptionsV1": { - "message": "View all log in options" + "message": "Visualizza tutte le opzioni di accesso" }, "notificationSentDevice": { "message": "Una notifica è stata inviata al tuo dispositivo." }, "aNotificationWasSentToYourDevice": { - "message": "A notification was sent to your device" + "message": "Una notifica è stata inviata al tuo dispositivo" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "Assicurati che il tuo account sia sbloccato e che la frase dell'impronta digitale corrisponda nell'altro dispositivo" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "You will be notified once the request is approved" + "message": "Sarai notificato una volta che la richiesta sarà approvata" }, "needAnotherOptionV1": { - "message": "Need another option?" + "message": "Bisogno di un'altra opzione?" }, "loginInitiated": { "message": "Accesso avviato" @@ -3182,16 +3182,16 @@ "message": "Si apre in una nuova finestra" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Remember this device to make future logins seamless" + "message": "Ricorda questo dispositivo per rendere immediati i futuri accessi" }, "deviceApprovalRequired": { "message": "Approvazione del dispositivo obbligatoria. Seleziona un'opzione di approvazione:" }, "deviceApprovalRequiredV2": { - "message": "Device approval required" + "message": "Approvazione dispositivo richiesta" }, "selectAnApprovalOptionBelow": { - "message": "Select an approval option below" + "message": "Seleziona un'opzione di approvazione sotto" }, "rememberThisDevice": { "message": "Ricorda questo dispositivo" @@ -3267,7 +3267,7 @@ "message": "Email utente mancante" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "Email utente attiva non trovata. Logout in corso." }, "deviceTrusted": { "message": "Dispositivo fidato" @@ -3478,11 +3478,11 @@ "description": "Screen reader text (aria-label) for unlock account button in overlay" }, "totpCodeAria": { - "message": "Time-based One-Time Password Verification Code", + "message": "Codice di Verifica One-Time a tempo", "description": "Aria label for the totp code displayed in the inline menu for autofill" }, "totpSecondsSpanAria": { - "message": "Time remaining before current TOTP expires", + "message": "Tempo rimasto prima che l'attuale TOTP scada", "description": "Aria label for the totp seconds displayed in the inline menu for autofill" }, "fillCredentialsFor": { @@ -3711,10 +3711,10 @@ "message": "Passkey" }, "accessing": { - "message": "Accessing" + "message": "Accedendo a" }, "loggedInExclamation": { - "message": "Logged in!" + "message": "Accesso effettuato!" }, "passkeyNotCopied": { "message": "La passkey non sarà copiata" @@ -3741,7 +3741,7 @@ "message": "Nessun login corrispondente per questo sito" }, "searchSavePasskeyNewLogin": { - "message": "Search or save passkey as new login" + "message": "Cerca o salva la passkey come nuovo login" }, "confirm": { "message": "Conferma" @@ -4208,13 +4208,13 @@ "message": "Filtri" }, "filterVault": { - "message": "Filter vault" + "message": "Filtra cassaforte" }, "filterApplied": { - "message": "One filter applied" + "message": "Un filtro applicato" }, "filterAppliedPlural": { - "message": "$COUNT$ filters applied", + "message": "$COUNT$ filtri applicati", "placeholders": { "count": { "content": "$1", @@ -4328,7 +4328,7 @@ "message": "Abilita animazioni" }, "showAnimations": { - "message": "Show animations" + "message": "Mostra animazioni" }, "addAccount": { "message": "Aggiungi account" @@ -4546,13 +4546,13 @@ "message": "Posizione elemento" }, "fileSend": { - "message": "File Send" + "message": "Send di File" }, "fileSends": { "message": "Send File" }, "textSend": { - "message": "Text Send" + "message": "Send di Testo" }, "textSends": { "message": "Send Testo" @@ -4570,7 +4570,7 @@ "message": "Mostra il numero di suggerimenti di riempimento automatico sull'icona dell'estensione" }, "showQuickCopyActions": { - "message": "Show quick copy actions on Vault" + "message": "Mostra azioni di copia rapida nella Cassaforte" }, "systemDefault": { "message": "Predefinito del sistema" @@ -4579,37 +4579,37 @@ "message": "I requisiti della policy aziendale sono stati applicati a questa impostazione" }, "sshPrivateKey": { - "message": "Private key" + "message": "Chiave privata" }, "sshPublicKey": { - "message": "Public key" + "message": "Chiave pubblica" }, "sshFingerprint": { - "message": "Fingerprint" + "message": "Impronta digitale" }, "sshKeyAlgorithm": { - "message": "Key type" + "message": "Tipo di chiave" }, "sshKeyAlgorithmED25519": { "message": "ED25519" }, "sshKeyAlgorithmRSA2048": { - "message": "RSA 2048-Bit" + "message": "RSA a 2048 bit" }, "sshKeyAlgorithmRSA3072": { - "message": "RSA 3072-Bit" + "message": "RSA a 3072 bit" }, "sshKeyAlgorithmRSA4096": { - "message": "RSA 4096-Bit" + "message": "RSA a 4096 bit" }, "retry": { - "message": "Retry" + "message": "Riprova" }, "vaultCustomTimeoutMinimum": { - "message": "Minimum custom timeout is 1 minute." + "message": "Il timeout personalizzato minimo è 1 minuto." }, "additionalContentAvailable": { - "message": "Additional content is available" + "message": "Sono disponibili ulteriori contenuti" }, "fileSavedToDevice": { "message": "File salvato sul dispositivo. Gestisci dai download del dispositivo." @@ -4642,22 +4642,22 @@ "message": "Non hai i permessi per modificare questo elemento" }, "authenticating": { - "message": "Authenticating" + "message": "Autenticazione" }, "fillGeneratedPassword": { - "message": "Fill generated password", + "message": "Riempi password generata", "description": "Heading for the password generator within the inline menu" }, "passwordRegenerated": { - "message": "Password regenerated", + "message": "Password rigenerata", "description": "Notification message for when a password has been regenerated" }, "saveLoginToBitwarden": { - "message": "Save login to Bitwarden?", + "message": "Salvare il login su Bitwarden?", "description": "Confirmation message for saving a login to Bitwarden" }, "spaceCharacterDescriptor": { - "message": "Space", + "message": "Spazio", "description": "Represents the space key in screen reader content as a readable word" }, "tildeCharacterDescriptor": { @@ -4669,157 +4669,157 @@ "description": "Represents the ` key in screen reader content as a readable word" }, "exclamationCharacterDescriptor": { - "message": "Exclamation mark", + "message": "Punto esclamativo", "description": "Represents the ! key in screen reader content as a readable word" }, "atSignCharacterDescriptor": { - "message": "At sign", + "message": "Chiocciola", "description": "Represents the @ key in screen reader content as a readable word" }, "hashSignCharacterDescriptor": { - "message": "Hash sign", + "message": "Cancelletto", "description": "Represents the # key in screen reader content as a readable word" }, "dollarSignCharacterDescriptor": { - "message": "Dollar sign", + "message": "Simbolo del dollaro", "description": "Represents the $ key in screen reader content as a readable word" }, "percentSignCharacterDescriptor": { - "message": "Percent sign", + "message": "Segno di percentuale", "description": "Represents the % key in screen reader content as a readable word" }, "caretCharacterDescriptor": { - "message": "Caret", + "message": "Accento circonflesso", "description": "Represents the ^ key in screen reader content as a readable word" }, "ampersandCharacterDescriptor": { - "message": "Ampersand", + "message": "E commerciale", "description": "Represents the & key in screen reader content as a readable word" }, "asteriskCharacterDescriptor": { - "message": "Asterisk", + "message": "Asterisco", "description": "Represents the * key in screen reader content as a readable word" }, "parenLeftCharacterDescriptor": { - "message": "Left parenthesis", + "message": "Parentesi sinistra", "description": "Represents the ( key in screen reader content as a readable word" }, "parenRightCharacterDescriptor": { - "message": "Right parenthesis", + "message": "Parentesi destra", "description": "Represents the ) key in screen reader content as a readable word" }, "hyphenCharacterDescriptor": { - "message": "Underscore", + "message": "Trattino basso", "description": "Represents the _ key in screen reader content as a readable word" }, "underscoreCharacterDescriptor": { - "message": "Hyphen", + "message": "Trattino", "description": "Represents the - key in screen reader content as a readable word" }, "plusCharacterDescriptor": { - "message": "Plus", + "message": "Più", "description": "Represents the + key in screen reader content as a readable word" }, "equalsCharacterDescriptor": { - "message": "Equals", + "message": "Uguale", "description": "Represents the = key in screen reader content as a readable word" }, "braceLeftCharacterDescriptor": { - "message": "Left brace", + "message": "Parentesi graffa aperta", "description": "Represents the { key in screen reader content as a readable word" }, "braceRightCharacterDescriptor": { - "message": "Right brace", + "message": "Parentesi graffa chiusa", "description": "Represents the } key in screen reader content as a readable word" }, "bracketLeftCharacterDescriptor": { - "message": "Left bracket", + "message": "Parentesi quadra aperta", "description": "Represents the [ key in screen reader content as a readable word" }, "bracketRightCharacterDescriptor": { - "message": "Right bracket", + "message": "Parentesi quadra chiusa", "description": "Represents the ] key in screen reader content as a readable word" }, "pipeCharacterDescriptor": { - "message": "Pipe", + "message": "Barra verticale", "description": "Represents the | key in screen reader content as a readable word" }, "backSlashCharacterDescriptor": { - "message": "Back slash", + "message": "Barra rovesciata", "description": "Represents the back slash key in screen reader content as a readable word" }, "colonCharacterDescriptor": { - "message": "Colon", + "message": "Due punti", "description": "Represents the : key in screen reader content as a readable word" }, "semicolonCharacterDescriptor": { - "message": "Semicolon", + "message": "Punto e virgola", "description": "Represents the ; key in screen reader content as a readable word" }, "doubleQuoteCharacterDescriptor": { - "message": "Double quote", + "message": "Doppi apici", "description": "Represents the double quote key in screen reader content as a readable word" }, "singleQuoteCharacterDescriptor": { - "message": "Single quote", + "message": "Apostrofo", "description": "Represents the ' key in screen reader content as a readable word" }, "lessThanCharacterDescriptor": { - "message": "Less than", + "message": "Minore", "description": "Represents the < key in screen reader content as a readable word" }, "greaterThanCharacterDescriptor": { - "message": "Greater than", + "message": "Maggiore", "description": "Represents the > key in screen reader content as a readable word" }, "commaCharacterDescriptor": { - "message": "Comma", + "message": "Virgola", "description": "Represents the , key in screen reader content as a readable word" }, "periodCharacterDescriptor": { - "message": "Period", + "message": "Punto", "description": "Represents the . key in screen reader content as a readable word" }, "questionCharacterDescriptor": { - "message": "Question mark", + "message": "Punto interrogativo", "description": "Represents the ? key in screen reader content as a readable word" }, "forwardSlashCharacterDescriptor": { - "message": "Forward slash", + "message": "Slash", "description": "Represents the / key in screen reader content as a readable word" }, "lowercaseAriaLabel": { - "message": "Lowercase" + "message": "Minuscolo" }, "uppercaseAriaLabel": { - "message": "Uppercase" + "message": "Maiuscolo" }, "generatedPassword": { - "message": "Generated password" + "message": "Password generata" }, "compactMode": { - "message": "Compact mode" + "message": "Modalità compatta" }, "beta": { "message": "Beta" }, "importantNotice": { - "message": "Important notice" + "message": "Avviso importante" }, "setupTwoStepLogin": { - "message": "Set up two-step login" + "message": "Imposta accesso in due passaggi" }, "newDeviceVerificationNoticeContentPage1": { - "message": "Bitwarden will send a code to your account email to verify logins from new devices starting in February 2025." + "message": "Bitwarden invierà un codice all'email del tuo account per verificare gli accessi da nuovi dispositivi a partire da febbraio 2025." }, "newDeviceVerificationNoticeContentPage2": { - "message": "You can set up two-step login as an alternative way to protect your account or change your email to one you can access." + "message": "Puoi impostare l'accesso in due passaggi come modo alternativo per proteggere il tuo account, o cambiare la tua e-mail in una alla quale puoi accedere." }, "remindMeLater": { - "message": "Remind me later" + "message": "Ricordamelo più tardi" }, "newDeviceVerificationNoticePageOneFormContent": { - "message": "Do you have reliable access to your email, $EMAIL$?", + "message": "Riesci ancora ad accedere a questa email, $EMAIL$?", "placeholders": { "email": { "content": "$1", @@ -4828,24 +4828,24 @@ } }, "newDeviceVerificationNoticePageOneEmailAccessNo": { - "message": "No, I do not" + "message": "No, non riesco" }, "newDeviceVerificationNoticePageOneEmailAccessYes": { - "message": "Yes, I can reliably access my email" + "message": "Sì, riesco ad accedere a questa email" }, "turnOnTwoStepLogin": { - "message": "Turn on two-step login" + "message": "Attiva accesso in due passaggi" }, "changeAcctEmail": { - "message": "Change account email" + "message": "Cambia l'email dell'account" }, "extensionWidth": { - "message": "Extension width" + "message": "Larghezza estensione" }, "wide": { - "message": "Wide" + "message": "Larga" }, "extraWide": { - "message": "Extra wide" + "message": "Molto larga" } } diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 0ffe01e7992..42dd73020ec 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -1005,7 +1005,7 @@ "message": "自動入力を簡単にするために、タブページに ID アイテムを表示します" }, "clickToAutofillOnVault": { - "message": "Click items to autofill on Vault view" + "message": "保管庫で、自動入力するアイテムをクリックしてください" }, "clearClipboard": { "message": "クリップボードの消去", @@ -4810,10 +4810,10 @@ "message": "2段階認証を設定する" }, "newDeviceVerificationNoticeContentPage1": { - "message": "Bitwarden will send a code to your account email to verify logins from new devices starting in February 2025." + "message": "Bitwarden は2025年2月以降、新しいデバイスからのログイン時にアカウントのメールアドレスに確認コードを送信します。" }, "newDeviceVerificationNoticeContentPage2": { - "message": "You can set up two-step login as an alternative way to protect your account or change your email to one you can access." + "message": "代わりに2段階認証によるログインでアカウントを保護するか、メールアドレスをあなたがアクセスできるものに変更できます。" }, "remindMeLater": { "message": "後で再通知" @@ -4831,13 +4831,13 @@ "message": "いいえ、違います。" }, "newDeviceVerificationNoticePageOneEmailAccessYes": { - "message": "Yes, I can reliably access my email" + "message": "はい、メールアドレスには私が確実にアクセスできます" }, "turnOnTwoStepLogin": { - "message": "Turn on two-step login" + "message": "2段階認証によるログインを有効にする" }, "changeAcctEmail": { - "message": "Change account email" + "message": "アカウントのメールアドレスを変更する" }, "extensionWidth": { "message": "拡張機能の幅" diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index a4c064e0394..e1236b3f86d 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -4154,7 +4154,7 @@ "message": "Ek bilgiler" }, "itemHistory": { - "message": "Öğe geçmişi" + "message": "Kayıt geçmişi" }, "lastEdited": { "message": "Son düzenlenme" diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 9af42f75e08..69c1194af47 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -428,7 +428,7 @@ "description": "Short for 'credential generator'." }, "passGenInfo": { - "message": "自动生成安全可靠唯一的登录密码。" + "message": "自动为您的登录生成强大且唯一的密码。" }, "bitWebVaultApp": { "message": "Bitwarden 网页 App" @@ -888,7 +888,7 @@ "message": "两步登录要求您从其他设备(例如安全钥匙、验证器 App、短信、电话或者电子邮件)来验证您的登录,这能使您的账户更加安全。两步登录需要在 bitwarden.com 网页版密码库中设置。现在访问此网站吗?" }, "twoStepLoginConfirmationContent": { - "message": "通过在 Bitwarden 网页 App 中设置两步登录,可以使您的账户更加安全。" + "message": "在 Bitwarden 网页 App 中设置两步登录,让您的账户更加安全。" }, "twoStepLoginConfirmationTitle": { "message": "前往网页 App 吗?" @@ -2123,7 +2123,7 @@ "message": "您仍然想要填充此登录信息吗?" }, "autofillIframeWarning": { - "message": "该表单由不同于您保存的登录的 URI 域名托管。选择「确定」以自动填充,或选择「取消」停止填充。" + "message": "该表单由与您保存的登录 URI 不同的域名托管。选择「确定」继续自动填充,或选择「取消」停止自动填充。" }, "autofillIframeWarningTip": { "message": "要防止以后出现此警告,请将此站点的 URI $HOSTNAME$ 保存到您的 Bitwarden 登录项目中。", @@ -3982,7 +3982,7 @@ "message": "自动填充建议" }, "autofillSuggestionsTip": { - "message": "保存此站点的登录项目用来自动填充" + "message": "将此站点保存为登录项目以用于自动填充" }, "yourVaultIsEmpty": { "message": "您的密码库是空的" From e75a38c438270fd386e816bb4414b7cae630c30b Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:34:47 +0000 Subject: [PATCH 04/18] Autosync the updated translations (#12713) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/az/messages.json | 8 +- apps/web/src/locales/da/messages.json | 8 +- apps/web/src/locales/de/messages.json | 14 +-- apps/web/src/locales/en_IN/messages.json | 6 +- apps/web/src/locales/ja/messages.json | 146 +++++++++++------------ apps/web/src/locales/lv/messages.json | 8 +- apps/web/src/locales/sk/messages.json | 14 +-- apps/web/src/locales/zh_CN/messages.json | 26 ++-- 8 files changed, 115 insertions(+), 115 deletions(-) diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 09785738464..b8111a0e997 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -9272,16 +9272,16 @@ "message": "Güncəlllənən vergi məlumatı" }, "billingInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Yararsız vergi kimliyi, bunun xəta olduğunu düşünürsünüzsə, dəstək komandası ilə əlaqə saxlayın." }, "billingTaxIdTypeInferenceError": { - "message": "We were unable to validate your tax ID, if you believe this is an error please contact support." + "message": "Vergi kimliyi nömrənizi doğrulaya bilmədik, bunun xəta olduğunu düşünürsünüzsə, dəstək komandası ilə əlaqə saxlayın." }, "billingPreviewInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Yararsız vergi kimliyi, bunun xəta olduğunu düşünürsünüzsə, dəstək komandası ilə əlaqə saxlayın." }, "billingPreviewInvoiceError": { - "message": "An error occurred while previewing the invoice. Please try again later." + "message": "Faktura önizləməsi zamanı bir xəta baş verdi. Lütfən daha sonra yenidən sınayın." }, "unverified": { "message": "Doğrulanmayıb" diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index b2b3b0491c3..f71e1feeb3b 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -9272,16 +9272,16 @@ "message": "Opdaterede momsoplysninger" }, "billingInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Ugyldigt moms-ID. Mener man, at dette er en fejl, kontakt venligst supporten." }, "billingTaxIdTypeInferenceError": { - "message": "We were unable to validate your tax ID, if you believe this is an error please contact support." + "message": "Moms-ID kan ikke bekræftes. Mener man, at dette er en fejl, kontakt venligst supporten." }, "billingPreviewInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Ugyldigt moms-ID. Mener man, at dette er en fejl, kontakt venligst supporten." }, "billingPreviewInvoiceError": { - "message": "An error occurred while previewing the invoice. Please try again later." + "message": "En fejl opstod under forhåndsvisning af fakturaen. Forsøg igen senere." }, "unverified": { "message": "Ubekræftet" diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 4596dd88b3a..93422471457 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -9272,16 +9272,16 @@ "message": "Steuerinformationen aktualisiert" }, "billingInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Ungültige Steuer-ID. Wenn du glaubst, dass dies ein Fehler ist, wende dich bitte an den Support." }, "billingTaxIdTypeInferenceError": { - "message": "We were unable to validate your tax ID, if you believe this is an error please contact support." + "message": "Wir konnten deine Steuer-ID nicht überprüfen. Wenn du glaubst, dass dies ein Fehler ist, kontaktiere bitte den Support." }, "billingPreviewInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Ungültige Steuer-ID. Wenn du glaubst, dass dies ein Fehler ist, wende dich bitte an den Support." }, "billingPreviewInvoiceError": { - "message": "An error occurred while previewing the invoice. Please try again later." + "message": "Bei der Vorschau der Rechnung ist ein Fehler aufgetreten. Bitte versuche es später erneut." }, "unverified": { "message": "Nicht verifiziert" @@ -10021,7 +10021,7 @@ "message": "Der Name der Organisation darf 50 Zeichen nicht überschreiten." }, "resellerRenewalWarning": { - "message": "Your subscription will renew soon. To insure uninterrupted service, contact $RESELLER$ to confirm your renewal before $RENEWAL_DATE$.", + "message": "Dein Abonnement wird bald verlängert. Um einen ununterbrochenen Betrieb zu gewährleisten, kontaktiere $RESELLER$ um deine Verlängerung vor dem $RENEWAL_DATE$ zu bestätigen.", "placeholders": { "reseller": { "content": "$1", @@ -10034,7 +10034,7 @@ } }, "resellerOpenInvoiceWarning": { - "message": "An invoice for your subscription was issued on $ISSUED_DATE$. To insure uninterrupted service, contact $RESELLER$ to confirm your renewal before $DUE_DATE$.", + "message": "Eine Rechnung für dein Abonnement wurde am $ISSUED_DATE$ ausgestellt. Um einen ununterbrochenen Betrieb zu gewährleisten, kontaktiere $RESELLER$, um deine Verlängerung vor dem $DUE_DATE$ zu bestätigen.", "placeholders": { "reseller": { "content": "$1", @@ -10051,7 +10051,7 @@ } }, "resellerPastDueWarning": { - "message": "The invoice for your subscription has not been paid. To insure uninterrupted service, contact $RESELLER$ to confirm your renewal before $GRACE_PERIOD_END$.", + "message": "Die Rechnung für dein Abonnement wurde nicht bezahlt. Um einen ununterbrochenen Betrieb zu gewährleisten, kontaktiere $RESELLER$, um deine Verlängerung vor dem $GRACE_PERIOD_END$ zu bestätigen.", "placeholders": { "reseller": { "content": "$1", diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 131b6b36383..ec67bb192c9 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -9272,13 +9272,13 @@ "message": "Updated tax information" }, "billingInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Invalid Aadhaar ID, if you believe this is an error please contact support." }, "billingTaxIdTypeInferenceError": { - "message": "We were unable to validate your tax ID, if you believe this is an error please contact support." + "message": "We were unable to validate your Aadhaar ID, if you believe this is an error please contact support." }, "billingPreviewInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Invalid Aadhaar ID, if you believe this is an error please contact support." }, "billingPreviewInvoiceError": { "message": "An error occurred while previewing the invoice. Please try again later." diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 1383ce49170..6b3b6f13b46 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -3,22 +3,22 @@ "message": "すべてのアプリ" }, "criticalApplications": { - "message": "Critical applications" + "message": "きわめて重要なアプリ" }, "accessIntelligence": { - "message": "Access Intelligence" + "message": "アクセス インテリジェンス" }, "riskInsights": { - "message": "Risk Insights" + "message": "リスク分析" }, "passwordRisk": { - "message": "Password Risk" + "message": "パスワードのリスク" }, "reviewAtRiskPasswords": { - "message": "Review at-risk passwords (weak, exposed, or reused) across applications. Select your most critical applications to prioritize security actions for your users to address at-risk passwords." + "message": "危険なパスワード(強度が低い、流出済み、再利用)を、アプリをまたいで調査します。特に重要なアプリを選択して、危険なパスワードに優先対応するようユーザーに促しましょう。" }, "dataLastUpdated": { - "message": "Data last updated: $DATE$", + "message": "データの最終更新: $DATE$", "placeholders": { "date": { "content": "$1", @@ -33,10 +33,10 @@ "message": "メンバーを削除" }, "restoreMembers": { - "message": "Restore members" + "message": "メンバーを復元" }, "cannotRestoreAccessError": { - "message": "Cannot restore organization access" + "message": "組織へのアクセスを復元できません" }, "allApplicationsWithCount": { "message": "すべてのアプリ ($COUNT$)", @@ -48,10 +48,10 @@ } }, "createNewLoginItem": { - "message": "Create new login item" + "message": "新しいログインアイテムを作成" }, "criticalApplicationsWithCount": { - "message": "Critical applications ($COUNT$)", + "message": "特に重要なアプリ ($COUNT$)", "placeholders": { "count": { "content": "$1", @@ -69,7 +69,7 @@ } }, "noAppsInOrgTitle": { - "message": "No applications found in $ORG NAME$", + "message": "$ORG NAME$ にアプリが見つかりませんでした", "placeholders": { "org name": { "content": "$1", @@ -78,22 +78,22 @@ } }, "noAppsInOrgDescription": { - "message": "As users save logins, applications appear here, showing any at-risk passwords. Mark critical apps and notify users to update passwords." + "message": "ユーザーがログイン情報を保存すると、アプリがここに表示され、リスクの高いパスワードがあれば表示されます。特に重要なアプリはマークして、パスワードを更新するようにユーザーに通知しましょう。" }, "noCriticalAppsTitle": { - "message": "You haven't marked any applications as a Critical" + "message": "重要なアプリとしてマークしたものがありません" }, "noCriticalAppsDescription": { - "message": "Select your most critical applications to discover at-risk passwords, and notify users to change those passwords." + "message": "特に重要なアプリケーションを選択して、危険なパスワードを発見し、ユーザーにパスワードを変更するよう通知しましょう。" }, "markCriticalApps": { - "message": "Mark critical apps" + "message": "重要なアプリをマークする" }, "markAppAsCritical": { - "message": "Mark app as critical" + "message": "重要なアプリとしてマーク" }, "appsMarkedAsCritical": { - "message": "Apps marked as critical" + "message": "重要なアプリとしてマークされました" }, "application": { "message": "アプリ" @@ -102,13 +102,13 @@ "message": "リスクがあるパスワード" }, "requestPasswordChange": { - "message": "Request password change" + "message": "パスワードの変更を要求する" }, "totalPasswords": { "message": "合計パスワード数" }, "searchApps": { - "message": "Search applications" + "message": "アプリを検索" }, "atRiskMembers": { "message": "リスクがあるメンバー" @@ -469,7 +469,7 @@ "message": "パスワードの自動生成" }, "generatePassphrase": { - "message": "Generate passphrase" + "message": "パスフレーズを生成" }, "checkPassword": { "message": "パスワードが漏洩していないか確認する" @@ -572,7 +572,7 @@ "message": "セキュアメモ" }, "typeSshKey": { - "message": "SSH key" + "message": "SSH 鍵" }, "typeLoginPlural": { "message": "ログイン" @@ -733,11 +733,11 @@ "description": "Copy password to clipboard" }, "copyPassphrase": { - "message": "Copy passphrase", + "message": "パスフレーズをコピー", "description": "Copy passphrase to clipboard" }, "passwordCopied": { - "message": "Password copied" + "message": "パスワードをコピーしました" }, "copyUsername": { "message": "ユーザー名のコピー", @@ -994,7 +994,7 @@ "message": "Bitwarden アプリで「デバイスでログイン」の設定をする必要があります。別のオプションが必要ですか?" }, "needAnotherOptionV1": { - "message": "Need another option?" + "message": "別の選択肢が必要ですか?" }, "loginWithMasterPassword": { "message": "マスターパスワードでログイン" @@ -1009,13 +1009,13 @@ "message": "別のログイン方法を使用する" }, "logInWithPasskey": { - "message": "Log in with passkey" + "message": "パスキーでログイン" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "シングルサインオンを使用する" }, "welcomeBack": { - "message": "Welcome back" + "message": "ようこそ" }, "invalidPasskeyPleaseTryAgain": { "message": "無効なパスキーです。もう一度やり直してください。" @@ -1099,7 +1099,7 @@ "message": "アカウントの作成" }, "newToBitwarden": { - "message": "New to Bitwarden?" + "message": "Bitwarden は初めてですか?" }, "setAStrongPassword": { "message": "強力なパスワードを設定する" @@ -1117,13 +1117,13 @@ "message": "ログイン" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Bitwarden にログイン" }, "authenticationTimeout": { - "message": "Authentication timeout" + "message": "認証のタイムアウト" }, "authenticationSessionTimedOut": { - "message": "The authentication session timed out. Please restart the login process." + "message": "認証セッションの有効期限が切れました。ログイン操作を最初からやり直してください。" }, "verifyIdentity": { "message": "本人確認" @@ -1294,7 +1294,7 @@ "message": "このコレクション内のアイテムをすべて表示する権限がありません。" }, "youDoNotHavePermissions": { - "message": "You do not have permissions to this collection" + "message": "このコレクションの利用権限がありません" }, "noCollectionsInList": { "message": "表示するコレクションがありません" @@ -1321,10 +1321,10 @@ "message": "デバイスに通知を送信しました。" }, "aNotificationWasSentToYourDevice": { - "message": "A notification was sent to your device" + "message": "お使いのデバイスに通知が送信されました" }, "makeSureYourAccountIsUnlockedAndTheFingerprintEtc": { - "message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device" + "message": "アカウントがロック解除されていることと、フィンガープリントフレーズが他の端末と一致していることを確認してください" }, "versionNumber": { "message": "バージョン $VERSION_NUMBER$", @@ -1658,25 +1658,25 @@ "message": "パスワードの履歴" }, "generatorHistory": { - "message": "Generator history" + "message": "生成履歴" }, "clearGeneratorHistoryTitle": { - "message": "Clear generator history" + "message": "生成履歴を消去" }, "cleargGeneratorHistoryDescription": { - "message": "If you continue, all entries will be permanently deleted from generator's history. Are you sure you want to continue?" + "message": "続行すると、すべてのエントリは生成履歴から完全に削除されます。続行してもよろしいですか?" }, "noPasswordsInList": { "message": "表示するパスワードがありません" }, "clearHistory": { - "message": "Clear history" + "message": "履歴を消去" }, "nothingToShow": { - "message": "Nothing to show" + "message": "表示するものがありません" }, "nothingGeneratedRecently": { - "message": "You haven't generated anything recently" + "message": "最近生成したものはありません" }, "clear": { "message": "消去する", @@ -1786,7 +1786,7 @@ "message": "これらの操作はやり直せないため注意してください!" }, "dangerZoneDescSingular": { - "message": "Careful, this action is not reversible!" + "message": "この操作は元に戻せないため注意してください!" }, "deauthorizeSessions": { "message": "セッションの承認を取り消す" @@ -1801,7 +1801,7 @@ "message": "全てのセッションを無効化" }, "accountIsOwnedMessage": { - "message": "This account is owned by $ORGANIZATIONNAME$", + "message": "このアカウントは $ORGANIZATIONNAME$ が所有しています", "placeholders": { "organizationName": { "content": "$1", @@ -3430,7 +3430,7 @@ } }, "viewAllLogInOptions": { - "message": "View all log in options" + "message": "すべてのログインオプションを表示" }, "viewAllLoginOptions": { "message": "すべてのログインオプションを表示" @@ -3883,13 +3883,13 @@ "message": "ブラウザを更新" }, "generatingRiskInsights": { - "message": "Generating your risk insights..." + "message": "リスク分析を生成しています..." }, "updateBrowserDesc": { "message": "サポートされていないブラウザを使用しています。ウェブ保管庫が正しく動作しないかもしれません。" }, "freeTrialEndPromptCount": { - "message": "Your free trial ends in $COUNT$ days.", + "message": "無料体験はあと $COUNT$ 日で終了します。", "placeholders": { "count": { "content": "$1", @@ -3898,7 +3898,7 @@ } }, "freeTrialEndPromptMultipleDays": { - "message": "$ORGANIZATION$, your free trial ends in $COUNT$ days.", + "message": "$ORGANIZATION$ 様、無料体験はあと $COUNT$ 日で終了します。", "placeholders": { "count": { "content": "$2", @@ -3911,7 +3911,7 @@ } }, "freeTrialEndPromptTomorrow": { - "message": "$ORGANIZATION$, your free trial ends tomorrow.", + "message": "$ORGANIZATION$ 様、無料体験は明日で終了します。", "placeholders": { "organization": { "content": "$1", @@ -3920,10 +3920,10 @@ } }, "freeTrialEndPromptTomorrowNoOrgName": { - "message": "Your free trial ends tomorrow." + "message": "無料体験は明日終了します。" }, "freeTrialEndPromptToday": { - "message": "$ORGANIZATION$, your free trial ends today.", + "message": "$ORGANIZATION$ 様、無料体験は本日終了します。", "placeholders": { "organization": { "content": "$1", @@ -3932,16 +3932,16 @@ } }, "freeTrialEndingTodayWithoutOrgName": { - "message": "Your free trial ends today." + "message": "無料体験は本日で終了します。" }, "clickHereToAddPaymentMethod": { - "message": "Click here to add a payment method." + "message": "支払い方法を追加するにはここをクリックしてください。" }, "joinOrganization": { "message": "組織に参加" }, "joinOrganizationName": { - "message": "Join $ORGANIZATIONNAME$", + "message": "$ORGANIZATIONNAME$ に参加", "placeholders": { "organizationName": { "content": "$1", @@ -4492,7 +4492,7 @@ "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "You will be notified once the request is approved" + "message": "リクエストが承認されると通知されます" }, "free": { "message": "無料", @@ -4725,10 +4725,10 @@ "message": "組織のシングルサインオンポータルを使用してログインします。開始するには組織の識別子を入力してください。" }, "singleSignOnEnterOrgIdentifier": { - "message": "Enter your organization's SSO identifier to begin" + "message": "組織の SSO ID を入力して開始します" }, "singleSignOnEnterOrgIdentifierText": { - "message": "To log in with your SSO provider, enter your organization's SSO identifier to begin. You may need to enter this SSO identifier when you log in from a new device." + "message": "SSO プロバイダーでログインするには、組織の SSO ID を入力して開始します。新しいデバイスからログインする際に、この SSO ID を入力する必要がある場合があります。" }, "enterpriseSingleSignOn": { "message": "組織のシングルサインオン" @@ -4798,7 +4798,7 @@ "message": "ユーザーが他の組織に参加できないように制限します。" }, "singleOrgPolicyDesc": { - "message": "Restrict members from joining other organizations. This policy is required for organizations that have enabled domain verification." + "message": "メンバーに対し、他の組織への参加を制限します。ドメイン認証を有効にしている組織では、このポリシーは必須となります。" }, "singleOrgBlockCreateMessage": { "message": "現在の組織には、複数の組織に参加することを許可していないポリシーがあります。 組織の管理者に連絡するか、別の Bitwarden アカウントから登録してください。" @@ -4807,7 +4807,7 @@ "message": "オーナーまたは管理者でなく、すでに他の組織のメンバーであるメンバーは組織から削除されます。" }, "singleOrgPolicyMemberWarning": { - "message": "Non-compliant members will be placed in revoked status until they leave all other organizations. Administrators are exempt and can restore members once compliance is met." + "message": "ポリシーに準拠していないメンバーは、他のすべての組織から退出するまで失効状態になります。これは管理者には適用されず、管理者はコンプライアンスが満たされたメンバーを復元できます。" }, "requireSso": { "message": "シングルサインオン認証" @@ -5635,10 +5635,10 @@ "message": "除外します。このアクションには適用されません。" }, "nonCompliantMembersTitle": { - "message": "Non-compliant members" + "message": "非準拠のメンバー" }, "nonCompliantMembersError": { - "message": "Members that are non-compliant with the Single organization or Two-step login policy cannot be restored until they adhere to the policy requirements" + "message": "単一組織ポリシーまたは2段階ログインポリシーに準拠していないメンバーは、ポリシー要件を遵守するまで復元できません。" }, "fingerprint": { "message": "指紋" @@ -6437,7 +6437,7 @@ "message": "エンティティ ID が URL でない場合は必須です。" }, "offerNoLongerValid": { - "message": "This offer is no longer valid. Contact your organization administrators for more information." + "message": "このオファーは無効になりました。詳しくは組織の管理者にお問い合わせください。" }, "openIdOptionalCustomizations": { "message": "オプションのカスタマイズ" @@ -6529,10 +6529,10 @@ "message": "ユーザー名を生成" }, "generateEmail": { - "message": "Generate email" + "message": "メールアドレスを生成" }, "spinboxBoundariesHint": { - "message": "Value must be between $MIN$ and $MAX$.", + "message": "値は $MIN$ から $MAX$ の間でなければなりません。", "description": "Explains spin box minimum and maximum values to the user", "placeholders": { "min": { @@ -6546,7 +6546,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Use $RECOMMENDED$ characters or more to generate a strong password.", + "message": " 強力なパスワードを生成するには、 $RECOMMENDED$ 文字以上を使用してください。", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -6556,7 +6556,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Use $RECOMMENDED$ words or more to generate a strong passphrase.", + "message": " 強力なパスフレーズを生成するには、 $RECOMMENDED$ 単語以上を使用してください。", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -6671,11 +6671,11 @@ "message": "外部転送サービスを使用してメールエイリアスを生成します。" }, "forwarderDomainName": { - "message": "Email domain", + "message": "メールアドレスのドメイン", "description": "Labels the domain name email forwarder service option" }, "forwarderDomainNameHint": { - "message": "Choose a domain that is supported by the selected service", + "message": "選択したサービスでサポートされているドメインを選択してください", "description": "Guidance provided for email forwarding services that support multiple email domains." }, "forwarderError": { @@ -8101,16 +8101,16 @@ "message": "ログイン開始" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Remember this device to make future logins seamless" + "message": "このデバイスを記憶して今後のログインをシームレスにする" }, "deviceApprovalRequired": { "message": "デバイスの承認が必要です。以下から承認オプションを選択してください:" }, "deviceApprovalRequiredV2": { - "message": "Device approval required" + "message": "デバイスの承認が必要です" }, "selectAnApprovalOptionBelow": { - "message": "Select an approval option below" + "message": "以下の承認オプションを選択してください" }, "rememberThisDevice": { "message": "このデバイスを記憶する" @@ -8342,7 +8342,7 @@ "message": "ユーザーのメールアドレスがありません" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "アクティブなユーザーメールアドレスが見つかりません。ログアウトします。" }, "deviceTrusted": { "message": "信頼されたデバイス" @@ -8440,10 +8440,10 @@ "message": "組織のコレクションに関する挙動を管理します" }, "limitCollectionCreationDesc": { - "message": "Limit collection creation to owners and admins" + "message": "コレクションの作成を所有者と管理者のみに制限" }, "limitCollectionDeletionDesc": { - "message": "Limit collection deletion to owners and admins" + "message": "コレクションの削除を所有者と管理者のみに制限" }, "allowAdminAccessToAllCollectionItemsDesc": { "message": "所有者と管理者はすべてのコレクションとアイテムを管理できます" @@ -8491,7 +8491,7 @@ "message": "サーバー URL" }, "selfHostBaseUrl": { - "message": "Self-host server URL", + "message": "自己ホスト型サーバー URL", "description": "Label for field requesting a self-hosted integration service URL" }, "aliasDomain": { diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 6546b248914..0b830e6dc9a 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -9272,16 +9272,16 @@ "message": "Atjaunināta nodokļu informācija" }, "billingInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Nederīgs nodokļu identifikators. Ja ir pārliecība, ka tā ir kļūda, lūgums sazināties ar atbalstu." }, "billingTaxIdTypeInferenceError": { - "message": "We were unable to validate your tax ID, if you believe this is an error please contact support." + "message": "Mēs nevarējām pārbaudīt nodokļu identifikatoru. Ja ir pārliecība, ka tā ir kļūda, lūgums sazināties ar atbalstu." }, "billingPreviewInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Nederīgs nodokļu identifikators. Ja ir pārliecība, ka tā ir kļūda, lūgums sazināties ar atbalstu." }, "billingPreviewInvoiceError": { - "message": "An error occurred while previewing the invoice. Please try again later." + "message": "Rēķina priekšskatīšanas laikā atgadījās kļūda. Lūgums vēlāk mēģināt vēlreiz." }, "unverified": { "message": "Neapliecināts" diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 4c47afaa63d..dbffa25048c 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -9272,16 +9272,16 @@ "message": "Aktualizované daňové informácie" }, "billingInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Neplatne číslo pre DPH, ak myslíte že ide o chybu, kontaktujte prosím zákaznícku podporu." }, "billingTaxIdTypeInferenceError": { - "message": "We were unable to validate your tax ID, if you believe this is an error please contact support." + "message": "Nepodarilo sa nám overiť vaše číslo pre DPH, ak myslíte že ide o chybu, kontaktujte prosím zákaznícku podporu." }, "billingPreviewInvalidTaxIdError": { - "message": "Invalid tax ID, if you believe this is an error please contact support." + "message": "Neplatne číslo pre DPH, ak myslíte že ide o chybu, kontaktujte prosím zákaznícku podporu." }, "billingPreviewInvoiceError": { - "message": "An error occurred while previewing the invoice. Please try again later." + "message": "Pri vytváraní náhľadu faktúry nastala chyba. Prosím skúste to neskor." }, "unverified": { "message": "Neoverený" @@ -10021,7 +10021,7 @@ "message": "Meno organizácie nemôže mať viac ako 50 znakov." }, "resellerRenewalWarning": { - "message": "Your subscription will renew soon. To insure uninterrupted service, contact $RESELLER$ to confirm your renewal before $RENEWAL_DATE$.", + "message": "Vaše predplatné sa čoskoro obnoví. Aby ste si zabezpečili nepretržitú prevádzku, kontaktujte $RESELLER$ a potvrďte obnovenie pred $RENEWAL_DATE$.", "placeholders": { "reseller": { "content": "$1", @@ -10034,7 +10034,7 @@ } }, "resellerOpenInvoiceWarning": { - "message": "An invoice for your subscription was issued on $ISSUED_DATE$. To insure uninterrupted service, contact $RESELLER$ to confirm your renewal before $DUE_DATE$.", + "message": "Faktúra za vaše predplatné bola vystavená dňa $ISSUED_DATE$. Aby ste si zabezpečili nepretržitú prevádzku, kontaktujte $RESELLER$ a potvrďte obnovenie predplatného pred $DUE_DATE$.", "placeholders": { "reseller": { "content": "$1", @@ -10051,7 +10051,7 @@ } }, "resellerPastDueWarning": { - "message": "The invoice for your subscription has not been paid. To insure uninterrupted service, contact $RESELLER$ to confirm your renewal before $GRACE_PERIOD_END$.", + "message": "Faktúra za vaše predplatné nebola uhradená. Aby ste si zabezpečili nepretržitú prevádzku, kontaktujte $RESELLER$ a potvrďte obnovenie pred $GRACE_PERIOD_END$.", "placeholders": { "reseller": { "content": "$1", diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index a7d73801372..f293adcf62a 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -1006,7 +1006,7 @@ "message": "保持此窗口打开然后按照浏览器的提示操作。" }, "useADifferentLogInMethod": { - "message": "使用不同的登录方式" + "message": "使用其他登录方式" }, "logInWithPasskey": { "message": "使用通行密钥登录" @@ -1997,13 +1997,13 @@ "message": "域名规则" }, "domainRulesDesc": { - "message": "如果您在多个不同网站之间使用同一个登陆信息,您可以把这些网站标记为「通用」。Bitwarden 会为您设置「全局」域名。" + "message": "如果您在多个不同网站域名中使用同一个登录信息,您可以把这些网站标记为「等效」。「全局」域名是由 Bitwarden 为您预先创建的域名。" }, "globalEqDomains": { - "message": "全局通用域名" + "message": "全局等效域名" }, "customEqDomains": { - "message": "自定义通用域名" + "message": "自定义等效域名" }, "exclude": { "message": "排除" @@ -2039,7 +2039,7 @@ "message": "强制两步登录" }, "twoStepLoginDesc": { - "message": "在登录时要求使用额外的步骤来保护您的账户。" + "message": "在登录时要求执行额外的步骤来保护您的账户。" }, "twoStepLoginTeamsDesc": { "message": "为您的组织启用两步登录。" @@ -2055,7 +2055,7 @@ "message": "要实施 Duo 方式的两步登录,请使用下面的选项。" }, "twoStepLoginOrganizationSsoDesc": { - "message": "如果您已设置或计划设置 SSO,两步登录可能已经通过您的身份提供程序实施了。" + "message": "如果您已设置或计划设置 SSO,两步登录可能已经通过您的身份提供程序强制实施了。" }, "twoStepLoginRecoveryWarning": { "message": "启用两步登录可能会将您永久锁定在 Bitwarden 账户之外。如果您无法使用常规的两步登录提供程序(例如您丢失了设备),则可以使用恢复代码访问您的账户。如果您失去对您账户的访问,Bitwarden 支持也无法帮助您。我们建议您记下或打印恢复代码,并将其妥善保管。" @@ -3294,7 +3294,7 @@ "message": "管理员" }, "adminDesc": { - "message": "管理组织访问权限,所有集合,成员,报告以及安全设置" + "message": "管理组织的访问权限,所有集合、成员、报告,以及安全设置" }, "user": { "message": "用户" @@ -4304,7 +4304,7 @@ "message": "升级组织" }, "upgradeOrganizationDesc": { - "message": "本功能对免费组织不可用。切换到付费计划以解锁更多功能。" + "message": "此功能不适用于免费组织。请切换到付费计划以解锁更多功能。" }, "createOrganizationStep1": { "message": "创建组织:第一步" @@ -4514,7 +4514,7 @@ "message": "您的 API 密钥可用于在 Bitwarden CLI 中进行身份验证。" }, "userApiKeyWarning": { - "message": "您的 API 密钥是另一套等效的身份验证机制。请严格保密。" + "message": "您的 API 密钥是一种替代身份验证机制。请严格保密。" }, "oauth2ClientCredentials": { "message": "OAuth 2.0 客户端凭据", @@ -5998,16 +5998,16 @@ "message": "最小入站签名算法" }, "spWantAssertionsSigned": { - "message": "希望断言被签名" + "message": "要求使用签名的断言" }, "spValidateCertificates": { "message": "验证证书" }, "spUniqueEntityId": { - "message": "设置一个唯一的 SP 实体 ID" + "message": "设置专属的 SP 实体 ID" }, "spUniqueEntityIdDesc": { - "message": "生成您的组织独有的标识符" + "message": "为您的组织生成专属的标识符" }, "idpEntityId": { "message": "实体 ID" @@ -8077,7 +8077,7 @@ "message": "忽略" }, "notAvailableForFreeOrganization": { - "message": "免费组织不能使用此功能。请联系您的组织所有者寻求升级。" + "message": "此功能不适用于免费组织。请联系您的组织所有者寻求升级。" }, "smProjectSecretsNoItemsNoAccess": { "message": "请联系您的组织的管理员来管理此工程的机密。", From 828a7fe3396bad3ec04b013816d818d4e30da9c9 Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Mon, 6 Jan 2025 08:42:38 -0800 Subject: [PATCH 05/18] [PM-15557] Log the Cipher_ClientViewed event when opening the VaultItemDialog (#12669) --- .../vault-item-dialog/vault-item-dialog.component.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index 02dc5ef48bb..a9ff49c5791 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -9,9 +9,11 @@ import { map } from "rxjs/operators"; import { CollectionView } from "@bitwarden/admin-console/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; +import { EventType } from "@bitwarden/common/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -237,6 +239,7 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { private premiumUpgradeService: PremiumUpgradePromptService, private cipherAuthorizationService: CipherAuthorizationService, private apiService: ApiService, + private eventCollectionService: EventCollectionService, ) { this.updateTitle(); } @@ -257,6 +260,13 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { [this.params.activeCollectionId], this.params.isAdminConsoleAction, ); + + await this.eventCollectionService.collect( + EventType.Cipher_ClientViewed, + this.cipher.id, + false, + this.cipher.organizationId, + ); } this.performingInitialLoad = false; From ec21e8db592d929f55dae2579dc48825d44b3028 Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:44:36 +0100 Subject: [PATCH 06/18] Add missing credit card number pipe (#12508) Co-authored-by: Daniel James Smith --- .../cipher-view/card-details/card-details-view.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/vault/src/cipher-view/card-details/card-details-view.component.html b/libs/vault/src/cipher-view/card-details/card-details-view.component.html index d805408b385..fff771b6465 100644 --- a/libs/vault/src/cipher-view/card-details/card-details-view.component.html +++ b/libs/vault/src/cipher-view/card-details/card-details-view.component.html @@ -22,7 +22,7 @@

{{ setSectionTitle }}

readonly bitInput type="password" - [value]="card.number" + [value]="card.number | creditCardNumber: cipher.card.brand" aria-readonly="true" data-testid="cardholder-number" class="tw-font-mono" From c349ea95c6a2608bee3296a60805a98e3d24348f Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Mon, 6 Jan 2025 18:11:31 +0100 Subject: [PATCH 07/18] Remove v1 popout component (#12518) Co-authored-by: Daniel James Smith --- .../platform/popup/components/pop-out.component.html | 7 +------ .../src/platform/popup/components/pop-out.component.ts | 10 +--------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/apps/browser/src/platform/popup/components/pop-out.component.html b/apps/browser/src/platform/popup/components/pop-out.component.html index c3f1f8ca150..3097f6e30d3 100644 --- a/apps/browser/src/platform/popup/components/pop-out.component.html +++ b/apps/browser/src/platform/popup/components/pop-out.component.html @@ -1,9 +1,4 @@ - - - - + + + + + + + diff --git a/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts b/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts new file mode 100644 index 00000000000..abf74371912 --- /dev/null +++ b/apps/desktop/src/vault/app/vault/credential-generator-dialog.component.ts @@ -0,0 +1,69 @@ +import { DIALOG_DATA } from "@angular/cdk/dialog"; +import { CommonModule } from "@angular/common"; +import { Component, Inject } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { + ButtonModule, + DialogModule, + DialogService, + ItemModule, + LinkModule, +} from "@bitwarden/components"; +import { + CredentialGeneratorHistoryDialogComponent, + GeneratorModule, +} from "@bitwarden/generator-components"; +import { CipherFormGeneratorComponent } from "@bitwarden/vault"; + +type CredentialGeneratorParams = { + onCredentialGenerated: (value?: string) => void; + type: "password" | "username"; +}; + +@Component({ + standalone: true, + selector: "credential-generator-dialog", + templateUrl: "credential-generator-dialog.component.html", + imports: [ + CipherFormGeneratorComponent, + CommonModule, + DialogModule, + ButtonModule, + JslibModule, + GeneratorModule, + ItemModule, + LinkModule, + ], +}) +export class CredentialGeneratorDialogComponent { + credentialValue?: string; + + constructor( + @Inject(DIALOG_DATA) protected data: CredentialGeneratorParams, + private dialogService: DialogService, + ) {} + + applyCredentials = () => { + this.data.onCredentialGenerated(this.credentialValue); + }; + + clearCredentials = () => { + this.data.onCredentialGenerated(); + }; + + onCredentialGenerated = (value: string) => { + this.credentialValue = value; + }; + + openHistoryDialog = () => { + // open history dialog + this.dialogService.open(CredentialGeneratorHistoryDialogComponent); + }; + + static open = (dialogService: DialogService, data: CredentialGeneratorParams) => { + dialogService.open(CredentialGeneratorDialogComponent, { + data, + }); + }; +} diff --git a/apps/desktop/src/vault/app/vault/vault.component.ts b/apps/desktop/src/vault/app/vault/vault.component.ts index 67b69be7d1b..f375b303024 100644 --- a/apps/desktop/src/vault/app/vault/vault.component.ts +++ b/apps/desktop/src/vault/app/vault/vault.component.ts @@ -20,7 +20,9 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EventType } from "@bitwarden/common/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -40,6 +42,7 @@ import { invokeMenu, RendererMenuItem } from "../../../utils"; import { AddEditComponent } from "./add-edit.component"; import { AttachmentsComponent } from "./attachments.component"; import { CollectionsComponent } from "./collections.component"; +import { CredentialGeneratorDialogComponent } from "./credential-generator-dialog.component"; import { FolderAddEditComponent } from "./folder-add-edit.component"; import { PasswordHistoryComponent } from "./password-history.component"; import { ShareComponent } from "./share.component"; @@ -107,6 +110,7 @@ export class VaultComponent implements OnInit, OnDestroy { private apiService: ApiService, private dialogService: DialogService, private billingAccountProfileStateService: BillingAccountProfileStateService, + private configService: ConfigService, ) {} async ngOnInit() { @@ -622,11 +626,29 @@ export class VaultComponent implements OnInit, OnDestroy { } async openGenerator(comingFromAddEdit: boolean, passwordType = true) { - // FIXME: Will need to be extended to use the cipher-form-generator component introduced with https://github.com/bitwarden/clients/pull/11350 - if (this.modal != null) { - this.modal.close(); + const isGeneratorSwapEnabled = await this.configService.getFeatureFlag( + FeatureFlag.GeneratorToolsModernization, + ); + + if (isGeneratorSwapEnabled) { + CredentialGeneratorDialogComponent.open(this.dialogService, { + onCredentialGenerated: (value?: string) => { + if (this.addEditComponent != null) { + this.addEditComponent.markPasswordAsDirty(); + if (passwordType) { + this.addEditComponent.cipher.login.password = value ?? ""; + } else { + this.addEditComponent.cipher.login.username = value ?? ""; + } + } + }, + type: passwordType ? "password" : "username", + }); + return; } + // TODO: Legacy code below, remove once the new generator is fully implemented + // https://bitwarden.atlassian.net/browse/PM-7121 const cipher = this.addEditComponent?.cipher; const loginType = cipher != null && cipher.type === CipherType.Login && cipher.login != null; From ce07e408eaad52194ed53235a942cc24579de519 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:46:59 -0800 Subject: [PATCH 09/18] [PM-13028] - add fixed width to vault list icon (#12644) * add fixed width to vault list icon * justify start * don't display totp capture when in popout * Revert "don't display totp capture when in popout" This reverts commit f50b0a6caf4cb23d2af8521f51b9c772336782ac. --- .../vault-list-items-container.component.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html b/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html index 72ac590c779..b5d92a386b3 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-list-items-container/vault-list-items-container.component.html @@ -34,7 +34,9 @@

" class="{{ itemHeightClass }}" > - +
+ +
{{ cipher.name }} Date: Mon, 6 Jan 2025 13:49:33 -0500 Subject: [PATCH 10/18] [CL-506] Upgrade to Angular 18 (#12218) --- apps/web/src/app/app.module.ts | 4 +- apps/web/src/app/shared/shared.module.ts | 6 +- apps/web/webpack.config.js | 2 +- .../bit-web/src/app/app.module.ts | 4 +- package-lock.json | 4132 +++++++++-------- package.json | 40 +- 6 files changed, 2192 insertions(+), 1996 deletions(-) diff --git a/apps/web/src/app/app.module.ts b/apps/web/src/app/app.module.ts index 2a67232e3db..22fd745eab8 100644 --- a/apps/web/src/app/app.module.ts +++ b/apps/web/src/app/app.module.ts @@ -3,7 +3,7 @@ import { LayoutModule } from "@angular/cdk/layout"; import { NgModule } from "@angular/core"; import { FormsModule } from "@angular/forms"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; -import { InfiniteScrollModule } from "ngx-infinite-scroll"; +import { InfiniteScrollDirective } from "ngx-infinite-scroll"; import { AppComponent } from "./app.component"; import { CoreModule } from "./core"; @@ -23,7 +23,7 @@ import { WildcardRoutingModule } from "./wildcard-routing.module"; BrowserAnimationsModule, FormsModule, CoreModule, - InfiniteScrollModule, + InfiniteScrollDirective, DragDropModule, LayoutModule, OssRoutingModule, diff --git a/apps/web/src/app/shared/shared.module.ts b/apps/web/src/app/shared/shared.module.ts index 1b04583a395..8f44d8a4bf5 100644 --- a/apps/web/src/app/shared/shared.module.ts +++ b/apps/web/src/app/shared/shared.module.ts @@ -3,7 +3,7 @@ import { CommonModule, DatePipe } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; -import { InfiniteScrollModule } from "ngx-infinite-scroll"; +import { InfiniteScrollDirective } from "ngx-infinite-scroll"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { @@ -49,7 +49,7 @@ import "./locales"; DragDropModule, FormsModule, ReactiveFormsModule, - InfiniteScrollModule, + InfiniteScrollDirective, RouterModule, JslibModule, @@ -86,7 +86,7 @@ import "./locales"; DragDropModule, FormsModule, ReactiveFormsModule, - InfiniteScrollModule, + InfiniteScrollDirective, RouterModule, JslibModule, diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js index df325015aad..9373308c112 100644 --- a/apps/web/webpack.config.js +++ b/apps/web/webpack.config.js @@ -256,7 +256,7 @@ const devServer = 'sha256-JVRXyYPueLWdwGwY9m/7u4QlZ1xeQdqUj2t8OVIzZE4=' 'sha256-or0p3LaHetJ4FRq+flVORVFFNsOjQGWrDvX8Jf7ACWg=' 'sha256-jvLh2uL2/Pq/gpvNJMaEL4C+TNhBeGadLIUyPcVRZvY=' - 'sha256-Oca9ZYU1dwNscIhdNV7tFBsr4oqagBhZx9/p4w8GOcg=' + 'sha256-VZTcMoTEw3nbAHejvqlyyRm1Mdx+DVNgyKANjpWw0qg=' ;img-src 'self' data: diff --git a/bitwarden_license/bit-web/src/app/app.module.ts b/bitwarden_license/bit-web/src/app/app.module.ts index fd1a3b0b84c..3a78ae0ed01 100644 --- a/bitwarden_license/bit-web/src/app/app.module.ts +++ b/bitwarden_license/bit-web/src/app/app.module.ts @@ -4,7 +4,7 @@ import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { RouterModule } from "@angular/router"; -import { InfiniteScrollModule } from "ngx-infinite-scroll"; +import { InfiniteScrollDirective } from "ngx-infinite-scroll"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { CoreModule } from "@bitwarden/web-vault/app/core"; @@ -37,7 +37,7 @@ import { AccessIntelligenceModule } from "./tools/access-intelligence/access-int FormsModule, ReactiveFormsModule, CoreModule, - InfiniteScrollModule, + InfiniteScrollDirective, DragDropModule, AppRoutingModule, OssRoutingModule, diff --git a/package-lock.json b/package-lock.json index ba7953d0faf..c60d71881a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,22 +15,22 @@ "libs/*" ], "dependencies": { - "@angular/animations": "17.3.12", - "@angular/cdk": "17.3.10", - "@angular/common": "17.3.12", - "@angular/compiler": "17.3.12", - "@angular/core": "17.3.12", - "@angular/forms": "17.3.12", - "@angular/platform-browser": "17.3.12", - "@angular/platform-browser-dynamic": "17.3.12", - "@angular/router": "17.3.12", + "@angular/animations": "18.2.13", + "@angular/cdk": "18.2.14", + "@angular/common": "18.2.13", + "@angular/compiler": "18.2.13", + "@angular/core": "18.2.13", + "@angular/forms": "18.2.13", + "@angular/platform-browser": "18.2.13", + "@angular/platform-browser-dynamic": "18.2.13", + "@angular/router": "18.2.13", "@bitwarden/sdk-internal": "0.2.0-main.38", "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "13.1.0", "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", - "@ng-select/ng-select": "12.0.7", + "@ng-select/ng-select": "13.9.1", "argon2": "0.41.1", "argon2-browser": "1.18.0", "big-integer": "1.6.52", @@ -53,7 +53,7 @@ "lowdb": "1.0.0", "lunr": "2.3.9", "multer": "1.4.5-lts.1", - "ngx-infinite-scroll": "17.0.1", + "ngx-infinite-scroll": "18.0.0", "ngx-toastr": "19.0.0", "node-fetch": "2.6.12", "node-forge": "1.3.1", @@ -74,20 +74,20 @@ "zxcvbn": "4.4.2" }, "devDependencies": { - "@angular-devkit/build-angular": "17.3.11", - "@angular-eslint/eslint-plugin": "17.5.3", - "@angular-eslint/eslint-plugin-template": "17.5.3", - "@angular-eslint/schematics": "17.5.3", - "@angular-eslint/template-parser": "17.5.3", - "@angular/cli": "17.3.11", - "@angular/compiler-cli": "17.3.12", - "@angular/elements": "17.3.12", + "@angular-devkit/build-angular": "18.2.12", + "@angular-eslint/eslint-plugin": "18.4.3", + "@angular-eslint/eslint-plugin-template": "18.4.3", + "@angular-eslint/schematics": "18.4.3", + "@angular-eslint/template-parser": "18.4.3", + "@angular/cli": "18.2.12", + "@angular/compiler-cli": "18.2.13", + "@angular/elements": "18.2.13", "@babel/core": "7.24.9", "@babel/preset-env": "7.24.8", "@compodoc/compodoc": "1.1.26", "@electron/notarize": "2.5.0", "@electron/rebuild": "3.7.1", - "@ngtools/webpack": "17.3.11", + "@ngtools/webpack": "18.2.12", "@storybook/addon-a11y": "8.4.7", "@storybook/addon-actions": "8.4.7", "@storybook/addon-designs": "8.0.4", @@ -369,14 +369,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.11.tgz", - "integrity": "sha512-p+XIc/j51aI83ExNdeZwvkm1F4wkuKMGUUoj0MVUUi5E6NoiMlXYm6uU8+HbRvPBzGy5+3KOiGp3Fks0UmDSAA==", + "version": "0.1802.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.12.tgz", + "integrity": "sha512-bepVb2/GtJppYKaeW8yTGE6egmoWZ7zagFDsmBdbF+BYp+HmeoPsclARcdryBPVq68zedyTRdvhWSUTbw1AYuw==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { - "@angular-devkit/core": "18.2.11", + "@angular-devkit/core": "18.2.12", "rxjs": "7.8.1" }, "engines": { @@ -386,98 +384,96 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.3.11.tgz", - "integrity": "sha512-lHX5V2dSts328yvo/9E2u9QMGcvJhbEKKDDp9dBecwvIG9s+4lTOJgi9DPUE7W+AtmPcmbbhwC2JRQ/SLQhAoA==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.12.tgz", + "integrity": "sha512-quVUi7eqTq9OHumQFNl9Y8t2opm8miu4rlYnuF6rbujmmBDvdUvR6trFChueRczl2p5HWqTOr6NPoDGQm8AyNw==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1703.11", - "@angular-devkit/build-webpack": "0.1703.11", - "@angular-devkit/core": "17.3.11", - "@babel/core": "7.24.0", - "@babel/generator": "7.23.6", - "@babel/helper-annotate-as-pure": "7.22.5", - "@babel/helper-split-export-declaration": "7.22.6", - "@babel/plugin-transform-async-generator-functions": "7.23.9", - "@babel/plugin-transform-async-to-generator": "7.23.3", - "@babel/plugin-transform-runtime": "7.24.0", - "@babel/preset-env": "7.24.0", - "@babel/runtime": "7.24.0", - "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "17.3.11", + "@angular-devkit/architect": "0.1802.12", + "@angular-devkit/build-webpack": "0.1802.12", + "@angular-devkit/core": "18.2.12", + "@angular/build": "18.2.12", + "@babel/core": "7.25.2", + "@babel/generator": "7.25.0", + "@babel/helper-annotate-as-pure": "7.24.7", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.25.0", + "@babel/plugin-transform-async-to-generator": "7.24.7", + "@babel/plugin-transform-runtime": "7.24.7", + "@babel/preset-env": "7.25.3", + "@babel/runtime": "7.25.0", + "@discoveryjs/json-ext": "0.6.1", + "@ngtools/webpack": "18.2.12", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", - "autoprefixer": "10.4.18", + "autoprefixer": "10.4.20", "babel-loader": "9.1.3", - "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", - "copy-webpack-plugin": "11.0.0", - "critters": "0.0.22", - "css-loader": "6.10.0", - "esbuild-wasm": "0.20.1", + "copy-webpack-plugin": "12.0.2", + "critters": "0.0.24", + "css-loader": "7.1.2", + "esbuild-wasm": "0.23.0", "fast-glob": "3.3.2", - "http-proxy-middleware": "2.0.7", - "https-proxy-agent": "7.0.4", - "inquirer": "9.2.15", - "jsonc-parser": "3.2.1", + "http-proxy-middleware": "3.0.3", + "https-proxy-agent": "7.0.5", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", "karma-source-map-support": "1.4.0", "less": "4.2.0", - "less-loader": "11.1.0", + "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.1", - "magic-string": "0.30.8", - "mini-css-extract-plugin": "2.8.1", + "loader-utils": "3.3.1", + "magic-string": "0.30.11", + "mini-css-extract-plugin": "2.9.0", "mrmime": "2.0.0", - "open": "8.4.2", + "open": "10.1.0", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", - "picomatch": "4.0.1", - "piscina": "4.4.0", - "postcss": "8.4.35", + "picomatch": "4.0.2", + "piscina": "4.6.1", + "postcss": "8.4.41", "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.71.1", - "sass-loader": "14.1.1", - "semver": "7.6.0", + "sass": "1.77.6", + "sass-loader": "16.0.0", + "semver": "7.6.3", "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "terser": "5.29.1", + "terser": "5.31.6", "tree-kill": "1.2.2", - "tslib": "2.6.2", - "undici": "6.11.1", - "vite": "5.1.8", - "watchpack": "2.4.0", + "tslib": "2.6.3", + "vite": "5.4.6", + "watchpack": "2.4.1", "webpack": "5.94.0", - "webpack-dev-middleware": "6.1.2", - "webpack-dev-server": "4.15.1", - "webpack-merge": "5.10.0", + "webpack-dev-middleware": "7.4.2", + "webpack-dev-server": "5.0.4", + "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.20.1" + "esbuild": "0.23.0" }, "peerDependencies": { - "@angular/compiler-cli": "^17.0.0", - "@angular/localize": "^17.0.0", - "@angular/platform-server": "^17.0.0", - "@angular/service-worker": "^17.0.0", + "@angular/compiler-cli": "^18.0.0", + "@angular/localize": "^18.0.0", + "@angular/platform-server": "^18.0.0", + "@angular/service-worker": "^18.0.0", "@web/test-runner": "^0.18.0", "browser-sync": "^3.0.2", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "karma": "^6.3.0", - "ng-packagr": "^17.0.0", + "ng-packagr": "^18.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=5.2 <5.5" + "typescript": ">=5.4 <5.6" }, "peerDependenciesMeta": { "@angular/localize": { @@ -515,87 +511,22 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1703.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.11.tgz", - "integrity": "sha512-YNasVZk4rYdcM6M+KRH8PUBhVyJfqzUYLpO98GgRokW+taIDgifckSlmfDZzQRbw45qiwei1IKCLqcpC8nM5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "17.3.11", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/build-webpack": { - "version": "0.1703.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1703.11.tgz", - "integrity": "sha512-qbCiiHuoVkD7CtLyWoRi/Vzz6nrEztpF5XIyWUcQu67An1VlxbMTE4yoSQiURjCQMnB/JvS1GPVed7wOq3SJ/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/architect": "0.1703.11", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^4.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz", - "integrity": "sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", - "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.0", - "@babel/parser": "^7.24.0", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.0", - "@babel/types": "^7.24.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -621,27 +552,28 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@babel/preset-env": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", - "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.23.3", - "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-assertions": "^7.24.7", + "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", @@ -653,59 +585,60 @@ "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.9", - "@babel/plugin-transform-async-to-generator": "^7.23.3", - "@babel/plugin-transform-block-scoped-functions": "^7.23.3", - "@babel/plugin-transform-block-scoping": "^7.23.4", - "@babel/plugin-transform-class-properties": "^7.23.3", - "@babel/plugin-transform-class-static-block": "^7.23.4", - "@babel/plugin-transform-classes": "^7.23.8", - "@babel/plugin-transform-computed-properties": "^7.23.3", - "@babel/plugin-transform-destructuring": "^7.23.3", - "@babel/plugin-transform-dotall-regex": "^7.23.3", - "@babel/plugin-transform-duplicate-keys": "^7.23.3", - "@babel/plugin-transform-dynamic-import": "^7.23.4", - "@babel/plugin-transform-exponentiation-operator": "^7.23.3", - "@babel/plugin-transform-export-namespace-from": "^7.23.4", - "@babel/plugin-transform-for-of": "^7.23.6", - "@babel/plugin-transform-function-name": "^7.23.3", - "@babel/plugin-transform-json-strings": "^7.23.4", - "@babel/plugin-transform-literals": "^7.23.3", - "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", - "@babel/plugin-transform-member-expression-literals": "^7.23.3", - "@babel/plugin-transform-modules-amd": "^7.23.3", - "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.9", - "@babel/plugin-transform-modules-umd": "^7.23.3", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.23.3", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", - "@babel/plugin-transform-numeric-separator": "^7.23.4", - "@babel/plugin-transform-object-rest-spread": "^7.24.0", - "@babel/plugin-transform-object-super": "^7.23.3", - "@babel/plugin-transform-optional-catch-binding": "^7.23.4", - "@babel/plugin-transform-optional-chaining": "^7.23.4", - "@babel/plugin-transform-parameters": "^7.23.3", - "@babel/plugin-transform-private-methods": "^7.23.3", - "@babel/plugin-transform-private-property-in-object": "^7.23.4", - "@babel/plugin-transform-property-literals": "^7.23.3", - "@babel/plugin-transform-regenerator": "^7.23.3", - "@babel/plugin-transform-reserved-words": "^7.23.3", - "@babel/plugin-transform-shorthand-properties": "^7.23.3", - "@babel/plugin-transform-spread": "^7.23.3", - "@babel/plugin-transform-sticky-regex": "^7.23.3", - "@babel/plugin-transform-template-literals": "^7.23.3", - "@babel/plugin-transform-typeof-symbol": "^7.23.3", - "@babel/plugin-transform-unicode-escapes": "^7.23.3", - "@babel/plugin-transform-unicode-property-regex": "^7.23.3", - "@babel/plugin-transform-unicode-regex": "^7.23.3", - "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoped-functions": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@babel/plugin-transform-class-static-block": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.0", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-dotall-regex": "^7.24.7", + "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", + "@babel/plugin-transform-dynamic-import": "^7.24.7", + "@babel/plugin-transform-exponentiation-operator": "^7.24.7", + "@babel/plugin-transform-export-namespace-from": "^7.24.7", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-json-strings": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-member-expression-literals": "^7.24.7", + "@babel/plugin-transform-modules-amd": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", + "@babel/plugin-transform-modules-umd": "^7.24.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-new-target": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-object-super": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-property-literals": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-reserved-words": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-template-literals": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", + "@babel/plugin-transform-unicode-escapes": "^7.24.7", + "@babel/plugin-transform-unicode-property-regex": "^7.24.7", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.8", - "babel-plugin-polyfill-corejs3": "^0.9.0", - "babel-plugin-polyfill-regenerator": "^0.5.5", - "core-js-compat": "^3.31.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -720,102 +653,17 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/build-angular/node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/autoprefixer": { - "version": "10.4.18", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", - "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "node_modules/@angular-devkit/build-angular/node_modules/@discoveryjs/json-ext": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz", + "integrity": "sha512-boghen8F0Q8D+0/Q1/1r6DUEieUJ8w2a1gIknExMSHBsJFOr2+0KUfHiVYBvucPwl3+RU5PFBK833FjFCh3BhA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001591", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=14.17.0" } }, "node_modules/@angular-devkit/build-angular/node_modules/babel-loader": { @@ -836,251 +684,137 @@ "webpack": ">=5" } }, - "node_modules/@angular-devkit/build-angular/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "license": "MIT" }, - "node_modules/@angular-devkit/build-angular/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/@angular-devkit/build-angular/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@angular-devkit/build-angular/node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "node_modules/@angular-devkit/build-angular/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==", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, "engines": { - "node": ">= 12" + "node": ">=8.0.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } }, - "node_modules/@angular-devkit/build-angular/node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "node_modules/@angular-devkit/build-angular/node_modules/http-proxy-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", "dev": true, - "license": "MIT", "dependencies": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/css-loader": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", - "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.4", - "postcss-modules-scope": "^3.1.1", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/build-angular/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==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/@angular-devkit/build-angular/node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "BSD-2-Clause", "engines": { - "node": ">=4.0" + "node": ">= 10" } }, - "node_modules/@angular-devkit/build-angular/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/@angular-devkit/build-angular/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": "*" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@angular-devkit/build-angular/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/@angular-devkit/build-angular/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=10.13.0" + "node": ">=10" } }, - "node_modules/@angular-devkit/build-angular/node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "node_modules/@angular-devkit/build-angular/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==", "dev": true, - "license": "MIT", - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, - "node_modules/@angular-devkit/build-angular/node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "node_modules/@angular-devkit/build-angular/node_modules/memfs": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.1.tgz", + "integrity": "sha512-Fq5CMEth+2iprLJ5mNizRcWuiwRZYjNkUD0zKk224jZunE9CRacTRDK8QLALbMBlNX2y3nY6lKZbesCwDwacig==", "dev": true, - "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/inquirer": { - "version": "9.2.15", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", - "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ljharb/through": "^2.3.12", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^3.2.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "node": ">= 4.0.0" }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, - "node_modules/@angular-devkit/build-angular/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==", - "dev": true, - "license": "MIT" - }, "node_modules/@angular-devkit/build-angular/node_modules/mini-css-extract-plugin": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", - "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", + "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", "dev": true, - "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -1096,47 +830,28 @@ "webpack": "^5.0.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@angular-devkit/build-angular/node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" }, "engines": { - "node": "*" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" + "node": ">=18" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@angular-devkit/build-angular/node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "dev": true, "funding": [ { @@ -1152,59 +867,35 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/@angular-devkit/build-angular/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, - "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "glob": "^10.3.7" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@angular-devkit/build-angular/node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/sass": { - "version": "1.71.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", - "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "version": "1.77.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", + "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", "dev": true, - "license": "MIT", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -1218,11 +909,10 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/sass-loader": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", - "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.0.tgz", + "integrity": "sha512-n13Z+3rU9A177dk4888czcVFiC8CL9dii4qpXWUg3YIIgZEvi9TCFKjOQcbK0kJM7DJu9VucrZFddvNfYCPwtw==", "dev": true, - "license": "MIT", "dependencies": { "neo-async": "^2.6.2" }, @@ -1258,17 +948,16 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/@angular-devkit/build-angular/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, "node_modules/@angular-devkit/build-angular/node_modules/webpack": { @@ -1318,88 +1007,116 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/webpack-dev-server": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "node_modules/@angular-devkit/build-angular/node_modules/webpack-dev-middleware": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, - "license": "MIT", "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { "webpack": { "optional": true - }, - "webpack-cli": { - "optional": true } } }, - "node_modules/@angular-devkit/build-angular/node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "node_modules/@angular-devkit/build-angular/node_modules/webpack-dev-server": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, - "license": "MIT", "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.4.0", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, "node_modules/@angular-devkit/build-angular/node_modules/webpack/node_modules/ajv": { @@ -1469,13 +1186,30 @@ "node": ">=10.13.0" } }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1802.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.12.tgz", + "integrity": "sha512-0Z3fdbZVRnjYWE2/VYyfy+uieY+6YZyEp4ylzklVkc+fmLNsnz4Zw6cK1LzzcBqAwKIyh1IdW20Cg7o8b0sONA==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1802.12", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, "node_modules/@angular-devkit/core": { - "version": "18.2.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.11.tgz", - "integrity": "sha512-H9P1shRGigORWJHUY2BRa2YurT+DVminrhuaYHsbhXBRsPmgB2Dx/30YLTnC1s5XmR9QIRUCsg/d3kyT1wd5Zg==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.12.tgz", + "integrity": "sha512-NtB6ypsaDyPE6/fqWOdfTmACs+yK5RqfH5tStEzWFeeDsIEDYKsJ06ypuRep7qTjYus5Rmttk0Ds+cFgz8JdUQ==", "dev": true, - "license": "MIT", - "peer": true, "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -1498,444 +1232,936 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@angular-devkit/core/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@angular-devkit/schematics": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.11.tgz", - "integrity": "sha512-I5wviiIqiFwar9Pdk30Lujk8FczEEc18i22A5c6Z9lbmhPQdTroDnEQdsfXjy404wPe8H62s0I15o4pmMGfTYQ==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.12.tgz", + "integrity": "sha512-mMea9txHbnCX5lXLHlo0RAgfhFHDio45/jMsREM2PA8UtVf2S8ltXz7ZwUrUyMQRv8vaSfn4ijDstF4hDMnRgQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.11", - "jsonc-parser": "3.2.1", - "magic-string": "0.30.8", + "@angular-devkit/core": "18.2.12", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", "ora": "5.4.1", "rxjs": "7.8.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz", - "integrity": "sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "18.4.3", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.4.3.tgz", + "integrity": "sha512-zdrA8mR98X+U4YgHzUKmivRU+PxzwOL/j8G7eTOvBuq8GPzsP+hvak+tyxlgeGm9HsvpFj9ERHLtJ0xDUPs8fg==", + "dev": true }, - "node_modules/@angular-devkit/schematics/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "node_modules/@angular-eslint/eslint-plugin": { + "version": "18.4.3", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.4.3.tgz", + "integrity": "sha512-AyJbupiwTBR81P6T59v+aULEnPpZBCBxL2S5QFWfAhNCwWhcof4GihvdK2Z87yhvzDGeAzUFSWl/beJfeFa+PA==", "dev": true, - "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@angular-eslint/bundled-angular-compiler": "18.4.3", + "@angular-eslint/utils": "18.4.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" } }, - "node_modules/@angular-devkit/schematics/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "18.4.3", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.4.3.tgz", + "integrity": "sha512-ijGlX2N01ayMXTpeQivOA31AszO8OEbu9ZQUCxnu9AyMMhxyi2q50bujRChAvN9YXQfdQtbxuajxV6+aiWb5BQ==", "dev": true, - "license": "MIT", "dependencies": { - "ajv": "^8.0.0" + "@angular-eslint/bundled-angular-compiler": "18.4.3", + "@angular-eslint/utils": "18.4.3", + "aria-query": "5.3.2", + "axobject-query": "4.1.0" }, "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "@typescript-eslint/types": "^7.11.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" } }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "17.5.3", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-17.5.3.tgz", - "integrity": "sha512-x9jZ6mME9wxumErPGonWERXX/9TJ7mzEkQhOKt3BxBFm0sy9XQqLMAenp1PBSg3RF3rH7EEVdB2+jb75RtHp0g==", + "node_modules/@angular-eslint/eslint-plugin-template/node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, - "license": "MIT" + "engines": { + "node": ">= 0.4" + } }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "17.5.3", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-17.5.3.tgz", - "integrity": "sha512-2gMRZ+SkiygrPDtCJwMfjmwIFOcvxxC4NRX/MqRo6udsa0gtqPrc8acRbwrmAXlullmhzmaeUfkHpGDSzW8pFw==", + "node_modules/@angular-eslint/schematics": { + "version": "18.4.3", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-18.4.3.tgz", + "integrity": "sha512-D5maKn5e6n58+8n7jLFLD4g+RGPOPeDSsvPc1sqial5tEKLxAJQJS9WZ28oef3bhkob6C60D+1H0mMmEEVvyVA==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.3", - "@angular-eslint/utils": "17.5.3", - "@typescript-eslint/utils": "7.11.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" + "@angular-devkit/core": ">= 18.0.0 < 19.0.0", + "@angular-devkit/schematics": ">= 18.0.0 < 19.0.0", + "@angular-eslint/eslint-plugin": "18.4.3", + "@angular-eslint/eslint-plugin-template": "18.4.3", + "ignore": "6.0.2", + "semver": "7.6.3", + "strip-json-comments": "3.1.1" } }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "17.5.3", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-17.5.3.tgz", - "integrity": "sha512-RkRFagxqBPV2xdNyeQQROUm6I1Izto1Z3Wy73lCk2zq1RhVgbznniH/epmOIE8PMkHmMKmZ765FV++J/90p4Ig==", + "node_modules/@angular-eslint/schematics/node_modules/ignore": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", + "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.3", - "@angular-eslint/utils": "17.5.3", - "@typescript-eslint/type-utils": "7.11.0", - "@typescript-eslint/utils": "7.11.0", - "aria-query": "5.3.0", - "axobject-query": "4.0.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" + "engines": { + "node": ">= 4" } }, - "node_modules/@angular-eslint/schematics": { - "version": "17.5.3", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-17.5.3.tgz", - "integrity": "sha512-a0MlOjNLIM18l/66S+CzhANQR3QH3jDUa1MC50E4KBf1mwjQyfqd6RdfbOTMDjgFlPrfB+5JvoWOHHGj7FFM1A==", + "node_modules/@angular-eslint/schematics/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/eslint-plugin": "17.5.3", - "@angular-eslint/eslint-plugin-template": "17.5.3", - "ignore": "5.3.1", - "strip-json-comments": "3.1.1", - "tmp": "0.2.3" + "bin": { + "semver": "bin/semver.js" }, - "peerDependencies": { - "@angular/cli": ">= 17.0.0 < 18.0.0" + "engines": { + "node": ">=10" } }, "node_modules/@angular-eslint/template-parser": { - "version": "17.5.3", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-17.5.3.tgz", - "integrity": "sha512-NYybOsMkJUtFOW2JWALicipq0kK5+jGwA1MYyRoXjdbDlXltHUb9qkXj7p0fE6uRutBGXDl4288s8g/fZCnAIA==", + "version": "18.4.3", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.4.3.tgz", + "integrity": "sha512-JZMPtEB8yNip3kg4WDEWQyObSo2Hwf+opq2ElYuwe85GQkGhfJSJ2CQYo4FSwd+c5MUQAqESNRg9QqGYauDsiw==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.3", - "eslint-scope": "^8.0.0" + "@angular-eslint/bundled-angular-compiler": "18.4.3", + "eslint-scope": "^8.0.2" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/utils": { - "version": "17.5.3", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-17.5.3.tgz", - "integrity": "sha512-0nNm1FUOLhVHrdK2PP5dZCYYVmTIkEJ4CmlwpuC4JtCLbD5XAHQpY/ZW5Ff5n1b7KfJt1Zy//jlhkkIaw3LaBQ==", + "version": "18.4.3", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.4.3.tgz", + "integrity": "sha512-w0bJ9+ELAEiPBSTPPm9bvDngfu1d8JbzUhvs2vU+z7sIz/HMwUZT5S4naypj2kNN0gZYGYrW0lt+HIbW87zTAQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.5.3", - "@typescript-eslint/utils": "7.11.0" + "@angular-eslint/bundled-angular-compiler": "18.4.3" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular/animations": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.12.tgz", - "integrity": "sha512-9hsdWF4gRRcVJtPcCcYLaX1CIyM9wUu6r+xRl6zU5hq8qhl35hig6ounz7CXFAzLf0WDBdM16bPHouVGaG76lg==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.13.tgz", + "integrity": "sha512-rG5J5Ek5Hg+Tz2NjkNOaG6PupiNK/lPfophXpsR1t/nWujqnMWX2krahD/i6kgD+jNWNKCJCYSOVvCx/BHOtKA==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" - }, - "peerDependencies": { - "@angular/core": "17.3.12" - } - }, - "node_modules/@angular/cdk": { - "version": "17.3.10", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.3.10.tgz", - "integrity": "sha512-b1qktT2c1TTTe5nTji/kFAVW92fULK0YhYAvJ+BjZTPKu2FniZNe8o4qqQ0pUuvtMu+ZQxp/QqFYoidIVCjScg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "optionalDependencies": { - "parse5": "^7.1.2" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "^17.0.0 || ^18.0.0", - "@angular/core": "^17.0.0 || ^18.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/cli": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.11.tgz", - "integrity": "sha512-8R9LwAGL8hGAWJ4mNG9ZPUrBUzIdmst0Ldua6RJJ+PrqgjX+8IbO+lNnfrOY/XY+Z3LXbCEJflL26f9czCvTPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/architect": "0.1703.11", - "@angular-devkit/core": "17.3.11", - "@angular-devkit/schematics": "17.3.11", - "@schematics/angular": "17.3.11", - "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.3", - "ini": "4.1.2", - "inquirer": "9.2.15", - "jsonc-parser": "3.2.1", - "npm-package-arg": "11.0.1", - "npm-pick-manifest": "9.0.0", - "open": "8.4.2", - "ora": "5.4.1", - "pacote": "17.0.6", - "resolve": "1.22.8", - "semver": "7.6.0", - "symbol-observable": "4.0.0", - "yargs": "17.7.2" - }, - "bin": { - "ng": "bin/ng.js" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { - "version": "0.1703.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.11.tgz", - "integrity": "sha512-YNasVZk4rYdcM6M+KRH8PUBhVyJfqzUYLpO98GgRokW+taIDgifckSlmfDZzQRbw45qiwei1IKCLqcpC8nM5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "17.3.11", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "@angular/core": "18.2.13" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz", - "integrity": "sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==", + "node_modules/@angular/build": { + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.12.tgz", + "integrity": "sha512-4Ohz+OSILoL+cCAQ4UTiCT5v6pctu3fXNoNpTEUK46OmxELk9jDITO5rNyNS7TxBn9wY69kjX5VcDf7MenquFQ==", "dev": true, - "license": "MIT", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1802.12", + "@babel/core": "7.25.2", + "@babel/helper-annotate-as-pure": "7.24.7", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-syntax-import-attributes": "7.24.7", + "@inquirer/confirm": "3.1.22", + "@vitejs/plugin-basic-ssl": "1.1.0", + "browserslist": "^4.23.0", + "critters": "0.0.24", + "esbuild": "0.23.0", + "fast-glob": "3.3.2", + "https-proxy-agent": "7.0.5", + "listr2": "8.2.4", + "lmdb": "3.0.13", + "magic-string": "0.30.11", + "mrmime": "2.0.0", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.2", + "piscina": "4.6.1", + "rollup": "4.22.4", + "sass": "1.77.6", + "semver": "7.6.3", + "vite": "5.4.6", + "watchpack": "2.4.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "peerDependencies": { - "chokidar": "^3.5.2" + "@angular/compiler-cli": "^18.0.0", + "@angular/localize": "^18.0.0", + "@angular/platform-server": "^18.0.0", + "@angular/service-worker": "^18.0.0", + "less": "^4.2.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.4 <5.6" }, "peerDependenciesMeta": { - "chokidar": { + "@angular/localize": { "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular/build/node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@angular/cli/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/@angular/build/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular/build/node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", "dev": true, - "license": "MIT", "dependencies": { - "ajv": "^8.0.0" + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "ajv": "^8.0.0" + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", + "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", + "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", + "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", + "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", + "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", + "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", + "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", + "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", + "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", + "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", + "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", + "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", + "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", + "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", + "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@angular/build/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@angular/build/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/build/node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/build/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@angular/build/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true + }, + "node_modules/@angular/build/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/@angular/build/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/build/node_modules/listr2": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@angular/build/node_modules/rollup": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", + "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.22.4", + "@rollup/rollup-android-arm64": "4.22.4", + "@rollup/rollup-darwin-arm64": "4.22.4", + "@rollup/rollup-darwin-x64": "4.22.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", + "@rollup/rollup-linux-arm-musleabihf": "4.22.4", + "@rollup/rollup-linux-arm64-gnu": "4.22.4", + "@rollup/rollup-linux-arm64-musl": "4.22.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", + "@rollup/rollup-linux-riscv64-gnu": "4.22.4", + "@rollup/rollup-linux-s390x-gnu": "4.22.4", + "@rollup/rollup-linux-x64-gnu": "4.22.4", + "@rollup/rollup-linux-x64-musl": "4.22.4", + "@rollup/rollup-win32-arm64-msvc": "4.22.4", + "@rollup/rollup-win32-ia32-msvc": "4.22.4", + "@rollup/rollup-win32-x64-msvc": "4.22.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/@angular/build/node_modules/sass": { + "version": "1.77.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", + "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@angular/build/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/build/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/@angular/build/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/build/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@angular/build/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@angular/cdk": { + "version": "18.2.14", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.14.tgz", + "integrity": "sha512-vDyOh1lwjfVk9OqoroZAP8pf3xxKUvyl+TVR8nJxL4c5fOfUFkD7l94HaanqKSRwJcI2xiztuu92IVoHn8T33Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "optionalDependencies": { + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@angular/common": "^18.0.0 || ^19.0.0", + "@angular/core": "^18.0.0 || ^19.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/cli": { + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.12.tgz", + "integrity": "sha512-xhuZ/b7IhqNw1MgXf+arWf4x+GfUSt/IwbdWU4+CO8A7h0Y46zQywouP/KUK3cMQZfVdHdciTBvlpF3vFacA6Q==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1802.12", + "@angular-devkit/core": "18.2.12", + "@angular-devkit/schematics": "18.2.12", + "@inquirer/prompts": "5.3.8", + "@listr2/prompt-adapter-inquirer": "2.0.15", + "@schematics/angular": "18.2.12", + "@yarnpkg/lockfile": "1.1.0", + "ini": "4.1.3", + "jsonc-parser": "3.3.1", + "listr2": "8.2.4", + "npm-package-arg": "11.0.3", + "npm-pick-manifest": "9.1.0", + "pacote": "18.0.6", + "resolve": "1.22.8", + "semver": "7.6.3", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@angular/cli/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/cli/node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/cli/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true + }, + "node_modules/@angular/cli/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/@angular/cli/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular/cli/node_modules/listr2": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@angular/cli/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "bin": { + "semver": "bin/semver.js" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=10" } }, - "node_modules/@angular/cli/node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "node_modules/@angular/cli/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, - "license": "ISC", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, "engines": { - "node": ">= 12" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/@angular/cli/node_modules/inquirer": { - "version": "9.2.15", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", - "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "node_modules/@angular/cli/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { - "@ljharb/through": "^2.3.12", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^3.2.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@angular/cli/node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "node_modules/@angular/cli/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "ISC", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@angular/cli/node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "node_modules/@angular/cli/node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=0.12.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/@angular/common": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.12.tgz", - "integrity": "sha512-vabJzvrx76XXFrm1RJZ6o/CyG32piTB/1sfFfKHdlH1QrmArb8It4gyk9oEjZ1IkAD0HvBWlfWmn+T6Vx3pdUw==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.13.tgz", + "integrity": "sha512-4ZqrNp1PoZo7VNvW+sbSc2CB2axP1sCH2wXl8B0wdjsj8JY1hF1OhuugwhpAHtGxqewed2kCXayE+ZJqSTV4jw==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "17.3.12", + "@angular/core": "18.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.12.tgz", - "integrity": "sha512-vwI8oOL/gM+wPnptOVeBbMfZYwzRxQsovojZf+Zol9szl0k3SZ3FycWlxxXZGFu3VIEfrP6pXplTmyODS/Lt1w==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.13.tgz", + "integrity": "sha512-TzWcrkopyjFF+WeDr2cRe8CcHjU72KfYV3Sm2TkBkcXrkYX5sDjGWrBGrG3hRB4e4okqchrOCvm1MiTdy2vKMA==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "17.3.12" + "@angular/core": "18.2.13" }, "peerDependenciesMeta": { "@angular/core": { @@ -1944,15 +2170,14 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.12.tgz", - "integrity": "sha512-1F8M7nWfChzurb7obbvuE7mJXlHtY1UG58pcwcomVtpPb+kPavgAO8OEvJHYBMV+bzSxkXt5UIwL9lt9jHUxZA==", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.13.tgz", + "integrity": "sha512-DBSh4AQwkiJDSiVvJATRmjxf6wyUs9pwQLgaFdSlfuTRO+sdb0J2z1r3BYm8t0IqdoyXzdZq2YCH43EmyvD71g==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/core": "7.23.9", + "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^3.0.0", + "chokidar": "^4.0.0", "convert-source-map": "^1.5.1", "reflect-metadata": "^0.2.0", "semver": "^7.0.0", @@ -1965,30 +2190,29 @@ "ngcc": "bundles/ngcc/index.js" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "17.3.12", - "typescript": ">=5.2 <5.5" + "@angular/compiler": "18.2.13", + "typescript": ">=5.4 <5.6" } }, "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -2007,85 +2231,107 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/compiler-cli/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/core": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.12.tgz", - "integrity": "sha512-MuFt5yKi161JmauUta4Dh0m8ofwoq6Ino+KoOtkYMBGsSx+A7dSm+DUxxNwdj7+DNyg3LjVGCFgBFnq4g8z06A==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.13.tgz", + "integrity": "sha512-8mbWHMgO95OuFV1Ejy4oKmbe9NOJ3WazQf/f7wks8Bck7pcihd0IKhlPBNjFllbF5o+04EYSwFhEtvEgjMDClA==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.0" + "zone.js": "~0.14.10" } }, "node_modules/@angular/elements": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/elements/-/elements-17.3.12.tgz", - "integrity": "sha512-rUfEaV+Ol0bxtcEfNuf/7aVe+3/hAVJMNF/DHG71BSekCxPSH5WR6wE0zsXmVoTBadj+TUDlsyju9o9n3+C5Vg==", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/elements/-/elements-18.2.13.tgz", + "integrity": "sha512-yahRkXWgFolpWMeVsTIlWYwoq4Bsz6wrfS4b+TKHIZbTCyRUlJ5zBFecpYMwgmVuQDJZp+WkUWZV2Qg7kLJR5w==", "dev": true, - "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "17.3.12", + "@angular/core": "18.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/forms": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.3.12.tgz", - "integrity": "sha512-tV6r12Q3yEUlXwpVko4E+XscunTIpPkLbaiDn/MTL3Vxi2LZnsLgHyd/i38HaHN+e/H3B0a1ToSOhV5wf3ay4Q==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.13.tgz", + "integrity": "sha512-A67D867fu3DSBhdLWWZl/F5pr7v2+dRM2u3U7ZJ0ewh4a+sv+0yqWdJW+a8xIoiHxS+btGEJL2qAKJiH+MCFfg==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "17.3.12", - "@angular/core": "17.3.12", - "@angular/platform-browser": "17.3.12", + "@angular/common": "18.2.13", + "@angular/core": "18.2.13", + "@angular/platform-browser": "18.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.12.tgz", - "integrity": "sha512-DYY04ptWh/ulMHzd+y52WCE8QnEYGeIiW3hEIFjCN8z0kbIdFdUtEB0IK5vjNL3ejyhUmphcpeT5PYf3YXtqWQ==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.13.tgz", + "integrity": "sha512-tu7ZzY6qD3ATdWFzcTcsAKe7M6cJeWbT/4/bF9unyGO3XBPcNYDKoiz10+7ap2PUd0fmPwvuvTvSNJiFEBnB8Q==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "17.3.12", - "@angular/common": "17.3.12", - "@angular/core": "17.3.12" + "@angular/animations": "18.2.13", + "@angular/common": "18.2.13", + "@angular/core": "18.2.13" }, "peerDependenciesMeta": { "@angular/animations": { @@ -2094,38 +2340,36 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.3.12.tgz", - "integrity": "sha512-DQwV7B2x/DRLRDSisngZRdLqHdYbbrqZv2Hmu4ZbnNYaWPC8qvzgE/0CvY+UkDat3nCcsfwsMnlDeB6TL7/IaA==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.13.tgz", + "integrity": "sha512-kbQCf9+8EpuJC7buBxhSiwBtXvjAwAKh6MznD6zd2pyCYqfY6gfRCZQRtK59IfgVtKmEONWI9grEyNIRoTmqJg==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "17.3.12", - "@angular/compiler": "17.3.12", - "@angular/core": "17.3.12", - "@angular/platform-browser": "17.3.12" + "@angular/common": "18.2.13", + "@angular/compiler": "18.2.13", + "@angular/core": "18.2.13", + "@angular/platform-browser": "18.2.13" } }, "node_modules/@angular/router": { - "version": "17.3.12", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.3.12.tgz", - "integrity": "sha512-dg7PHBSW9fmPKTVzwvHEeHZPZdpnUqW/U7kj8D29HTP9ur8zZnx9QcnbplwPeYb8yYa62JMnZSEel2X4PxdYBg==", - "license": "MIT", + "version": "18.2.13", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.13.tgz", + "integrity": "sha512-VKmfgi/r/CkyBq9nChQ/ptmfu0JT/8ONnLVJ5H+SkFLRYJcIRyHLKjRihMCyVm6xM5yktOdCaW73NTQrFz7+bg==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "17.3.12", - "@angular/core": "17.3.12", - "@angular/platform-browser": "17.3.12", + "@angular/common": "18.2.13", + "@angular/core": "18.2.13", + "@angular/platform-browser": "18.2.13", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -2226,15 +2470,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -2242,13 +2485,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2428,19 +2670,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", @@ -2584,13 +2813,12 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -3097,16 +3325,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", - "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.20", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -3116,15 +3343,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", - "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", + "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.20" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-remap-async-to-generator": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -3781,17 +4007,16 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", - "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.7.tgz", + "integrity": "sha512-YqXjrk4C+a1kZjewqt+Mmu2UuV1s07y8kqcUf4qYLnoqemhR4gRQikhdAhSVJioMjVTu6Mo6pAbaypEA3jY6fw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.24.0", - "babel-plugin-polyfill-corejs2": "^0.4.8", - "babel-plugin-polyfill-corejs3": "^0.9.0", - "babel-plugin-polyfill-regenerator": "^0.5.5", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.1", + "babel-plugin-polyfill-regenerator": "^0.6.1", "semver": "^6.3.1" }, "engines": { @@ -3806,7 +4031,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -4091,33 +4315,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz", - "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -4144,11 +4341,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", - "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dev": true, - "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -4696,33 +4892,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@compodoc/compodoc/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@compodoc/compodoc/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", - "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, "node_modules/@compodoc/compodoc/node_modules/cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -4816,26 +4985,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@compodoc/compodoc/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/@compodoc/compodoc/node_modules/jackspeak": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", @@ -4865,13 +5014,6 @@ "node": ">=6" } }, - "node_modules/@compodoc/compodoc/node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@compodoc/compodoc/node_modules/lru-cache": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", @@ -4882,16 +5024,6 @@ "node": "20 || >=22" } }, - "node_modules/@compodoc/compodoc/node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, "node_modules/@compodoc/compodoc/node_modules/minimatch": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", @@ -4919,23 +5051,10 @@ "minipass": "^7.1.2" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@compodoc/compodoc/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@compodoc/compodoc/node_modules/semver": { @@ -5095,16 +5214,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/@electron/asar": { "version": "3.2.15", "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.15.tgz", @@ -5542,20 +5651,19 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", - "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -5834,6 +5942,252 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@inquirer/checkbox": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", + "integrity": "sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.3", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/confirm": { + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", + "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", + "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", + "dev": true, + "dependencies": { + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", + "@types/mute-stream": "^0.0.4", + "@types/node": "^22.5.5", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^1.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/@inquirer/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", + "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", + "dev": true, + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@inquirer/core/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@inquirer/editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.2.0.tgz", + "integrity": "sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/expand": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.3.0.tgz", + "integrity": "sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.8.tgz", + "integrity": "sha512-tKd+jsmhq21AP1LhexC0pPwsCxEhGgAkg28byjJAd+xhmIs8LUX8JbUc3vBf3PhLxWiB5EvyBE5X7JSPAqMAqg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.3.0.tgz", + "integrity": "sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-1.1.0.tgz", + "integrity": "sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/password": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.2.0.tgz", + "integrity": "sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/prompts": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.3.8.tgz", + "integrity": "sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==", + "dev": true, + "dependencies": { + "@inquirer/checkbox": "^2.4.7", + "@inquirer/confirm": "^3.1.22", + "@inquirer/editor": "^2.1.22", + "@inquirer/expand": "^2.1.22", + "@inquirer/input": "^2.2.9", + "@inquirer/number": "^1.0.10", + "@inquirer/password": "^2.1.22", + "@inquirer/rawlist": "^2.2.4", + "@inquirer/search": "^1.0.7", + "@inquirer/select": "^2.4.7" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/rawlist": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.3.0.tgz", + "integrity": "sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-1.1.0.tgz", + "integrity": "sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/select": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.5.0.tgz", + "integrity": "sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA==", + "dev": true, + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.3", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==", + "dev": true, + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/type/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -5943,6 +6297,7 @@ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -5960,6 +6315,7 @@ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -5974,6 +6330,7 @@ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -5987,6 +6344,7 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -6003,6 +6361,7 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -6586,6 +6945,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.15.tgz", + "integrity": "sha512-MZrGem/Ujjd4cPTLYDfCZK2iKKeiO/8OX13S6jqxldLs0Prf2aGqVlJ77nMBqMv7fzqgXEgjrNHLXcKR8l9lOg==", + "dev": true, + "dependencies": { + "@inquirer/type": "^1.5.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 6" + } + }, "node_modules/@lit-labs/react": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-1.2.1.tgz", @@ -6610,18 +6984,83 @@ "@lit-labs/ssr-dom-shim": "^1.0.0" } }, - "node_modules/@ljharb/through": { - "version": "2.3.13", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", - "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.13.tgz", + "integrity": "sha512-uiKPB0Fv6WEEOZjruu9a6wnW/8jrjzlZbxXscMB8kuCJ1k6kHpcBnuvaAWcqhbI7rqX5GKziwWEdD+wi2gNLfA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - } + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.13.tgz", + "integrity": "sha512-bEVIIfK5mSQoG1R19qA+fJOvCB+0wVGGnXHT3smchBVahYBdlPn2OsZZKzlHWfb1E+PhLBmYfqB5zQXFP7hJig==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.13.tgz", + "integrity": "sha512-Yml1KlMzOnXj/tnW7yX8U78iAzTk39aILYvCPbqeewAq1kSzl+w59k/fiVkTBfvDi/oW/5YRxL+Fq+Y1Fr1r2Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.13.tgz", + "integrity": "sha512-afbVrsMgZ9dUTNUchFpj5VkmJRxvht/u335jUJ7o23YTbNbnpmXif3VKQGCtnjSh+CZaqm6N3CPG8KO3zwyZ1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.13.tgz", + "integrity": "sha512-vOtxu0xC0SLdQ2WRXg8Qgd8T32ak4SPqk5zjItRszrJk2BdeXqfGxBJbP7o4aOvSPSmSSv46Lr1EP4HXU8v7Kg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.13.tgz", + "integrity": "sha512-UCrMJQY/gJnOl3XgbWRZZUvGGBuKy6i0YNSptgMzHBjs+QYDYR1Mt/RLTOPy4fzzves65O1EDmlL//OzEqoLlA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@malept/cross-spawn-promise": { "version": "2.0.0", @@ -6755,14 +7194,92 @@ } } }, - "node_modules/@msgpack/msgpack": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", - "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==", - "license": "ISC", - "engines": { - "node": ">= 10" - } + "node_modules/@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==", + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@napi-rs/cli": { "version": "2.18.4", @@ -6782,37 +7299,35 @@ } }, "node_modules/@ng-select/ng-select": { - "version": "12.0.7", - "resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-12.0.7.tgz", - "integrity": "sha512-Eht1zlLP0DJxiXcKnq3aY/EJ8odomgU0hM0BJoPY6oX3XFHndtFtdPxlZfhVtQn+FwyDEh7306rRx6digxVssA==", - "license": "MIT", + "version": "13.9.1", + "resolved": "https://registry.npmjs.org/@ng-select/ng-select/-/ng-select-13.9.1.tgz", + "integrity": "sha512-+DzQkQp8coGWZREflJM/qx7BXipV6HEVpZCXoa6fJJRHJfmUMsxa5uV6kUVmClUE98Rkffk9CPHt6kZcj8PuqQ==", "dependencies": { "tslib": "^2.3.1" }, "engines": { - "node": ">= 16", + "node": ">= 18", "npm": ">= 8" }, "peerDependencies": { - "@angular/common": "^17.0.0-rc.0", - "@angular/core": "^17.0.0-rc.0", - "@angular/forms": "^17.0.0-rc.0" + "@angular/common": "^18.0.0", + "@angular/core": "^18.0.0", + "@angular/forms": "^18.0.0" } }, "node_modules/@ngtools/webpack": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.11.tgz", - "integrity": "sha512-SfTCbplt4y6ak5cf2IfqdoVOsnoNdh/j6Vu+wb8WWABKwZ5yfr2S/Gk6ithSKcdIZhAF8DNBOoyk1EJuf8Xkfg==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.12.tgz", + "integrity": "sha512-FFJAwtWbtpncMOVNuULPBwFJB7GSjiUwO93eGTzRp8O4EPQ8lCQeFbezQm/NP34+T0+GBLGzPSuQT+muob8YKw==", "dev": true, - "license": "MIT", "engines": { - "node": "^18.13.0 || >=20.9.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "peerDependencies": { - "@angular/compiler-cli": "^17.0.0", - "typescript": ">=5.2 <5.5", + "@angular/compiler-cli": "^18.0.0", + "typescript": ">=5.4 <5.6", "webpack": "^5.54.0" } }, @@ -6859,7 +7374,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", "dev": true, - "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -6876,7 +7390,6 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -6889,7 +7402,6 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, - "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -6902,15 +7414,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@npmcli/agent/node_modules/socks-proxy-agent": { "version": "8.0.4", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "dev": true, - "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -6939,7 +7449,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^7.0.0", "ini": "^4.1.3", @@ -6955,22 +7464,11 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/git/node_modules/ini": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", - "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/@npmcli/git/node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16" } @@ -6979,15 +7477,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@npmcli/git/node_modules/proc-log": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -6997,7 +7493,6 @@ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -7013,7 +7508,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.1.0.tgz", "integrity": "sha512-c8UuGLeZpm69BryRykLuKRyKFZYJsZSCT4aVY5ds4omyZqJ172ApzgfKJ5eV/r3HgLdUYgFVe54KSFVjKoe27w==", "dev": true, - "license": "ISC", "dependencies": { "npm-bundled": "^3.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -7108,7 +7602,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7118,7 +7611,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.2.1.tgz", "integrity": "sha512-f7zYC6kQautXHvNbLEWgD/uGu1+xCn9izgqBfgItWSx22U0ZDekxN08A1vM8cTxj/cRVe0Q94Ode+tdoYmIOOQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "glob": "^10.2.2", @@ -7137,7 +7629,6 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -7149,15 +7640,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@npmcli/package-json/node_modules/proc-log": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7167,7 +7656,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.2.tgz", "integrity": "sha512-xhfYPXoV5Dy4UkY0D+v2KkwvnDfiA/8Mt3sWCGI/hM03NsYIH8ZaG6QzS9x7pje5vHZBZJ2v6VRFVTWACnqcmQ==", "dev": true, - "license": "ISC", "dependencies": { "which": "^4.0.0" }, @@ -7180,7 +7668,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16" } @@ -7190,7 +7677,6 @@ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -7202,26 +7688,25 @@ } }, "node_modules/@npmcli/redact": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", - "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.1.tgz", + "integrity": "sha512-YgsR5jCQZhVmTJvjduTOIHph0L73pK8xwMVaDY0PatySqVM9AZj93jpoXYSJqfHFxFkN9dmqTw6OiqExsS3LPw==", "dev": true, - "license": "ISC", "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@npmcli/run-script": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", - "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", + "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.0.0", "@npmcli/promise-spawn": "^7.0.0", "node-gyp": "^10.0.0", + "proc-log": "^4.0.0", "which": "^4.0.0" }, "engines": { @@ -7233,17 +7718,24 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16" } }, + "node_modules/@npmcli/run-script/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/run-script/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -7369,83 +7861,19 @@ ] }, "node_modules/@schematics/angular": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.11.tgz", - "integrity": "sha512-tvJpTgYC+hCnTyLszYRUZVyNTpPd+C44gh5CPTcG3qkqStzXQwynQAf6X/DjtwXbUiPQF0XfF0+0R489GpdZPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "17.3.11", - "@angular-devkit/schematics": "17.3.11", - "jsonc-parser": "3.2.1" - }, - "engines": { - "node": "^18.13.0 || >=20.9.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.11.tgz", - "integrity": "sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==", + "version": "18.2.12", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.12.tgz", + "integrity": "sha512-sIoeipsisK5eTLW3XuNZYcal83AfslBbgI7LnV+3VrXwpasKPGHwo2ZdwhCd2IXAkuJ02Iyu7MyV0aQRM9i/3g==", "dev": true, - "license": "MIT", "dependencies": { - "ajv": "8.12.0", - "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.1", - "rxjs": "7.8.1", - "source-map": "0.7.4" + "@angular-devkit/core": "18.2.12", + "@angular-devkit/schematics": "18.2.12", + "jsonc-parser": "3.3.1" }, "engines": { - "node": "^18.13.0 || >=20.9.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@schematics/angular/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@schematics/angular/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } } }, "node_modules/@sideway/address": { @@ -7477,7 +7905,6 @@ "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", "integrity": "sha512-wueKWDk70QixNLB363yHc2D2ItTgYiMTdPwK8D9dKQMR3ZQ0c35IxP5xnwQ8cNLoCgCRcHf14kE+CLIvNX1zmA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.3.2" }, @@ -7490,7 +7917,6 @@ "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.1.0.tgz", "integrity": "sha512-JzBqdVIyqm2FRQCulY6nbQzMpJJpSiJ8XXWMhtOX9eKgaXXpfNOF53lzQEjIydlStnd/eFtuC1dW4VYdD93oRg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -7500,7 +7926,6 @@ "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.2.tgz", "integrity": "sha512-c6B0ehIWxMI8wiS/bj6rHMPqeFvngFV7cDU/MY+B16P9Z3Mp9k8L93eYZ7BYzSickzuqAQqAq0V956b3Ju6mLw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -7510,7 +7935,6 @@ "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.3.2.tgz", "integrity": "sha512-5Vz5dPVuunIIvC5vBb0APwo7qKA4G9yM48kPWJT+OEERs40md5GoUR1yedwpekWZ4m0Hhw44m6zU+ObsON+iDA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", @@ -7528,7 +7952,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, - "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -7541,7 +7964,6 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -7565,7 +7987,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -7577,15 +7998,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/@sigstore/sign/node_modules/make-fetch-happen": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -7609,7 +8028,6 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -7622,7 +8040,6 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, - "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -7640,7 +8057,6 @@ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7650,7 +8066,6 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -7663,7 +8078,6 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -7676,7 +8090,6 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -7689,7 +8102,6 @@ "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.4.tgz", "integrity": "sha512-44vtsveTPUpqhm9NCrbU8CWLe3Vck2HO1PNLw7RIajbB7xhtn5RBPm1VNSCMwqGYHhDsBJG8gDF0q4lgydsJvw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.3.2", "tuf-js": "^2.2.1" @@ -7703,7 +8115,6 @@ "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.2.1.tgz", "integrity": "sha512-8iKx79/F73DKbGfRf7+t4dqrc0bRr0thdPrxAtCKWRm/F0tG71i6O1rvlnScncJLLBZHn3h8M3c1BSUAb9yu8g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.1.0", @@ -8615,7 +9026,6 @@ "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", "dev": true, - "license": "MIT", "engines": { "node": "^16.14.0 || >=18.0.0" } @@ -8625,7 +9035,6 @@ "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.1.tgz", "integrity": "sha512-92F7/SFyufn4DXsha9+QfKnN03JGqtMFMXgSHbZOo8JG59WkTni7UzAouNQDf7AuP9OAMxVOPQcqG3sB7w+kkg==", "dev": true, - "license": "MIT", "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.4" @@ -9207,6 +9616,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mute-stream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", + "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "22.10.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", @@ -9485,6 +9903,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true + }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", @@ -9772,102 +10196,10 @@ "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/typescript-estree": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", - "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", - "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/utils": "7.11.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/typescript-estree": "7.16.1", + "@typescript-eslint/visitor-keys": "7.16.1", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -9876,21 +10208,24 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.56.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", + "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.11.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/visitor-keys": "7.16.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -9949,6 +10284,7 @@ "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.11.0", @@ -9972,6 +10308,7 @@ "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "7.11.0", "@typescript-eslint/visitor-keys": "7.11.0" @@ -9990,6 +10327,7 @@ "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -10004,6 +10342,7 @@ "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/types": "7.11.0", "@typescript-eslint/visitor-keys": "7.11.0", @@ -10033,6 +10372,7 @@ "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/types": "7.11.0", "eslint-visitor-keys": "^3.4.3" @@ -10525,19 +10865,6 @@ "node": ">=10" } }, - "node_modules/@yao-pkg/pkg/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -11201,6 +11528,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -11549,13 +11877,12 @@ } }, "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" + "engines": { + "node": ">= 0.4" } }, "node_modules/babel-jest": { @@ -11605,6 +11932,7 @@ "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -11659,61 +11987,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", - "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0", - "core-js-compat": "^3.34.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", - "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", - "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", + "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.6.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -12640,6 +12932,7 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -13877,11 +14170,11 @@ "license": "MIT" }, "node_modules/critters": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", - "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", + "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", + "deprecated": "Ownership of Critters has moved to the Nuxt team, who will be maintaining the project going forward. If you'd like to keep using Critters, please switch to the actively-maintained fork at https://github.com/danielroe/beasties", "dev": true, - "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -13892,26 +14185,6 @@ "postcss-media-query-parser": "^0.2.3" } }, - "node_modules/critters/node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -15454,42 +15727,42 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", - "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.1", - "@esbuild/android-arm": "0.20.1", - "@esbuild/android-arm64": "0.20.1", - "@esbuild/android-x64": "0.20.1", - "@esbuild/darwin-arm64": "0.20.1", - "@esbuild/darwin-x64": "0.20.1", - "@esbuild/freebsd-arm64": "0.20.1", - "@esbuild/freebsd-x64": "0.20.1", - "@esbuild/linux-arm": "0.20.1", - "@esbuild/linux-arm64": "0.20.1", - "@esbuild/linux-ia32": "0.20.1", - "@esbuild/linux-loong64": "0.20.1", - "@esbuild/linux-mips64el": "0.20.1", - "@esbuild/linux-ppc64": "0.20.1", - "@esbuild/linux-riscv64": "0.20.1", - "@esbuild/linux-s390x": "0.20.1", - "@esbuild/linux-x64": "0.20.1", - "@esbuild/netbsd-x64": "0.20.1", - "@esbuild/openbsd-x64": "0.20.1", - "@esbuild/sunos-x64": "0.20.1", - "@esbuild/win32-arm64": "0.20.1", - "@esbuild/win32-ia32": "0.20.1", - "@esbuild/win32-x64": "0.20.1" + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" } }, "node_modules/esbuild-register": { @@ -15506,16 +15779,15 @@ } }, "node_modules/esbuild-wasm": { - "version": "0.20.1", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.1.tgz", - "integrity": "sha512-6v/WJubRsjxBbQdz6izgvx7LsVFvVaGmSdwrFHmEzoVgfXL89hkKPoQHsnVI2ngOkcBUQT9kmAM1hVL1k/Av4A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.23.0.tgz", + "integrity": "sha512-6jP8UmWy6R6TUUV8bMuC3ZyZ6lZKI56x0tkxyCIqWwRRJ/DgeQKneh/Oid5EoGoPFLrGNkz47ZEtWAYuiY/u9g==", "dev": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/escalade": { @@ -17595,6 +17867,7 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -18200,6 +18473,25 @@ "node": ">=12" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/http-assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz", @@ -18570,7 +18862,6 @@ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.5.tgz", "integrity": "sha512-VuuG0wCnjhnylG1ABXT3dAuIpTNDs/G8jlpmwXY03fXoXy/8ZK8/T+hMzt8L4WnrLCJgdybqgPagnF/f97cg3A==", "dev": true, - "license": "ISC", "dependencies": { "minimatch": "^9.0.0" }, @@ -18602,8 +18893,7 @@ "version": "4.3.7", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -18775,11 +19065,10 @@ "license": "ISC" }, "node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -19255,6 +19544,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -19456,6 +19754,7 @@ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -19473,6 +19772,7 @@ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" } @@ -20298,6 +20598,16 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-haste-map/node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "peer": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/jest-junit": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", @@ -21078,6 +21388,7 @@ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -21205,7 +21516,6 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, - "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -21268,11 +21578,10 @@ } }, "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true, - "license": "MIT" + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true }, "node_modules/jsonfile": { "version": "6.1.0", @@ -21302,8 +21611,7 @@ "dev": true, "engines": [ "node >= 0.2.0" - ], - "license": "MIT" + ] }, "node_modules/jsqr": { "version": "1.4.0", @@ -21422,16 +21730,6 @@ "node": ">=6" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/koa": { "version": "2.15.3", "resolved": "https://registry.npmjs.org/koa/-/koa-2.15.3.tgz", @@ -21662,24 +21960,29 @@ } }, "node_modules/less-loader": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.2.0.tgz", + "integrity": "sha512-MYUxjSQSBUQmowc0l5nPieOYwMzGPUaTzB6inNW/bdPEG9zOL3eAAD1Qw5ZxSPk7we5dMojHwNODYMV1hq4EVg==", "dev": true, - "license": "MIT", - "dependencies": { - "klona": "^2.0.4" - }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "less": "^3.5.0 || ^4.0.0", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/less/node_modules/make-dir": { @@ -22189,6 +22492,37 @@ "@types/trusted-types": "^2.0.2" } }, + "node_modules/lmdb": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.13.tgz", + "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "msgpackr": "^1.10.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.4.1", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.0.13", + "@lmdb/lmdb-darwin-x64": "3.0.13", + "@lmdb/lmdb-linux-arm": "3.0.13", + "@lmdb/lmdb-linux-arm64": "3.0.13", + "@lmdb/lmdb-linux-x64": "3.0.13", + "@lmdb/lmdb-win32-x64": "3.0.13" + } + }, + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -22200,11 +22534,10 @@ } }, "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 12.13.0" } @@ -22652,16 +22985,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, - "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/make-dir": { @@ -23823,8 +24152,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/minimatch": { "version": "9.0.5", @@ -23965,37 +24293,6 @@ "dev": true, "license": "ISC" }, - "node_modules/minipass-json-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.2.tgz", - "integrity": "sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -24183,12 +24480,43 @@ "node": ">=10" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.2.tgz", + "integrity": "sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g==", + "dev": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, "node_modules/multer": { "version": "1.4.5-lts.1", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", @@ -24354,16 +24682,15 @@ } }, "node_modules/ngx-infinite-scroll": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-17.0.1.tgz", - "integrity": "sha512-T+XseajbmT9YTMmPnFV/AfSlwjaV9m2gZtbIIZH3S+yg/rvvfbgkThqs54UWIu+pqcqNR4UhrXfw6mUjCVZD2A==", - "license": "MIT", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-18.0.0.tgz", + "integrity": "sha512-D183TDwpsd9Zl56UmItsl3RzHdN25srAISfg6lc3A8mEKkEgOq0s7ZzRAYcx8DHsAkMgtZqjIPEvMifD3DOB/g==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": ">=17.0.0 <18.0.0", - "@angular/core": ">=17.0.0 <18.0.0" + "@angular/common": ">=18.0.0 <19.0.0", + "@angular/core": ">=18.0.0 <19.0.0" } }, "node_modules/ngx-toastr": { @@ -24386,7 +24713,6 @@ "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "!win32" @@ -24401,7 +24727,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "license": "MIT", "optional": true }, "node_modules/no-case": { @@ -24510,7 +24835,6 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", "dev": true, - "license": "MIT", "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", @@ -24541,12 +24865,25 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/node-gyp/node_modules/@npmcli/fs": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, - "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -24559,7 +24896,6 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -24569,7 +24905,6 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -24593,7 +24928,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -24606,7 +24940,6 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16" } @@ -24615,15 +24948,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/node-gyp/node_modules/make-fetch-happen": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -24647,7 +24978,6 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -24660,7 +24990,6 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, - "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -24678,7 +25007,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, - "license": "ISC", "dependencies": { "abbrev": "^2.0.0" }, @@ -24694,7 +25022,6 @@ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -24704,7 +25031,6 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -24717,7 +25043,6 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -24730,7 +25055,6 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -24743,7 +25067,6 @@ "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -24810,7 +25133,6 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", @@ -24825,7 +25147,6 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -24837,8 +25158,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", @@ -24878,7 +25198,6 @@ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.1.tgz", "integrity": "sha512-+AvaheE/ww1JEwRHOrn4WHNzOxGtVp+adrg2AeZS/7KuxGUYFuBta98wYpfHBbJp6Tg6j1NKSEVHNcfZzJHQwQ==", "dev": true, - "license": "ISC", "dependencies": { "npm-normalize-package-bin": "^3.0.0" }, @@ -24891,7 +25210,6 @@ "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "semver": "^7.1.1" }, @@ -24904,20 +25222,18 @@ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", "dev": true, - "license": "ISC", "dependencies": { "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^5.0.0" }, @@ -24930,7 +25246,6 @@ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, - "license": "ISC", "dependencies": { "lru-cache": "^10.0.1" }, @@ -24942,15 +25257,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/npm-package-arg/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -24960,7 +25273,6 @@ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, - "license": "ISC", "dependencies": { "ignore-walk": "^6.0.4" }, @@ -24969,11 +25281,10 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", - "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, - "license": "ISC", "dependencies": { "npm-install-checks": "^6.0.0", "npm-normalize-package-bin": "^3.0.0", @@ -24985,17 +25296,16 @@ } }, "node_modules/npm-registry-fetch": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", - "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.1.0.tgz", + "integrity": "sha512-5+bKQRH0J1xG1uZ1zMNvxW0VEyoNWgJpY9UDuluPFLKDfJ9u2JmmjmTJV1srBGQOROfdBMiVvnH2Zvpbm+xkVA==", "dev": true, - "license": "ISC", "dependencies": { - "@npmcli/redact": "^1.1.0", + "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", "proc-log": "^4.0.0" @@ -25009,7 +25319,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, - "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -25022,7 +25331,6 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -25046,7 +25354,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -25058,15 +25365,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -25090,7 +25395,6 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -25103,7 +25407,6 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, - "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -25121,7 +25424,6 @@ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -25131,7 +25433,6 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -25144,7 +25445,6 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -25157,7 +25457,6 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -25456,6 +25755,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ordered-binary": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.3.tgz", + "integrity": "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==", + "dev": true + }, "node_modules/os-name": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/os-name/-/os-name-4.0.1.tgz", @@ -25603,33 +25908,31 @@ "license": "BlueOak-1.0.0" }, "node_modules/pacote": { - "version": "17.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", - "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.6.tgz", + "integrity": "sha512-+eK3G27SMwsB8kLIuj4h1FUhHtwiEUo21Tw8wNjmvdlpOEr613edv+8FUsTj/4F/VN5ywGE19X18N7CC2EJk6A==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.0", "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", + "@npmcli/run-script": "^8.0.0", "cacache": "^18.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^11.0.0", "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "npm-registry-fetch": "^17.0.0", + "proc-log": "^4.0.0", "promise-retry": "^2.0.1", - "read-package-json": "^7.0.0", - "read-package-json-fast": "^3.0.0", "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, "bin": { - "pacote": "lib/bin.js" + "pacote": "bin/index.js" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -25640,7 +25943,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, - "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -25653,7 +25955,6 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -25677,7 +25978,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -25689,15 +25989,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/pacote/node_modules/minipass-collect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -25706,11 +26004,10 @@ } }, "node_modules/pacote/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -25720,7 +26017,6 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -25733,7 +26029,6 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -25746,7 +26041,6 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -26157,11 +26451,10 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", - "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -26202,11 +26495,10 @@ } }, "node_modules/piscina": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.4.0.tgz", - "integrity": "sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", + "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, - "license": "MIT", "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -26582,8 +26874,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", @@ -27318,37 +27609,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/read-package-json": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.1.tgz", - "integrity": "sha512-8PcDiZ8DXUjLf687Ol4BR8Bpm2umR7vhoZOzNRt+uxD9GpBh/K+CAAALVIiYFknmvlmyg7hM7BSNUXPaCCqd0Q==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -28947,7 +29207,6 @@ "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.3.1.tgz", "integrity": "sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^2.3.2", "@sigstore/core": "^1.0.0", @@ -29183,7 +29442,6 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -29193,15 +29451,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" + "dev": true }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -29211,8 +29467,7 @@ "version": "3.0.20", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", - "dev": true, - "license": "CC0-1.0" + "dev": true }, "node_modules/spdy": { "version": "4.0.2", @@ -29264,7 +29519,8 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/ssri": { "version": "9.0.1", @@ -29975,11 +30231,10 @@ } }, "node_modules/terser": { - "version": "5.29.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", - "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -30125,6 +30380,7 @@ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -30140,6 +30396,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -30152,6 +30409,7 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -30173,6 +30431,7 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -30264,19 +30523,6 @@ "node": ">=12.0.0" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tinyrainbow": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", @@ -30652,10 +30898,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "license": "0BSD" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/tsscmp": { "version": "1.0.6", @@ -30713,7 +30958,6 @@ "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.1.tgz", "integrity": "sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==", "dev": true, - "license": "MIT", "dependencies": { "@tufjs/models": "2.0.1", "debug": "^4.3.4", @@ -30728,7 +30972,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, - "license": "ISC", "dependencies": { "semver": "^7.3.5" }, @@ -30741,7 +30984,6 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -30765,7 +31007,6 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -30777,15 +31018,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/tuf-js/node_modules/make-fetch-happen": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dev": true, - "license": "ISC", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -30809,7 +31048,6 @@ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -30822,7 +31060,6 @@ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dev": true, - "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -30840,7 +31077,6 @@ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -30850,7 +31086,6 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dev": true, - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -30863,7 +31098,6 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", "dev": true, - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -30876,7 +31110,6 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -31202,16 +31435,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undici": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.11.1.tgz", - "integrity": "sha512-KyhzaLJnV1qa3BSHdj4AZ2ndqI0QWPxYzaIOio0WzcEJB9gvuysprJSLtpvc2D9mhR9jPDUk7xlJlZbH2KR5iw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0" - } - }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", @@ -31604,7 +31827,6 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -31615,7 +31837,6 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", "dev": true, - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -31691,15 +31912,14 @@ } }, "node_modules/vite": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.8.tgz", - "integrity": "sha512-mB8ToUuSmzODSpENgvpFk2fTiU/YQ1tmcVJJ4WZbq4fPdGJkFNVcmVL5k7iDug6xzWjjuGDKAuSievIsD6H7Xw==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, - "license": "MIT", "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -31718,6 +31938,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -31735,6 +31956,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -31747,14 +31971,13 @@ } }, "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -31764,12 +31987,11 @@ } }, "node_modules/vite/node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -31777,29 +31999,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/w3c-xmlserializer": { @@ -31841,23 +32063,11 @@ "dev": true, "license": "ISC" }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, - "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -31871,7 +32081,6 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -31880,16 +32089,20 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "license": "BSD-2-Clause", "engines": { "node": ">=12" } @@ -31899,7 +32112,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, - "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -31946,7 +32158,6 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, - "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", @@ -31999,32 +32210,15 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" } }, - "node_modules/webpack-cli/node_modules/webpack-merge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/webpack-dev-middleware": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz", - "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.3.tgz", + "integrity": "sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.12", @@ -32053,7 +32247,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz", "integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -32110,7 +32303,6 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -32123,7 +32315,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" } @@ -32133,7 +32324,6 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -32145,11 +32335,10 @@ } }, "node_modules/webpack-dev-server/node_modules/memfs": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.15.0.tgz", - "integrity": "sha512-q9MmZXd2rRWHS6GU3WEm3HyiXZyyoA1DqdOhEq0lxPBmKb5S7IAOwX0RgUCwJfqjelDCySa5h8ujOy24LqsWcw==", + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.15.3.tgz", + "integrity": "sha512-vR/g1SgqvKJgAyYla+06G4p/EOcEmwhYuVb1yc1ixcKf8o/sh7Zngv63957ZSNd1xrZJoinmNyDf2LzuP8WJXw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", @@ -32226,18 +32415,17 @@ } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, - "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-node-externals": { @@ -32294,7 +32482,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -32311,7 +32498,6 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, - "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -32368,7 +32554,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -32384,8 +32569,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.3.0", @@ -32826,6 +33010,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zip-stream": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", diff --git a/package.json b/package.json index 843e9f34bb6..9922b6d7bac 100644 --- a/package.json +++ b/package.json @@ -35,20 +35,20 @@ "libs/*" ], "devDependencies": { - "@angular-devkit/build-angular": "17.3.11", - "@angular-eslint/eslint-plugin": "17.5.3", - "@angular-eslint/eslint-plugin-template": "17.5.3", - "@angular-eslint/schematics": "17.5.3", - "@angular-eslint/template-parser": "17.5.3", - "@angular/cli": "17.3.11", - "@angular/compiler-cli": "17.3.12", - "@angular/elements": "17.3.12", + "@angular-devkit/build-angular": "18.2.12", + "@angular-eslint/eslint-plugin": "18.4.3", + "@angular-eslint/eslint-plugin-template": "18.4.3", + "@angular-eslint/schematics": "18.4.3", + "@angular-eslint/template-parser": "18.4.3", + "@angular/cli": "18.2.12", + "@angular/compiler-cli": "18.2.13", + "@angular/elements": "18.2.13", "@babel/core": "7.24.9", "@babel/preset-env": "7.24.8", "@compodoc/compodoc": "1.1.26", "@electron/notarize": "2.5.0", "@electron/rebuild": "3.7.1", - "@ngtools/webpack": "17.3.11", + "@ngtools/webpack": "18.2.12", "@storybook/addon-a11y": "8.4.7", "@storybook/addon-actions": "8.4.7", "@storybook/addon-designs": "8.0.4", @@ -145,22 +145,22 @@ "webpack-node-externals": "3.0.0" }, "dependencies": { - "@angular/animations": "17.3.12", - "@angular/cdk": "17.3.10", - "@angular/common": "17.3.12", - "@angular/compiler": "17.3.12", - "@angular/core": "17.3.12", - "@angular/forms": "17.3.12", - "@angular/platform-browser": "17.3.12", - "@angular/platform-browser-dynamic": "17.3.12", - "@angular/router": "17.3.12", + "@angular/animations": "18.2.13", + "@angular/cdk": "18.2.14", + "@angular/common": "18.2.13", + "@angular/compiler": "18.2.13", + "@angular/core": "18.2.13", + "@angular/forms": "18.2.13", + "@angular/platform-browser": "18.2.13", + "@angular/platform-browser-dynamic": "18.2.13", + "@angular/router": "18.2.13", "@bitwarden/sdk-internal": "0.2.0-main.38", "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "13.1.0", "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", - "@ng-select/ng-select": "12.0.7", + "@ng-select/ng-select": "13.9.1", "argon2": "0.41.1", "argon2-browser": "1.18.0", "big-integer": "1.6.52", @@ -183,7 +183,7 @@ "lowdb": "1.0.0", "lunr": "2.3.9", "multer": "1.4.5-lts.1", - "ngx-infinite-scroll": "17.0.1", + "ngx-infinite-scroll": "18.0.0", "ngx-toastr": "19.0.0", "node-fetch": "2.6.12", "node-forge": "1.3.1", From 26f086368b23f57925ecad244d659b5aa0f760dd Mon Sep 17 00:00:00 2001 From: Alec Rippberger <127791530+alec-livefront@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:01:56 -0600 Subject: [PATCH 11/18] fix(auth): [PM-15987] improve email/master password entry back/forward navigation - Fix back button behavior in Safari to reliably return to email entry screen - Enable browser forward button after navigating back to email entry - Move email validation to input event instead of blur - Add continueClicked function to differentiate user clicks vs browser navigation - Add email verification gate to SSO route - Enhance master password validation logic - Fix strict typing errors Resolves PM-15987 --- .../src/angular/login/login.component.html | 37 +---- .../auth/src/angular/login/login.component.ts | 140 ++++++++++++------ 2 files changed, 102 insertions(+), 75 deletions(-) diff --git a/libs/auth/src/angular/login/login.component.html b/libs/auth/src/angular/login/login.component.html index 54a04d3de6c..c7837db74f2 100644 --- a/libs/auth/src/angular/login/login.component.html +++ b/libs/auth/src/angular/login/login.component.html @@ -20,8 +20,8 @@ formControlName="email" bitInput appAutofocus - (blur)="onEmailBlur($event)" - (keyup.enter)="continue()" + (input)="onEmailInput($event)" + (keyup.enter)="continuePressed()" /> @@ -33,7 +33,7 @@
- @@ -54,33 +54,10 @@ - - - - {{ "useSingleSignOn" | i18n }} - - - - - +
diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index 33c167dcaed..40f85e6d75c 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { CommonModule } from "@angular/common"; import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from "@angular/core"; import { FormBuilder, FormControl, ReactiveFormsModule, Validators } from "@angular/forms"; @@ -12,7 +10,6 @@ import { LoginStrategyServiceAbstraction, LoginSuccessHandlerService, PasswordLoginCredentials, - RegisterRouteService, } from "@bitwarden/auth/common"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; @@ -72,16 +69,15 @@ export enum LoginUiState { ], }) export class LoginComponent implements OnInit, OnDestroy { - @ViewChild("masterPasswordInputRef") masterPasswordInputRef: ElementRef; + @ViewChild("masterPasswordInputRef") masterPasswordInputRef: ElementRef | undefined; private destroy$ = new Subject(); - private enforcedMasterPasswordOptions: MasterPasswordPolicyOptions = undefined; + private enforcedMasterPasswordOptions: MasterPasswordPolicyOptions | undefined = undefined; readonly Icons = { WaveIcon, VaultIcon }; clientType: ClientType; ClientType = ClientType; LoginUiState = LoginUiState; - registerRoute$ = this.registerRouteService.registerRoute$(); // TODO: remove when email verification flag is removed isKnownDevice = false; loginUiState: LoginUiState = LoginUiState.EMAIL_ENTRY; @@ -97,13 +93,13 @@ export class LoginComponent implements OnInit, OnDestroy { { updateOn: "submit" }, ); - get emailFormControl(): FormControl { + get emailFormControl(): FormControl { return this.formGroup.controls.email; } // Web properties - enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions; - policies: Policy[]; + enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions | undefined; + policies: Policy[] | undefined; showResetPasswordAutoEnrollWarning = false; // Desktop properties @@ -125,7 +121,6 @@ export class LoginComponent implements OnInit, OnDestroy { private passwordStrengthService: PasswordStrengthServiceAbstraction, private platformUtilsService: PlatformUtilsService, private policyService: InternalPolicyService, - private registerRouteService: RegisterRouteService, private router: Router, private toastService: ToastService, private logService: LogService, @@ -200,12 +195,12 @@ export class LoginComponent implements OnInit, OnDestroy { return; } - const credentials = new PasswordLoginCredentials( - email, - masterPassword, - null, // captcha no longer used in new login / registration scenarios - null, - ); + if (!email || !masterPassword) { + this.logService.error("Email and master password are required"); + return; + } + + const credentials = new PasswordLoginCredentials(email, masterPassword); try { const authResult = await this.loginStrategyService.logIn(credentials); @@ -301,7 +296,12 @@ export class LoginComponent implements OnInit, OnDestroy { } protected async launchSsoBrowserWindow(clientId: "browser" | "desktop"): Promise { - await this.loginComponentService.launchSsoBrowserWindow(this.emailFormControl.value, clientId); + const email = this.emailFormControl.value; + if (!email) { + this.logService.error("Email is required for SSO login"); + return; + } + await this.loginComponentService.launchSsoBrowserWindow(email, clientId); } protected async evaluatePassword(): Promise { @@ -337,9 +337,14 @@ export class LoginComponent implements OnInit, OnDestroy { const masterPassword = this.formGroup.controls.masterPassword.value; + // Return false if masterPassword is null/undefined since this is only evaluated after successful login + if (!masterPassword) { + return false; + } + const passwordStrength = this.passwordStrengthService.getPasswordStrength( masterPassword, - this.formGroup.value.email, + this.formGroup.value.email ?? undefined, )?.score; return !this.policyService.evaluateMasterPassword( @@ -363,6 +368,7 @@ export class LoginComponent implements OnInit, OnDestroy { protected async validateEmail(): Promise { this.formGroup.controls.email.markAsTouched(); + this.formGroup.controls.email.updateValueAndValidity({ onlySelf: true, emitEvent: true }); return this.formGroup.controls.email.valid; } @@ -404,7 +410,10 @@ export class LoginComponent implements OnInit, OnDestroy { } // Check to see if the device is known so we can show the Login with Device option - await this.getKnownDevice(this.emailFormControl.value); + const email = this.emailFormControl.value; + if (email) { + await this.getKnownDevice(email); + } } } @@ -412,11 +421,10 @@ export class LoginComponent implements OnInit, OnDestroy { * Set the email value from the input field. * @param event The event object from the input field. */ - onEmailBlur(event: Event) { + onEmailInput(event: Event) { const emailInput = event.target as HTMLInputElement; this.formGroup.controls.email.setValue(emailInput.value); - // Call setLoginEmail so that the email is pre-populated when navigating to the "enter password" screen. - this.loginEmailService.setLoginEmail(this.formGroup.value.email); + this.loginEmailService.setLoginEmail(emailInput.value); } isLoginWithPasskeySupported() { @@ -428,28 +436,36 @@ export class LoginComponent implements OnInit, OnDestroy { await this.router.navigateByUrl("/hint"); } - protected async goToRegister(): Promise { - // TODO: remove when email verification flag is removed - const registerRoute = await firstValueFrom(this.registerRoute$); - - if (this.emailFormControl.valid) { - await this.router.navigate([registerRoute], { - queryParams: { email: this.emailFormControl.value }, - }); + protected async saveEmailSettings(): Promise { + const email = this.formGroup.value.email; + if (!email) { + this.logService.error("Email is required to save email settings."); return; } - await this.router.navigate([registerRoute]); + await this.loginEmailService.setLoginEmail(email); + this.loginEmailService.setRememberEmail(this.formGroup.value.rememberEmail ?? false); + await this.loginEmailService.saveEmailSettings(); } - protected async saveEmailSettings(): Promise { - await this.loginEmailService.setLoginEmail(this.formGroup.value.email); - this.loginEmailService.setRememberEmail(this.formGroup.value.rememberEmail); - await this.loginEmailService.saveEmailSettings(); + /** + * Continue button clicked (or enter key pressed). + * Adds the login url to the browser's history so that the back button can be used to go back to the email entry state. + * Needs to be separate from the continue() function because that can be triggered by the browser's forward button. + */ + protected async continuePressed() { + // Add a new entry to the browser's history so that there is a history entry to go back to + history.pushState({}, "", window.location.href); + await this.continue(); } + /** + * Continue to the master password entry state (only if email is validated) + */ protected async continue(): Promise { - if (await this.validateEmail()) { + const isEmailValid = await this.validateEmail(); + + if (isEmailValid) { await this.toggleLoginUiState(LoginUiState.MASTER_PASSWORD_ENTRY); } } @@ -460,6 +476,11 @@ export class LoginComponent implements OnInit, OnDestroy { * @param email - The user's email */ private async getKnownDevice(email: string): Promise { + if (!email) { + this.isKnownDevice = false; + return; + } + try { const deviceIdentifier = await this.appIdService.getAppId(); this.isKnownDevice = await this.devicesApiService.getKnownDevice(email, deviceIdentifier); @@ -503,7 +524,7 @@ export class LoginComponent implements OnInit, OnDestroy { const orgPolicies = await this.loginComponentService.getOrgPolicies(); this.policies = orgPolicies?.policies; - this.showResetPasswordAutoEnrollWarning = orgPolicies?.isPolicyAndAutoEnrollEnabled; + this.showResetPasswordAutoEnrollWarning = orgPolicies?.isPolicyAndAutoEnrollEnabled ?? false; let paramEmailIsSet = false; @@ -525,7 +546,9 @@ export class LoginComponent implements OnInit, OnDestroy { } // Check to see if the device is known so that we can show the Login with Device option - await this.getKnownDevice(this.emailFormControl.value); + if (this.emailFormControl.value) { + await this.getKnownDevice(this.emailFormControl.value); + } // Backup check to handle unknown case where activatedRoute is not available // This shouldn't happen under normal circumstances @@ -573,23 +596,50 @@ export class LoginComponent implements OnInit, OnDestroy { * Handle the back button click to transition back to the email entry state. */ protected async backButtonClicked() { - // Replace the history so the "forward" button doesn't show (which wouldn't do anything) - history.pushState(null, "", window.location.pathname); - await this.toggleLoginUiState(LoginUiState.EMAIL_ENTRY); + history.back(); } /** * Handle the popstate event to transition back to the email entry state when the back button is clicked. + * Also handles the case where the user clicks the forward button. * @param event - The popstate event. */ - private handlePopState = (event: PopStateEvent) => { + private handlePopState = async (event: PopStateEvent) => { if (this.loginUiState === LoginUiState.MASTER_PASSWORD_ENTRY) { - // Prevent default navigation + // Prevent default navigation when the browser's back button is clicked event.preventDefault(); - // Replace the history so the "forward" button doesn't show (which wouldn't do anything) - history.pushState(null, "", window.location.pathname); // Transition back to email entry state void this.toggleLoginUiState(LoginUiState.EMAIL_ENTRY); + } else if (this.loginUiState === LoginUiState.EMAIL_ENTRY) { + // Prevent default navigation when the browser's forward button is clicked + event.preventDefault(); + // Continue to the master password entry state + await this.continue(); } }; + + /** + * Handle the SSO button click. + * @param event - The event object. + */ + async handleSsoClick() { + const isEmailValid = await this.validateEmail(); + + if (!isEmailValid) { + return; + } + + await this.saveEmailSettings(); + + if (this.clientType === ClientType.Web) { + await this.router.navigate(["/sso"], { + queryParams: { email: this.formGroup.value.email }, + }); + return; + } + + await this.launchSsoBrowserWindow( + this.clientType === ClientType.Browser ? "browser" : "desktop", + ); + } } From 6aa5b1b953f30fd3dc54bfd424f5558ea15f7dc9 Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:14:16 +0100 Subject: [PATCH 12/18] [PM-7105][PM-7242][PM-16256] Remove v1 code for Tab/Vault Part 2 (#12516) * Remove v1 code for Tab/Vault Part 2 * Removal conditional for assign-collections --------- Co-authored-by: Daniel James Smith --- apps/browser/src/popup/app-routing.module.ts | 89 +- apps/browser/src/popup/app.module.ts | 38 - .../vault/guards/clear-vault-state.guard.ts | 2 +- .../components/action-buttons.component.html | 102 --- .../components/action-buttons.component.ts | 108 --- .../components/cipher-row.component.html | 51 -- .../popup/components/cipher-row.component.ts | 31 - .../vault-v2.component.html | 0 .../{vault => vault-v2}/vault-v2.component.ts | 8 +- .../add-edit-custom-fields.component.html | 140 --- .../vault/add-edit-custom-fields.component.ts | 15 - .../components/vault/add-edit.component.html | 826 ------------------ .../components/vault/add-edit.component.ts | 417 --------- .../vault/attachments.component.html | 72 -- .../components/vault/attachments.component.ts | 82 -- .../vault/collections.component.html | 43 - .../components/vault/collections.component.ts | 61 -- .../vault/current-tab.component.html | 95 -- .../components/vault/current-tab.component.ts | 354 -------- .../vault/password-history.component.html | 40 - .../vault/password-history.component.ts | 44 - .../components/vault/share.component.html | 77 -- .../popup/components/vault/share.component.ts | 72 -- .../vault/vault-filter.component.html | 238 ----- .../vault/vault-filter.component.ts | 482 ---------- .../vault/vault-items.component.html | 123 --- .../components/vault/vault-items.component.ts | 316 ------- .../vault/vault-select.component.html | 82 -- .../vault/vault-select.component.ts | 227 ----- .../vault/view-custom-fields.component.html | 98 --- .../vault/view-custom-fields.component.ts | 14 - .../components/vault/view.component.html | 719 --------------- .../popup/components/vault/view.component.ts | 443 ---------- .../popup/settings/appearance.component.html | 80 -- .../popup/settings/appearance.component.ts | 75 -- .../settings/folder-add-edit.component.html | 49 -- .../settings/folder-add-edit.component.ts | 78 -- .../popup/settings/folders.component.html | 38 - .../vault/popup/settings/folders.component.ts | 48 - .../vault/popup/settings/sync.component.html | 35 - .../vault/popup/settings/sync.component.ts | 46 - .../settings/vault-settings.component.html | 56 -- .../settings/vault-settings.component.ts | 25 - 43 files changed, 31 insertions(+), 6008 deletions(-) delete mode 100644 apps/browser/src/vault/popup/components/action-buttons.component.html delete mode 100644 apps/browser/src/vault/popup/components/action-buttons.component.ts delete mode 100644 apps/browser/src/vault/popup/components/cipher-row.component.html delete mode 100644 apps/browser/src/vault/popup/components/cipher-row.component.ts rename apps/browser/src/vault/popup/components/{vault => vault-v2}/vault-v2.component.html (100%) rename apps/browser/src/vault/popup/components/{vault => vault-v2}/vault-v2.component.ts (95%) delete mode 100644 apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/add-edit.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/add-edit.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/attachments.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/attachments.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/collections.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/collections.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/current-tab.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/current-tab.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/password-history.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/password-history.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/share.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/share.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/vault-filter.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/vault-filter.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/vault-items.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/vault-items.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/vault-select.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/vault-select.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/view-custom-fields.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/view-custom-fields.component.ts delete mode 100644 apps/browser/src/vault/popup/components/vault/view.component.html delete mode 100644 apps/browser/src/vault/popup/components/vault/view.component.ts delete mode 100644 apps/browser/src/vault/popup/settings/appearance.component.html delete mode 100644 apps/browser/src/vault/popup/settings/appearance.component.ts delete mode 100644 apps/browser/src/vault/popup/settings/folder-add-edit.component.html delete mode 100644 apps/browser/src/vault/popup/settings/folder-add-edit.component.ts delete mode 100644 apps/browser/src/vault/popup/settings/folders.component.html delete mode 100644 apps/browser/src/vault/popup/settings/folders.component.ts delete mode 100644 apps/browser/src/vault/popup/settings/sync.component.html delete mode 100644 apps/browser/src/vault/popup/settings/sync.component.ts delete mode 100644 apps/browser/src/vault/popup/settings/vault-settings.component.html delete mode 100644 apps/browser/src/vault/popup/settings/vault-settings.component.ts diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 49d680cd752..161c4ca0524 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -93,28 +93,16 @@ import { ExportBrowserV2Component } from "../tools/popup/settings/export/export- import { ImportBrowserV2Component } from "../tools/popup/settings/import/import-browser-v2.component"; import { SettingsV2Component } from "../tools/popup/settings/settings-v2.component"; import { clearVaultStateGuard } from "../vault/guards/clear-vault-state.guard"; -import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component"; -import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component"; -import { CollectionsComponent } from "../vault/popup/components/vault/collections.component"; -import { PasswordHistoryComponent } from "../vault/popup/components/vault/password-history.component"; -import { ShareComponent } from "../vault/popup/components/vault/share.component"; -import { VaultItemsComponent } from "../vault/popup/components/vault/vault-items.component"; -import { VaultV2Component } from "../vault/popup/components/vault/vault-v2.component"; -import { ViewComponent } from "../vault/popup/components/vault/view.component"; import { AddEditV2Component } from "../vault/popup/components/vault-v2/add-edit/add-edit-v2.component"; import { AssignCollections } from "../vault/popup/components/vault-v2/assign-collections/assign-collections.component"; import { AttachmentsV2Component } from "../vault/popup/components/vault-v2/attachments/attachments-v2.component"; import { PasswordHistoryV2Component } from "../vault/popup/components/vault-v2/vault-password-history-v2/vault-password-history-v2.component"; +import { VaultV2Component } from "../vault/popup/components/vault-v2/vault-v2.component"; import { ViewV2Component } from "../vault/popup/components/vault-v2/view-v2/view-v2.component"; import { AppearanceV2Component } from "../vault/popup/settings/appearance-v2.component"; -import { AppearanceComponent } from "../vault/popup/settings/appearance.component"; -import { FolderAddEditComponent } from "../vault/popup/settings/folder-add-edit.component"; import { FoldersV2Component } from "../vault/popup/settings/folders-v2.component"; -import { FoldersComponent } from "../vault/popup/settings/folders.component"; -import { SyncComponent } from "../vault/popup/settings/sync.component"; import { TrashComponent } from "../vault/popup/settings/trash.component"; import { VaultSettingsV2Component } from "../vault/popup/settings/vault-settings-v2.component"; -import { VaultSettingsComponent } from "../vault/popup/settings/vault-settings.component"; import { RouteElevation } from "./app-routing.animations"; import { debounceNavigationGuard } from "./services/debounce-navigation.service"; @@ -271,56 +259,43 @@ const routes: Routes = [ data: { elevation: 1 } satisfies RouteDataProperties, }, { - path: "ciphers", - component: VaultItemsComponent, - canActivate: [authGuard], - data: { elevation: 1 } satisfies RouteDataProperties, - }, - ...extensionRefreshSwap(ViewComponent, ViewV2Component, { path: "view-cipher", + component: ViewV2Component, canActivate: [authGuard], data: { // Above "trash" elevation: 3, } satisfies RouteDataProperties, - }), - ...extensionRefreshSwap(PasswordHistoryComponent, PasswordHistoryV2Component, { + }, + { path: "cipher-password-history", + component: PasswordHistoryV2Component, canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, - }), - ...extensionRefreshSwap(AddEditComponent, AddEditV2Component, { + }, + { path: "add-cipher", + component: AddEditV2Component, canActivate: [authGuard, debounceNavigationGuard()], data: { elevation: 1 } satisfies RouteDataProperties, runGuardsAndResolvers: "always", - }), - ...extensionRefreshSwap(AddEditComponent, AddEditV2Component, { + }, + { path: "edit-cipher", + component: AddEditV2Component, canActivate: [authGuard, debounceNavigationGuard()], data: { // Above "trash" elevation: 3, } satisfies RouteDataProperties, runGuardsAndResolvers: "always", - }), - { - path: "share-cipher", - component: ShareComponent, - canActivate: [authGuard], - data: { elevation: 1 } satisfies RouteDataProperties, }, { - path: "collections", - component: CollectionsComponent, - canActivate: [authGuard], - data: { elevation: 1 } satisfies RouteDataProperties, - }, - ...extensionRefreshSwap(AttachmentsComponent, AttachmentsV2Component, { path: "attachments", + component: AttachmentsV2Component, canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, - }), + }, { path: "generator", component: CredentialGeneratorComponent, @@ -361,33 +336,17 @@ const routes: Routes = [ canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }), - ...extensionRefreshSwap(VaultSettingsComponent, VaultSettingsV2Component, { - path: "vault-settings", - canActivate: [authGuard], - data: { elevation: 1 } satisfies RouteDataProperties, - }), - ...extensionRefreshSwap(FoldersComponent, FoldersV2Component, { - path: "folders", - canActivate: [authGuard], - data: { elevation: 2 } satisfies RouteDataProperties, - }), - { - path: "add-folder", - component: FolderAddEditComponent, - canActivate: [authGuard], - data: { elevation: 1 } satisfies RouteDataProperties, - }, { - path: "edit-folder", - component: FolderAddEditComponent, + path: "vault-settings", + component: VaultSettingsV2Component, canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }, { - path: "sync", - component: SyncComponent, + path: "folders", + component: FoldersV2Component, canActivate: [authGuard], - data: { elevation: 1 } satisfies RouteDataProperties, + data: { elevation: 2 } satisfies RouteDataProperties, }, ...extensionRefreshSwap(ExcludedDomainsV1Component, ExcludedDomainsComponent, { path: "excluded-domains", @@ -400,16 +359,18 @@ const routes: Routes = [ canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }, - ...extensionRefreshSwap(AppearanceComponent, AppearanceV2Component, { + { path: "appearance", + component: AppearanceV2Component, canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, - }), - ...extensionRefreshSwap(AddEditComponent, AddEditV2Component, { + }, + { path: "clone-cipher", + component: AddEditV2Component, canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, - }), + }, { path: "add-send", component: SendAddEditV2Component, @@ -685,7 +646,7 @@ const routes: Routes = [ { path: "assign-collections", component: AssignCollections, - canActivate: [canAccessFeature(FeatureFlag.ExtensionRefresh, true, "/")], + canActivate: [authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }, { diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 83475a661c9..1fe8f1f18db 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -54,25 +54,6 @@ import { PopupHeaderComponent } from "../platform/popup/layout/popup-header.comp import { PopupPageComponent } from "../platform/popup/layout/popup-page.component"; import { PopupTabNavigationComponent } from "../platform/popup/layout/popup-tab-navigation.component"; import { FilePopoutCalloutComponent } from "../tools/popup/components/file-popout-callout.component"; -import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component"; -import { CipherRowComponent } from "../vault/popup/components/cipher-row.component"; -import { AddEditCustomFieldsComponent } from "../vault/popup/components/vault/add-edit-custom-fields.component"; -import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component"; -import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component"; -import { CollectionsComponent } from "../vault/popup/components/vault/collections.component"; -import { CurrentTabComponent } from "../vault/popup/components/vault/current-tab.component"; -import { PasswordHistoryComponent } from "../vault/popup/components/vault/password-history.component"; -import { ShareComponent } from "../vault/popup/components/vault/share.component"; -import { VaultFilterComponent } from "../vault/popup/components/vault/vault-filter.component"; -import { VaultItemsComponent } from "../vault/popup/components/vault/vault-items.component"; -import { VaultSelectComponent } from "../vault/popup/components/vault/vault-select.component"; -import { ViewCustomFieldsComponent } from "../vault/popup/components/vault/view-custom-fields.component"; -import { ViewComponent } from "../vault/popup/components/vault/view.component"; -import { AppearanceComponent } from "../vault/popup/settings/appearance.component"; -import { FolderAddEditComponent } from "../vault/popup/settings/folder-add-edit.component"; -import { FoldersComponent } from "../vault/popup/settings/folders.component"; -import { SyncComponent } from "../vault/popup/settings/sync.component"; -import { VaultSettingsComponent } from "../vault/popup/settings/vault-settings.component"; import { AppRoutingModule } from "./app-routing.module"; import { AppComponent } from "./app.component"; @@ -127,48 +108,29 @@ import "../platform/popup/locales"; ExtensionAnonLayoutWrapperComponent, ], declarations: [ - ActionButtonsComponent, - AddEditComponent, - AddEditCustomFieldsComponent, AppComponent, - AttachmentsComponent, - CipherRowComponent, - VaultItemsComponent, - CollectionsComponent, ColorPasswordPipe, ColorPasswordCountPipe, - CurrentTabComponent, EnvironmentComponent, ExcludedDomainsV1Component, Fido2CipherRowV1Component, Fido2UseBrowserLinkV1Component, - FolderAddEditComponent, - FoldersComponent, - VaultFilterComponent, HintComponent, HomeComponent, LoginViaAuthRequestComponentV1, LoginComponentV1, LoginDecryptionOptionsComponentV1, NotificationsSettingsV1Component, - AppearanceComponent, - PasswordHistoryComponent, RegisterComponent, SetPasswordComponent, - VaultSettingsComponent, - ShareComponent, SsoComponentV1, - SyncComponent, TabsV2Component, TwoFactorComponent, TwoFactorOptionsComponent, UpdateTempPasswordComponent, UserVerificationComponent, VaultTimeoutInputComponent, - ViewComponent, - ViewCustomFieldsComponent, RemovePasswordComponent, - VaultSelectComponent, Fido2V1Component, AutofillV1Component, EnvironmentSelectorComponent, diff --git a/apps/browser/src/vault/guards/clear-vault-state.guard.ts b/apps/browser/src/vault/guards/clear-vault-state.guard.ts index 2b43f1ecbd3..b212c55d833 100644 --- a/apps/browser/src/vault/guards/clear-vault-state.guard.ts +++ b/apps/browser/src/vault/guards/clear-vault-state.guard.ts @@ -1,7 +1,7 @@ import { inject } from "@angular/core"; import { CanDeactivateFn } from "@angular/router"; -import { VaultV2Component } from "../popup/components/vault/vault-v2.component"; +import { VaultV2Component } from "../popup/components/vault-v2/vault-v2.component"; import { VaultPopupItemsService } from "../popup/services/vault-popup-items.service"; import { VaultPopupListFiltersService } from "../popup/services/vault-popup-list-filters.service"; diff --git a/apps/browser/src/vault/popup/components/action-buttons.component.html b/apps/browser/src/vault/popup/components/action-buttons.component.html deleted file mode 100644 index f63c1f1ac32..00000000000 --- a/apps/browser/src/vault/popup/components/action-buttons.component.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - diff --git a/apps/browser/src/vault/popup/components/action-buttons.component.ts b/apps/browser/src/vault/popup/components/action-buttons.component.ts deleted file mode 100644 index fd559aca817..00000000000 --- a/apps/browser/src/vault/popup/components/action-buttons.component.ts +++ /dev/null @@ -1,108 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core"; -import { Subject, takeUntil } from "rxjs"; - -import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; -import { EventType } from "@bitwarden/common/enums"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { PasswordRepromptService } from "@bitwarden/vault"; - -@Component({ - selector: "app-action-buttons", - templateUrl: "action-buttons.component.html", -}) -export class ActionButtonsComponent implements OnInit, OnDestroy { - @Output() onView = new EventEmitter(); - @Output() launchEvent = new EventEmitter(); - @Input() cipher: CipherView; - @Input() showView = false; - - cipherType = CipherType; - userHasPremiumAccess = false; - - private componentIsDestroyed$ = new Subject(); - - constructor( - private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, - private eventCollectionService: EventCollectionService, - private totpService: TotpServiceAbstraction, - private passwordRepromptService: PasswordRepromptService, - private billingAccountProfileStateService: BillingAccountProfileStateService, - ) {} - - ngOnInit() { - this.billingAccountProfileStateService.hasPremiumFromAnySource$ - .pipe(takeUntil(this.componentIsDestroyed$)) - .subscribe((canAccessPremium: boolean) => { - this.userHasPremiumAccess = canAccessPremium; - }); - } - - ngOnDestroy() { - this.componentIsDestroyed$.next(true); - this.componentIsDestroyed$.complete(); - } - - launchCipher() { - this.launchEvent.emit(this.cipher); - } - - async copy(cipher: CipherView, value: string, typeI18nKey: string, aType: string) { - if ( - this.cipher.reprompt !== CipherRepromptType.None && - this.passwordRepromptService.protectedFields().includes(aType) && - !(await this.passwordRepromptService.showPasswordPrompt()) - ) { - return; - } - - if (value == null || (aType === "TOTP" && !this.displayTotpCopyButton(cipher))) { - return; - } else if (aType === "TOTP") { - value = await this.totpService.getCode(value); - } - - if (!cipher.viewPassword) { - return; - } - - this.platformUtilsService.copyToClipboard(value, { window: window }); - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)), - ); - - if (typeI18nKey === "password") { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.eventCollectionService.collect(EventType.Cipher_ClientCopiedPassword, cipher.id); - } else if (typeI18nKey === "verificationCodeTotp") { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.eventCollectionService.collect(EventType.Cipher_ClientCopiedHiddenField, cipher.id); - } else if (typeI18nKey === "securityCode") { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.eventCollectionService.collect(EventType.Cipher_ClientCopiedCardCode, cipher.id); - } - } - - displayTotpCopyButton(cipher: CipherView) { - return ( - (cipher?.login?.hasTotp ?? false) && (cipher.organizationUseTotp || this.userHasPremiumAccess) - ); - } - - view() { - this.onView.emit(this.cipher); - } -} diff --git a/apps/browser/src/vault/popup/components/cipher-row.component.html b/apps/browser/src/vault/popup/components/cipher-row.component.html deleted file mode 100644 index 8ac9147cb92..00000000000 --- a/apps/browser/src/vault/popup/components/cipher-row.component.html +++ /dev/null @@ -1,51 +0,0 @@ -
-
- - - -
-
diff --git a/apps/browser/src/vault/popup/components/cipher-row.component.ts b/apps/browser/src/vault/popup/components/cipher-row.component.ts deleted file mode 100644 index 6b71470a86b..00000000000 --- a/apps/browser/src/vault/popup/components/cipher-row.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Component, EventEmitter, Input, Output } from "@angular/core"; - -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; - -@Component({ - selector: "app-cipher-row", - templateUrl: "cipher-row.component.html", -}) -export class CipherRowComponent { - @Output() onSelected = new EventEmitter(); - @Output() launchEvent = new EventEmitter(); - @Output() onView = new EventEmitter(); - @Input() cipher: CipherView; - @Input() last: boolean; - @Input() showView = false; - @Input() title: string; - - selectCipher(c: CipherView) { - this.onSelected.emit(c); - } - - launchCipher(c: CipherView) { - this.launchEvent.emit(c); - } - - viewCipher(c: CipherView) { - this.onView.emit(c); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/vault-v2.component.html b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.html similarity index 100% rename from apps/browser/src/vault/popup/components/vault/vault-v2.component.html rename to apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.html diff --git a/apps/browser/src/vault/popup/components/vault/vault-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts similarity index 95% rename from apps/browser/src/vault/popup/components/vault/vault-v2.component.ts rename to apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts index 68aa40cbf62..9970c115bb7 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts @@ -18,12 +18,14 @@ import { PopupPageComponent } from "../../../../platform/popup/layout/popup-page import { VaultPopupItemsService } from "../../services/vault-popup-items.service"; import { VaultPopupListFiltersService } from "../../services/vault-popup-list-filters.service"; import { VaultUiOnboardingService } from "../../services/vault-ui-onboarding.service"; -import { AutofillVaultListItemsComponent, VaultListItemsContainerComponent } from "../vault-v2"; + import { NewItemDropdownV2Component, NewItemInitialValues, -} from "../vault-v2/new-item-dropdown/new-item-dropdown-v2.component"; -import { VaultHeaderV2Component } from "../vault-v2/vault-header/vault-header-v2.component"; +} from "./new-item-dropdown/new-item-dropdown-v2.component"; +import { VaultHeaderV2Component } from "./vault-header/vault-header-v2.component"; + +import { AutofillVaultListItemsComponent, VaultListItemsContainerComponent } from "."; enum VaultState { Empty, diff --git a/apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.html b/apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.html deleted file mode 100644 index 8464655c20b..00000000000 --- a/apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.html +++ /dev/null @@ -1,140 +0,0 @@ -
-

- {{ "customFields" | i18n }} -

-
- -
-
- - - -
- - - - - - - -
- - -
- -
-
- -
-
-
- -
- - - -
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.ts b/apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.ts deleted file mode 100644 index 6992455a8a6..00000000000 --- a/apps/browser/src/vault/popup/components/vault/add-edit-custom-fields.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component } from "@angular/core"; - -import { AddEditCustomFieldsComponent as BaseAddEditCustomFieldsComponent } from "@bitwarden/angular/vault/components/add-edit-custom-fields.component"; -import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; - -@Component({ - selector: "app-vault-add-edit-custom-fields", - templateUrl: "add-edit-custom-fields.component.html", -}) -export class AddEditCustomFieldsComponent extends BaseAddEditCustomFieldsComponent { - constructor(i18nService: I18nService, eventCollectionService: EventCollectionService) { - super(i18nService, eventCollectionService); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.html b/apps/browser/src/vault/popup/components/vault/add-edit.component.html deleted file mode 100644 index fb1efbbbd79..00000000000 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.html +++ /dev/null @@ -1,826 +0,0 @@ -
-
-
- -
-

- {{ title }} -

-
- -
-
-
- - {{ "personalOwnershipPolicyInEffect" | i18n }} - -
-

- {{ "itemInformation" | i18n }} -

-
-
- - -
-
- - -
- -
-
-
- - -
-
- -
-
-
-
- - -
-
- - - -
-
- - -
-
-
- -
- {{ "typePasskey" | i18n }} - {{ "dateCreated" | i18n }} - {{ cipher.login.fido2Credentials[0].creationDate | date: "short" }} -
-
-
-
- -
-
- - -
-
- - - -
-
-
- - -
-
- - -
-
-
- - -
-
- -
-
-
- - - - - - - -
-
- - - - - - - -
-
- - -
-
-
- - -
-
- -
-
-
- -
-
- - - - - - - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- {{ "sshPrivateKey" | i18n }} - {{ cipher.sshKey.privateKey }} -
-
- {{ "sshPublicKey" | i18n }} - {{ cipher.sshKey.publicKey }} -
-
- {{ "sshKeyFingerprint" | i18n }} - {{ cipher.sshKey.keyFingerprint }} -
-
-
-
-
-
- -
- -
- - - - - - -
-
- - -
-
-
- -
-
-
-
-
- - -
-
- -
-
-
-
- - -
-
- - -
-
- - -
- - -
-
-
-

- -

-
-
- -
-
-
- - -
-

- {{ "ownership" | i18n }} -

-
-
- - -
-
-
-
-

- {{ "collections" | i18n }} -

-
-
- {{ "noCollectionsInList" | i18n }} -
-
-
-
- - -
-
-
-
-
- -
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts deleted file mode 100644 index 39414217b0d..00000000000 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts +++ /dev/null @@ -1,417 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { DatePipe, Location } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import qrcodeParser from "qrcode-parser"; -import { firstValueFrom } from "rxjs"; -import { first } from "rxjs/operators"; - -import { CollectionService } from "@bitwarden/admin-console/common"; -import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component"; -import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { OrganizationService } 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 { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; -import { normalizeExpiryYearFormat } from "@bitwarden/common/autofill/utils"; -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"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; -import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; -import { DialogService } from "@bitwarden/components"; -import { PasswordRepromptService } from "@bitwarden/vault"; - -import { BrowserFido2UserInterfaceSession } from "../../../../autofill/fido2/services/browser-fido2-user-interface.service"; -import { BrowserApi } from "../../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; -import { PopupCloseWarningService } from "../../../../popup/services/popup-close-warning.service"; -import { Fido2UserVerificationService } from "../../../services/fido2-user-verification.service"; -import { fido2PopoutSessionData$ } from "../../utils/fido2-popout-session-data"; -import { closeAddEditVaultItemPopout, VaultPopoutType } from "../../utils/vault-popout-window"; - -@Component({ - selector: "app-vault-add-edit", - templateUrl: "add-edit.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class AddEditComponent extends BaseAddEditComponent implements OnInit { - currentUris: string[]; - showAttachments = true; - openAttachmentsInPopup: boolean; - showAutoFillOnPageLoadOptions: boolean; - - private fido2PopoutSessionData$ = fido2PopoutSessionData$(); - - constructor( - cipherService: CipherService, - folderService: FolderService, - i18nService: I18nService, - platformUtilsService: PlatformUtilsService, - auditService: AuditService, - accountService: AccountService, - private autofillSettingsService: AutofillSettingsServiceAbstraction, - collectionService: CollectionService, - messagingService: MessagingService, - private route: ActivatedRoute, - private router: Router, - private location: Location, - eventCollectionService: EventCollectionService, - policyService: PolicyService, - private popupCloseWarningService: PopupCloseWarningService, - organizationService: OrganizationService, - passwordRepromptService: PasswordRepromptService, - logService: LogService, - dialogService: DialogService, - datePipe: DatePipe, - configService: ConfigService, - private fido2UserVerificationService: Fido2UserVerificationService, - cipherAuthorizationService: CipherAuthorizationService, - ) { - super( - cipherService, - folderService, - i18nService, - platformUtilsService, - auditService, - accountService, - collectionService, - messagingService, - eventCollectionService, - policyService, - logService, - passwordRepromptService, - organizationService, - dialogService, - window, - datePipe, - configService, - cipherAuthorizationService, - ); - } - - async ngOnInit() { - await super.ngOnInit(); - - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - if (params.cipherId) { - this.cipherId = params.cipherId; - } - if (params.folderId) { - this.folderId = params.folderId; - } - if (params.collectionId) { - this.collectionId = params.collectionId; - const collection = this.writeableCollections.find((c) => c.id === params.collectionId); - if (collection != null) { - this.collectionIds = [collection.id]; - this.organizationId = collection.organizationId; - } - } - if (params.type) { - const type = parseInt(params.type, null); - this.type = type; - } - this.editMode = !params.cipherId; - - if (params.cloneMode != null) { - this.cloneMode = params.cloneMode === "true"; - } - if (params.selectedVault) { - this.organizationId = params.selectedVault; - } - - await this.load(); - - if (!this.editMode || this.cloneMode) { - // Only allow setting username if there's no existing value - if ( - params.username && - (this.cipher.login.username == null || this.cipher.login.username === "") - ) { - this.cipher.login.username = params.username; - } - - if (params.name && (this.cipher.name == null || this.cipher.name === "")) { - this.cipher.name = params.name; - } - if ( - params.uri && - this.cipher.login.uris[0] && - (this.cipher.login.uris[0].uri == null || this.cipher.login.uris[0].uri === "") - ) { - this.cipher.login.uris[0].uri = params.uri; - } - } - - this.openAttachmentsInPopup = BrowserPopupUtils.inPopup(window); - - if (this.inAddEditPopoutWindow()) { - BrowserApi.messageListener("add-edit-popout", this.handleExtensionMessage.bind(this)); - } - }); - - if (!this.editMode) { - const tabs = await BrowserApi.tabsQuery({ windowType: "normal" }); - this.currentUris = - tabs == null - ? null - : tabs.filter((tab) => tab.url != null && tab.url !== "").map((tab) => tab.url); - } - - this.setFocus(); - - if (BrowserPopupUtils.inPopout(window)) { - this.popupCloseWarningService.enable(); - } - } - - async load() { - await super.load(); - this.showAutoFillOnPageLoadOptions = - this.cipher.type === CipherType.Login && - (await firstValueFrom(this.autofillSettingsService.autofillOnPageLoad$)); - } - - async submit(): Promise { - const fido2SessionData = await firstValueFrom(this.fido2PopoutSessionData$); - const { isFido2Session, sessionId, userVerification } = fido2SessionData; - const inFido2PopoutWindow = BrowserPopupUtils.inPopout(window) && isFido2Session; - - // normalize card expiry year on save - if (this.cipher.type === this.cipherType.Card) { - this.cipher.card.expYear = normalizeExpiryYearFormat(this.cipher.card.expYear); - } - - // TODO: Revert to use fido2 user verification service once user verification for passkeys is approved for production. - // PM-4577 - https://github.com/bitwarden/clients/pull/8746 - if ( - inFido2PopoutWindow && - !(await this.handleFido2UserVerification(sessionId, userVerification)) - ) { - return false; - } - - const success = await super.submit(); - if (!success) { - return false; - } - - if (BrowserPopupUtils.inPopout(window)) { - this.popupCloseWarningService.disable(); - } - - if (inFido2PopoutWindow) { - BrowserFido2UserInterfaceSession.confirmNewCredentialResponse( - sessionId, - this.cipher.id, - userVerification, - ); - return true; - } - - if (this.inAddEditPopoutWindow()) { - this.messagingService.send("addEditCipherSubmitted"); - await closeAddEditVaultItemPopout(1000); - return true; - } - - if (this.cloneMode) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/tabs/vault"]); - } else { - this.location.back(); - } - return true; - } - - attachments() { - super.attachments(); - - if (this.openAttachmentsInPopup) { - const destinationUrl = this.router - .createUrlTree(["/attachments"], { queryParams: { cipherId: this.cipher.id } }) - .toString(); - const currentBaseUrl = window.location.href.replace(this.router.url, ""); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserPopupUtils.openCurrentPagePopout(window, currentBaseUrl + destinationUrl); - } else { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/attachments"], { queryParams: { cipherId: this.cipher.id } }); - } - } - - editCollections() { - super.editCollections(); - if (this.cipher.organizationId != null) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/collections"], { queryParams: { cipherId: this.cipher.id } }); - } - } - - async cancel() { - super.cancel(); - - const sessionData = await firstValueFrom(this.fido2PopoutSessionData$); - if (BrowserPopupUtils.inPopout(window) && sessionData.isFido2Session) { - this.popupCloseWarningService.disable(); - BrowserFido2UserInterfaceSession.abortPopout(sessionData.sessionId); - return; - } - - if (this.inAddEditPopoutWindow()) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - closeAddEditVaultItemPopout(); - return; - } - - this.location.back(); - } - - async generateUsername(): Promise { - const confirmed = await super.generateUsername(); - if (confirmed) { - await this.saveCipherState(); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["generator"], { queryParams: { type: "username" } }); - } - return confirmed; - } - - async generatePassword(): Promise { - const confirmed = await super.generatePassword(); - if (confirmed) { - await this.saveCipherState(); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["generator"], { queryParams: { type: "password" } }); - } - return confirmed; - } - - async delete(): Promise { - const confirmed = await super.delete(); - if (confirmed) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/tabs/vault"]); - } - return confirmed; - } - - toggleUriInput(uri: LoginUriView) { - const u = uri as any; - u.showCurrentUris = !u.showCurrentUris; - } - - allowOwnershipOptions(): boolean { - return ( - (!this.editMode || this.cloneMode) && - this.ownershipOptions && - (this.ownershipOptions.length > 1 || !this.allowPersonal) - ); - } - - private saveCipherState() { - return this.cipherService.setAddEditCipherInfo({ - cipher: this.cipher, - collectionIds: - this.collections == null - ? [] - : this.collections.filter((c) => (c as any).checked).map((c) => c.id), - }); - } - - private setFocus() { - window.setTimeout(() => { - if (this.editMode) { - return; - } - - if (this.cipher.name != null && this.cipher.name !== "") { - document.getElementById("loginUsername").focus(); - } else { - document.getElementById("name").focus(); - } - }, 200); - } - - repromptChanged() { - super.repromptChanged(); - - if (!this.showAutoFillOnPageLoadOptions) { - return; - } - - if (this.reprompt) { - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("passwordRepromptDisabledAutofillOnPageLoad"), - ); - return; - } - - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("autofillOnPageLoadSetToDefault"), - ); - } - - private inAddEditPopoutWindow() { - return BrowserPopupUtils.inSingleActionPopout(window, VaultPopoutType.addEditVaultItem); - } - - async captureTOTPFromTab() { - try { - const screenshot = await BrowserApi.captureVisibleTab(); - const data = await qrcodeParser(screenshot); - const url = new URL(data.toString()); - if (url.protocol == "otpauth:" && url.searchParams.has("secret")) { - this.cipher.login.totp = data.toString(); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("totpCaptureSuccess"), - ); - } - } catch (e) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("totpCaptureError"), - ); - } - } - - private handleExtensionMessage(message: { [key: string]: any; command: string }) { - if (message.command === "inlineAutofillMenuRefreshAddEditCipher") { - this.load().catch((error) => this.logService.error(error)); - } - } - - // TODO: Remove and use fido2 user verification service once user verification for passkeys is approved for production. - // Be sure to make the same changes to add-edit-v2.component.ts if applicable - private async handleFido2UserVerification( - sessionId: string, - userVerification: boolean, - ): Promise { - // We are bypassing user verification pending approval for production. - return true; - } -} diff --git a/apps/browser/src/vault/popup/components/vault/attachments.component.html b/apps/browser/src/vault/popup/components/vault/attachments.component.html deleted file mode 100644 index b95dc69af8f..00000000000 --- a/apps/browser/src/vault/popup/components/vault/attachments.component.html +++ /dev/null @@ -1,72 +0,0 @@ -
-
-
- - -
-

- {{ "attachments" | i18n }} -

-
- -
-
-
-
-
-
-
- {{ a.fileName }} -
- {{ a.sizeName }} -
- -
-
-
-
-
-

- {{ "newAttachment" | i18n }} -

-
-
- - -
-
- -
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/attachments.component.ts b/apps/browser/src/vault/popup/components/vault/attachments.component.ts deleted file mode 100644 index b63b743b9fa..00000000000 --- a/apps/browser/src/vault/popup/components/vault/attachments.component.ts +++ /dev/null @@ -1,82 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Location } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { first } from "rxjs/operators"; - -import { AttachmentsComponent as BaseAttachmentsComponent } from "@bitwarden/angular/vault/components/attachments.component"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; -import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { DialogService, ToastService } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; - -@Component({ - selector: "app-vault-attachments", - templateUrl: "attachments.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class AttachmentsComponent extends BaseAttachmentsComponent implements OnInit { - openedAttachmentsInPopup: boolean; - - constructor( - cipherService: CipherService, - i18nService: I18nService, - keyService: KeyService, - encryptService: EncryptService, - platformUtilsService: PlatformUtilsService, - apiService: ApiService, - private location: Location, - private route: ActivatedRoute, - stateService: StateService, - logService: LogService, - fileDownloadService: FileDownloadService, - dialogService: DialogService, - billingAccountProfileStateService: BillingAccountProfileStateService, - accountService: AccountService, - toastService: ToastService, - ) { - super( - cipherService, - i18nService, - keyService, - encryptService, - platformUtilsService, - apiService, - window, - logService, - stateService, - fileDownloadService, - dialogService, - billingAccountProfileStateService, - accountService, - toastService, - ); - } - - async ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - this.cipherId = params.cipherId; - await this.init(); - }); - - this.openedAttachmentsInPopup = history.length === 1; - } - - back() { - this.location.back(); - } - - close() { - window.close(); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/collections.component.html b/apps/browser/src/vault/popup/components/vault/collections.component.html deleted file mode 100644 index 36c1336c5b4..00000000000 --- a/apps/browser/src/vault/popup/components/vault/collections.component.html +++ /dev/null @@ -1,43 +0,0 @@ -
-
-
- -
-

- {{ "collections" | i18n }} -

-
- -
-
-
-
-
-
- {{ "noCollectionsInList" | i18n }} -
-
-
-
- - -
-
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/collections.component.ts b/apps/browser/src/vault/popup/components/vault/collections.component.ts deleted file mode 100644 index 407f87e996c..00000000000 --- a/apps/browser/src/vault/popup/components/vault/collections.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Location } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { first } from "rxjs/operators"; - -import { CollectionService } from "@bitwarden/admin-console/common"; -import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { ToastService } from "@bitwarden/components"; - -@Component({ - selector: "app-vault-collections", - templateUrl: "collections.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class CollectionsComponent extends BaseCollectionsComponent implements OnInit { - constructor( - collectionService: CollectionService, - platformUtilsService: PlatformUtilsService, - i18nService: I18nService, - cipherService: CipherService, - organizationService: OrganizationService, - private route: ActivatedRoute, - private location: Location, - logService: LogService, - accountService: AccountService, - toastService: ToastService, - ) { - super( - collectionService, - platformUtilsService, - i18nService, - cipherService, - organizationService, - logService, - accountService, - toastService, - ); - } - - async ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - this.onSavedCollections.subscribe(() => { - this.back(); - }); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - this.cipherId = params.cipherId; - await this.load(); - }); - } - - back() { - this.location.back(); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.html b/apps/browser/src/vault/popup/components/vault/current-tab.component.html deleted file mode 100644 index bb8a401da62..00000000000 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.html +++ /dev/null @@ -1,95 +0,0 @@ - -

{{ "currentTab" | i18n }}

-
- - -
- -
- -
-
-
-
- -
- - -
-

- {{ "typeLogins" | i18n }} - {{ loginCiphers.length }} -

-
- - -
-

{{ "autoFillInfo" | i18n }}

- -
-
-
-
-

- {{ "cards" | i18n }} - {{ cardCiphers.length }} -

-
- -
-
-
-

- {{ "identities" | i18n }} - {{ identityCiphers.length }} -

-
- -
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts deleted file mode 100644 index 156a708015f..00000000000 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ /dev/null @@ -1,354 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core"; -import { Router } from "@angular/router"; -import { Subject, firstValueFrom, from, Subscription } from "rxjs"; -import { debounceTime, switchMap, takeUntil } from "rxjs/operators"; - -import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; -import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; -import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { SyncService } from "@bitwarden/common/platform/sync"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { PasswordRepromptService } from "@bitwarden/vault"; - -import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service"; -import { BrowserApi } from "../../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; -import { VaultFilterService } from "../../../services/vault-filter.service"; - -const BroadcasterSubscriptionId = "CurrentTabComponent"; - -@Component({ - selector: "app-current-tab", - templateUrl: "current-tab.component.html", -}) -export class CurrentTabComponent implements OnInit, OnDestroy { - pageDetails: any[] = []; - tab: chrome.tabs.Tab; - cardCiphers: CipherView[]; - identityCiphers: CipherView[]; - loginCiphers: CipherView[]; - url: string; - hostname: string; - searchText: string; - inSidebar = false; - searchTypeSearch = false; - loaded = false; - isLoading = false; - showOrganizations = false; - showHowToAutofill = false; - autofillCalloutText: string; - protected search$ = new Subject(); - private destroy$ = new Subject(); - private collectPageDetailsSubscription: Subscription; - - private totpCode: string; - private totpTimeout: number; - private loadedTimeout: number; - private searchTimeout: number; - - constructor( - private platformUtilsService: PlatformUtilsService, - private cipherService: CipherService, - private autofillService: AutofillService, - private i18nService: I18nService, - private router: Router, - private ngZone: NgZone, - private broadcasterService: BroadcasterService, - private changeDetectorRef: ChangeDetectorRef, - private syncService: SyncService, - private searchService: SearchService, - private autofillSettingsService: AutofillSettingsServiceAbstraction, - private passwordRepromptService: PasswordRepromptService, - private organizationService: OrganizationService, - private vaultFilterService: VaultFilterService, - private vaultSettingsService: VaultSettingsService, - ) {} - - async ngOnInit() { - this.searchTypeSearch = !this.platformUtilsService.isSafari(); - this.inSidebar = BrowserPopupUtils.inSidebar(window); - - this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.ngZone.run(async () => { - switch (message.command) { - case "syncCompleted": - if (this.isLoading) { - window.setTimeout(() => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.load(); - }, 500); - } - break; - default: - break; - } - - this.changeDetectorRef.detectChanges(); - }); - }); - - if (!this.syncService.syncInProgress) { - await this.load(); - await this.setCallout(); - } else { - this.loadedTimeout = window.setTimeout(async () => { - if (!this.isLoading) { - await this.load(); - await this.setCallout(); - } - }, 5000); - } - - this.search$ - .pipe( - debounceTime(500), - switchMap(() => { - return from(this.searchVault()); - }), - takeUntil(this.destroy$), - ) - .subscribe(); - - const autofillOnPageLoadOrgPolicy = await firstValueFrom( - this.autofillSettingsService.activateAutofillOnPageLoadFromPolicy$, - ); - const autofillOnPageLoadPolicyToastHasDisplayed = await firstValueFrom( - this.autofillSettingsService.autofillOnPageLoadPolicyToastHasDisplayed$, - ); - - // If the org "autofill on page load" policy is set, set the user setting to match it - // @TODO override user setting instead of overwriting - if (autofillOnPageLoadOrgPolicy === true) { - await this.autofillSettingsService.setAutofillOnPageLoad(true); - - if (!autofillOnPageLoadPolicyToastHasDisplayed) { - this.platformUtilsService.showToast( - "info", - null, - this.i18nService.t("autofillPageLoadPolicyActivated"), - ); - - await this.autofillSettingsService.setAutofillOnPageLoadPolicyToastHasDisplayed(true); - } - } - - // If the org policy is ever disabled after being enabled, reset the toast notification - if (!autofillOnPageLoadOrgPolicy && autofillOnPageLoadPolicyToastHasDisplayed) { - await this.autofillSettingsService.setAutofillOnPageLoadPolicyToastHasDisplayed(false); - } - } - - ngOnDestroy() { - window.clearTimeout(this.loadedTimeout); - this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); - - this.destroy$.next(); - this.destroy$.complete(); - } - - async refresh() { - await this.load(); - } - - addCipher() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/add-cipher"], { - queryParams: { - name: this.hostname, - uri: this.url, - selectedVault: this.vaultFilterService.getVaultFilter().selectedOrganizationId, - }, - }); - } - - viewCipher(cipher: CipherView) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/view-cipher"], { queryParams: { cipherId: cipher.id } }); - } - - async fillCipher(cipher: CipherView, closePopupDelay?: number) { - if ( - cipher.reprompt !== CipherRepromptType.None && - !(await this.passwordRepromptService.showPasswordPrompt()) - ) { - return; - } - - this.totpCode = null; - if (this.totpTimeout != null) { - window.clearTimeout(this.totpTimeout); - } - - if (this.pageDetails == null || this.pageDetails.length === 0) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("autofillError")); - return; - } - - try { - this.totpCode = await this.autofillService.doAutoFill({ - tab: this.tab, - cipher: cipher, - pageDetails: this.pageDetails, - doc: window.document, - fillNewPassword: true, - allowTotpAutofill: true, - }); - if (this.totpCode != null) { - this.platformUtilsService.copyToClipboard(this.totpCode, { window: window }); - } - if (BrowserPopupUtils.inPopup(window)) { - if (!closePopupDelay) { - if (this.platformUtilsService.isFirefox() || this.platformUtilsService.isSafari()) { - BrowserApi.closePopup(window); - } else { - // Slight delay to fix bug in Chromium browsers where popup closes without copying totp to clipboard - setTimeout(() => BrowserApi.closePopup(window), 50); - } - } else { - setTimeout(() => BrowserApi.closePopup(window), closePopupDelay); - } - } - } catch { - this.ngZone.run(() => { - this.platformUtilsService.showToast("error", null, this.i18nService.t("autofillError")); - this.changeDetectorRef.detectChanges(); - }); - } - } - - async searchVault() { - if (!(await this.searchService.isSearchable(this.searchText))) { - return; - } - - await this.router.navigate(["/tabs/vault"], { queryParams: { searchText: this.searchText } }); - } - - closeOnEsc(e: KeyboardEvent) { - // If input not empty, use browser default behavior of clearing input instead - if (e.key === "Escape" && (this.searchText == null || this.searchText === "")) { - BrowserApi.closePopup(window); - } - } - - protected async load() { - this.isLoading = false; - this.tab = await BrowserApi.getTabFromCurrentWindow(); - - if (this.tab != null) { - this.url = this.tab.url; - } else { - this.loginCiphers = []; - this.isLoading = this.loaded = true; - return; - } - - this.pageDetails = []; - this.collectPageDetailsSubscription?.unsubscribe(); - this.collectPageDetailsSubscription = this.autofillService - .collectPageDetailsFromTab$(this.tab) - .pipe(takeUntil(this.destroy$)) - .subscribe((pageDetails) => (this.pageDetails = pageDetails)); - - this.hostname = Utils.getHostname(this.url); - const otherTypes: CipherType[] = []; - const dontShowCards = !(await firstValueFrom(this.vaultSettingsService.showCardsCurrentTab$)); - const dontShowIdentities = !(await firstValueFrom( - this.vaultSettingsService.showIdentitiesCurrentTab$, - )); - this.showOrganizations = await this.organizationService.hasOrganizations(); - if (!dontShowCards) { - otherTypes.push(CipherType.Card); - } - if (!dontShowIdentities) { - otherTypes.push(CipherType.Identity); - } - - const ciphers = await this.cipherService.getAllDecryptedForUrl( - this.url, - otherTypes.length > 0 ? otherTypes : null, - ); - - this.loginCiphers = []; - this.cardCiphers = []; - this.identityCiphers = []; - - ciphers.forEach((c) => { - if (!this.vaultFilterService.filterCipherForSelectedVault(c)) { - switch (c.type) { - case CipherType.Login: - this.loginCiphers.push(c); - break; - case CipherType.Card: - this.cardCiphers.push(c); - break; - case CipherType.Identity: - this.identityCiphers.push(c); - break; - default: - break; - } - } - }); - - if (this.loginCiphers.length) { - this.loginCiphers = this.loginCiphers.sort((a, b) => - this.cipherService.sortCiphersByLastUsedThenName(a, b), - ); - } - - this.isLoading = this.loaded = true; - } - - async goToSettings() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["autofill"]); - } - - async dismissCallout() { - await this.autofillSettingsService.setAutofillOnPageLoadCalloutIsDismissed(true); - this.showHowToAutofill = false; - } - - private async setCallout() { - const inlineMenuVisibilityIsOff = - (await firstValueFrom(this.autofillSettingsService.inlineMenuVisibility$)) === - AutofillOverlayVisibility.Off; - - this.showHowToAutofill = - this.loginCiphers.length > 0 && - inlineMenuVisibilityIsOff && - !(await firstValueFrom(this.autofillSettingsService.autofillOnPageLoad$)) && - !(await firstValueFrom(this.autofillSettingsService.autofillOnPageLoadCalloutIsDismissed$)); - - if (this.showHowToAutofill) { - const autofillCommand = await this.platformUtilsService.getAutofillKeyboardShortcut(); - await this.setAutofillCalloutText(autofillCommand); - } - } - - private setAutofillCalloutText(command: string) { - if (command) { - this.autofillCalloutText = this.i18nService.t("autofillSelectInfoWithCommand", command); - } else { - this.autofillCalloutText = this.i18nService.t("autofillSelectInfoWithoutCommand"); - } - } -} diff --git a/apps/browser/src/vault/popup/components/vault/password-history.component.html b/apps/browser/src/vault/popup/components/vault/password-history.component.html deleted file mode 100644 index 6286aa1022d..00000000000 --- a/apps/browser/src/vault/popup/components/vault/password-history.component.html +++ /dev/null @@ -1,40 +0,0 @@ -
-
- -
-

- {{ "passwordHistory" | i18n }} -

-
-
-
-
-
-
-
-
- - {{ h.lastUsedDate | date: "medium" }} -
-
-
- -
-
-
-
-
-

{{ "noPasswordsInList" | i18n }}

-
-
diff --git a/apps/browser/src/vault/popup/components/vault/password-history.component.ts b/apps/browser/src/vault/popup/components/vault/password-history.component.ts deleted file mode 100644 index bf1b4ea7717..00000000000 --- a/apps/browser/src/vault/popup/components/vault/password-history.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Location } from "@angular/common"; -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute } from "@angular/router"; -import { first } from "rxjs/operators"; - -import { PasswordHistoryComponent as BasePasswordHistoryComponent } from "@bitwarden/angular/vault/components/password-history.component"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; - -@Component({ - selector: "app-password-history", - templateUrl: "password-history.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class PasswordHistoryComponent extends BasePasswordHistoryComponent implements OnInit { - constructor( - cipherService: CipherService, - platformUtilsService: PlatformUtilsService, - i18nService: I18nService, - accountService: AccountService, - private location: Location, - private route: ActivatedRoute, - ) { - super(cipherService, platformUtilsService, i18nService, accountService, window); - } - - async ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - if (params.cipherId) { - this.cipherId = params.cipherId; - } else { - this.close(); - } - await this.init(); - }); - } - - close() { - this.location.back(); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/share.component.html b/apps/browser/src/vault/popup/components/vault/share.component.html deleted file mode 100644 index 46aaecd06b8..00000000000 --- a/apps/browser/src/vault/popup/components/vault/share.component.html +++ /dev/null @@ -1,77 +0,0 @@ -
- -
-
- -
-

- {{ "moveToOrganization" | i18n }} -

-
- -
-
-
-
-
-
- {{ "noOrganizationsList" | i18n }} -
-
-
-
- - -
-
- -
-
-

- {{ "collections" | i18n }} -

-
-
- {{ "noCollectionsInList" | i18n }} -
-
-
-
- - -
-
-
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/share.component.ts b/apps/browser/src/vault/popup/components/vault/share.component.ts deleted file mode 100644 index 8e061665b73..00000000000 --- a/apps/browser/src/vault/popup/components/vault/share.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Component, OnInit } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { first } from "rxjs/operators"; - -import { CollectionService } from "@bitwarden/admin-console/common"; -import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; - -@Component({ - selector: "app-vault-share", - templateUrl: "share.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class ShareComponent extends BaseShareComponent implements OnInit { - constructor( - collectionService: CollectionService, - platformUtilsService: PlatformUtilsService, - i18nService: I18nService, - logService: LogService, - cipherService: CipherService, - private route: ActivatedRoute, - private router: Router, - organizationService: OrganizationService, - accountService: AccountService, - ) { - super( - collectionService, - platformUtilsService, - i18nService, - cipherService, - logService, - organizationService, - accountService, - ); - } - - async ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - this.onSharedCipher.subscribe(() => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["view-cipher", { cipherId: this.cipherId }]); - }); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - this.cipherId = params.cipherId; - await this.load(); - }); - } - - async submit(): Promise { - const success = await super.submit(); - if (success) { - this.cancel(); - } - return success; - } - - cancel() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/view-cipher"], { - replaceUrl: true, - queryParams: { cipherId: this.cipher.id }, - }); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/vault-filter.component.html b/apps/browser/src/vault/popup/components/vault/vault-filter.component.html deleted file mode 100644 index bf557f74608..00000000000 --- a/apps/browser/src/vault/popup/components/vault/vault-filter.component.html +++ /dev/null @@ -1,238 +0,0 @@ - -
- -
-

{{ "myVault" | i18n }}

- -
- -
-
-
- -
- - - -

{{ "noItemsInList" | i18n }}

- -
-
- -
-

- {{ "favorites" | i18n }} - {{ favoriteCiphers.length }} -

-
- - -
-
-
-

- {{ "types" | i18n }} - 4 -

-
- - - - - -
-
-
-

- {{ "folders" | i18n }} - {{ folderCount }} -

-
- -
-
-
-

- {{ "collections" | i18n }} - {{ nestedCollections.length }} -

-
- -
-
-
-

- {{ "noneFolder" | i18n }} -
{{ noFolderCiphers.length }}
-

-
- - -
-
-
-

- {{ "trash" | i18n }} - {{ deletedCount }} -

-
- -
-
-
- -
-

{{ "noItemsInList" | i18n }}

-
- -
-
- - -
-
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts deleted file mode 100644 index d430568869c..00000000000 --- a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts +++ /dev/null @@ -1,482 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Location } from "@angular/common"; -import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { BehaviorSubject, Subject, firstValueFrom, from } from "rxjs"; -import { first, switchMap, takeUntil } from "rxjs/operators"; - -import { CollectionView } from "@bitwarden/admin-console/common"; -import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { SyncService } from "@bitwarden/common/platform/sync"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; - -import { BrowserGroupingsComponentState } from "../../../../models/browserGroupingsComponentState"; -import { BrowserApi } from "../../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; -import { VaultBrowserStateService } from "../../../services/vault-browser-state.service"; -import { VaultFilterService } from "../../../services/vault-filter.service"; - -const ComponentId = "VaultComponent"; - -@Component({ - selector: "app-vault-filter", - templateUrl: "vault-filter.component.html", -}) -export class VaultFilterComponent implements OnInit, OnDestroy { - get showNoFolderCiphers(): boolean { - return ( - this.noFolderCiphers != null && - this.noFolderCiphers.length < this.noFolderListSize && - this.collections.length === 0 - ); - } - - get folderCount(): number { - return this.nestedFolders.length - (this.showNoFolderCiphers ? 0 : 1); - } - folders: FolderView[]; - nestedFolders: TreeNode[]; - collections: CollectionView[]; - nestedCollections: TreeNode[]; - loaded = false; - cipherType = CipherType; - ciphers: CipherView[]; - favoriteCiphers: CipherView[]; - noFolderCiphers: CipherView[]; - folderCounts = new Map(); - collectionCounts = new Map(); - typeCounts = new Map(); - state: BrowserGroupingsComponentState; - showLeftHeader = true; - searchPending = false; - searchTypeSearch = false; - deletedCount = 0; - vaultFilter: VaultFilter; - selectedOrganization: string = null; - showCollections = true; - - isSshKeysEnabled = false; - - private loadedTimeout: number; - private selectedTimeout: number; - private preventSelected = false; - private noFolderListSize = 100; - private searchTimeout: any = null; - private hasSearched = false; - private hasLoadedAllCiphers = false; - private allCiphers: CipherView[] = null; - private destroy$ = new Subject(); - private _searchText$ = new BehaviorSubject(""); - private isSearchable: boolean = false; - - get searchText() { - return this._searchText$.value; - } - set searchText(value: string) { - this._searchText$.next(value); - } - - constructor( - private i18nService: I18nService, - private cipherService: CipherService, - private router: Router, - private ngZone: NgZone, - private broadcasterService: BroadcasterService, - private changeDetectorRef: ChangeDetectorRef, - private route: ActivatedRoute, - private syncService: SyncService, - private platformUtilsService: PlatformUtilsService, - private searchService: SearchService, - private location: Location, - private vaultFilterService: VaultFilterService, - private vaultBrowserStateService: VaultBrowserStateService, - private configService: ConfigService, - ) { - this.noFolderListSize = 100; - } - - async ngOnInit() { - this.searchTypeSearch = !this.platformUtilsService.isSafari(); - this.showLeftHeader = !( - BrowserPopupUtils.inSidebar(window) && this.platformUtilsService.isFirefox() - ); - await this.vaultBrowserStateService.setBrowserVaultItemsComponentState(null); - - this.broadcasterService.subscribe(ComponentId, (message: any) => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.ngZone.run(async () => { - switch (message.command) { - case "syncCompleted": - window.setTimeout(() => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.load(); - }, 500); - break; - default: - break; - } - - this.changeDetectorRef.detectChanges(); - }); - }); - - const restoredScopeState = await this.restoreState(); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - this.state = await this.vaultBrowserStateService.getBrowserGroupingsComponentState(); - if (this.state?.searchText) { - this.searchText = this.state.searchText; - } else if (params.searchText) { - this.searchText = params.searchText; - this.location.replaceState("vault"); - } - - if (!this.syncService.syncInProgress) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.load(); - } else { - this.loadedTimeout = window.setTimeout(() => { - if (!this.loaded) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.load(); - } - }, 5000); - } - - if (!this.syncService.syncInProgress || restoredScopeState) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserPopupUtils.setContentScrollY(window, this.state?.scrollY); - } - }); - - this._searchText$ - .pipe( - switchMap((searchText) => from(this.searchService.isSearchable(searchText))), - takeUntil(this.destroy$), - ) - .subscribe((isSearchable) => { - this.isSearchable = isSearchable; - }); - - this.isSshKeysEnabled = await this.configService.getFeatureFlag(FeatureFlag.SSHKeyVaultItem); - } - - ngOnDestroy() { - if (this.loadedTimeout != null) { - window.clearTimeout(this.loadedTimeout); - } - if (this.selectedTimeout != null) { - window.clearTimeout(this.selectedTimeout); - } - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.saveState(); - this.broadcasterService.unsubscribe(ComponentId); - this.destroy$.next(); - this.destroy$.complete(); - } - - async load() { - this.vaultFilter = this.vaultFilterService.getVaultFilter(); - - this.updateSelectedOrg(); - await this.loadCollectionsAndFolders(); - await this.loadCiphers(); - - if (this.showNoFolderCiphers && this.nestedFolders.length > 0) { - // Remove "No Folder" from folder listing - this.nestedFolders = this.nestedFolders.slice(0, this.nestedFolders.length - 1); - } - - this.loaded = true; - } - - async loadCiphers() { - this.allCiphers = await this.cipherService.getAllDecrypted(); - if (!this.hasLoadedAllCiphers) { - this.hasLoadedAllCiphers = !(await this.searchService.isSearchable(this.searchText)); - } - await this.search(null); - this.getCounts(); - } - - async loadCollections() { - const allCollections = await this.vaultFilterService.buildCollections( - this.selectedOrganization, - ); - this.collections = allCollections.fullList; - this.nestedCollections = allCollections.nestedList; - } - - async loadFolders() { - const allFolders = await firstValueFrom( - this.vaultFilterService.buildNestedFolders(this.selectedOrganization), - ); - this.folders = allFolders.fullList; - this.nestedFolders = allFolders.nestedList; - } - - async search(timeout: number = null) { - this.searchPending = false; - if (this.searchTimeout != null) { - clearTimeout(this.searchTimeout); - } - const filterDeleted = (c: CipherView) => !c.isDeleted; - if (timeout == null) { - this.hasSearched = this.isSearchable; - this.ciphers = await this.searchService.searchCiphers( - this.searchText, - filterDeleted, - this.allCiphers, - ); - this.ciphers = this.ciphers.filter( - (c) => !this.vaultFilterService.filterCipherForSelectedVault(c), - ); - return; - } - this.searchPending = true; - this.searchTimeout = setTimeout(async () => { - this.hasSearched = this.isSearchable; - if (!this.hasLoadedAllCiphers && !this.hasSearched) { - await this.loadCiphers(); - } else { - this.ciphers = await this.searchService.searchCiphers( - this.searchText, - filterDeleted, - this.allCiphers, - ); - } - this.ciphers = this.ciphers.filter( - (c) => !this.vaultFilterService.filterCipherForSelectedVault(c), - ); - this.searchPending = false; - }, timeout); - } - - async selectType(type: CipherType) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/ciphers"], { queryParams: { type: type } }); - } - - async selectFolder(folder: FolderView) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/ciphers"], { queryParams: { folderId: folder.id || "none" } }); - } - - async selectCollection(collection: CollectionView) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/ciphers"], { queryParams: { collectionId: collection.id } }); - } - - async selectTrash() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/ciphers"], { queryParams: { deleted: true } }); - } - - async selectCipher(cipher: CipherView) { - this.selectedTimeout = window.setTimeout(() => { - if (!this.preventSelected) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/view-cipher"], { queryParams: { cipherId: cipher.id } }); - } - this.preventSelected = false; - }, 200); - } - - async launchCipher(cipher: CipherView) { - if (cipher.type !== CipherType.Login || !cipher.login.canLaunch) { - return; - } - - if (this.selectedTimeout != null) { - window.clearTimeout(this.selectedTimeout); - } - this.preventSelected = true; - await this.cipherService.updateLastLaunchedDate(cipher.id); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab(cipher.login.launchUri); - if (BrowserPopupUtils.inPopup(window)) { - BrowserApi.closePopup(window); - } - } - - async addCipher() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/add-cipher"], { - queryParams: { selectedVault: this.vaultFilter.selectedOrganizationId }, - }); - } - - async vaultFilterChanged() { - if (this.showSearching) { - await this.search(); - } - this.updateSelectedOrg(); - await this.loadCollectionsAndFolders(); - this.getCounts(); - } - - updateSelectedOrg() { - this.vaultFilter = this.vaultFilterService.getVaultFilter(); - if (this.vaultFilter.selectedOrganizationId != null) { - this.selectedOrganization = this.vaultFilter.selectedOrganizationId; - } else { - this.selectedOrganization = null; - } - } - - getCounts() { - let favoriteCiphers: CipherView[] = null; - let noFolderCiphers: CipherView[] = null; - const folderCounts = new Map(); - const collectionCounts = new Map(); - const typeCounts = new Map(); - - this.deletedCount = this.allCiphers.filter( - (c) => c.isDeleted && !this.vaultFilterService.filterCipherForSelectedVault(c), - ).length; - - this.ciphers?.forEach((c) => { - if (!this.vaultFilterService.filterCipherForSelectedVault(c)) { - if (c.isDeleted) { - return; - } - if (c.favorite) { - if (favoriteCiphers == null) { - favoriteCiphers = []; - } - favoriteCiphers.push(c); - } - - if (c.folderId == null) { - if (noFolderCiphers == null) { - noFolderCiphers = []; - } - noFolderCiphers.push(c); - } - - if (typeCounts.has(c.type)) { - typeCounts.set(c.type, typeCounts.get(c.type) + 1); - } else { - typeCounts.set(c.type, 1); - } - - if (folderCounts.has(c.folderId)) { - folderCounts.set(c.folderId, folderCounts.get(c.folderId) + 1); - } else { - folderCounts.set(c.folderId, 1); - } - - if (c.collectionIds != null) { - c.collectionIds.forEach((colId) => { - if (collectionCounts.has(colId)) { - collectionCounts.set(colId, collectionCounts.get(colId) + 1); - } else { - collectionCounts.set(colId, 1); - } - }); - } - } - }); - - this.favoriteCiphers = favoriteCiphers; - this.noFolderCiphers = noFolderCiphers; - this.typeCounts = typeCounts; - this.folderCounts = folderCounts; - this.collectionCounts = collectionCounts; - } - - showSearching() { - return this.hasSearched || (!this.searchPending && this.isSearchable); - } - - closeOnEsc(e: KeyboardEvent) { - // If input not empty, use browser default behavior of clearing input instead - if (e.key === "Escape" && (this.searchText == null || this.searchText === "")) { - BrowserApi.closePopup(window); - } - } - - private async loadCollectionsAndFolders() { - this.showCollections = !this.vaultFilter.myVaultOnly; - await this.loadFolders(); - await this.loadCollections(); - } - - private async saveState() { - this.state = Object.assign(new BrowserGroupingsComponentState(), { - scrollY: BrowserPopupUtils.getContentScrollY(window), - searchText: this.searchText, - favoriteCiphers: this.favoriteCiphers, - noFolderCiphers: this.noFolderCiphers, - ciphers: this.ciphers, - collectionCounts: this.collectionCounts, - folderCounts: this.folderCounts, - typeCounts: this.typeCounts, - folders: this.folders, - collections: this.collections, - deletedCount: this.deletedCount, - }); - await this.vaultBrowserStateService.setBrowserGroupingsComponentState(this.state); - } - - private async restoreState(): Promise { - this.state = await this.vaultBrowserStateService.getBrowserGroupingsComponentState(); - if (this.state == null) { - return false; - } - - if (this.state.favoriteCiphers != null) { - this.favoriteCiphers = this.state.favoriteCiphers; - } - if (this.state.noFolderCiphers != null) { - this.noFolderCiphers = this.state.noFolderCiphers; - } - if (this.state.ciphers != null) { - this.ciphers = this.state.ciphers; - } - if (this.state.collectionCounts != null) { - this.collectionCounts = this.state.collectionCounts; - } - if (this.state.folderCounts != null) { - this.folderCounts = this.state.folderCounts; - } - if (this.state.typeCounts != null) { - this.typeCounts = this.state.typeCounts; - } - if (this.state.folders != null) { - this.folders = this.state.folders; - } - if (this.state.collections != null) { - this.collections = this.state.collections; - } - if (this.state.deletedCount != null) { - this.deletedCount = this.state.deletedCount; - } - - return true; - } -} diff --git a/apps/browser/src/vault/popup/components/vault/vault-items.component.html b/apps/browser/src/vault/popup/components/vault/vault-items.component.html deleted file mode 100644 index f10688554d9..00000000000 --- a/apps/browser/src/vault/popup/components/vault/vault-items.component.html +++ /dev/null @@ -1,123 +0,0 @@ -
-
- -
-

{{ "myVault" | i18n }}

- -
- -
-
-
- - -
-

- {{ "folders" | i18n }} -

-
- -
-
-
-

- {{ "collections" | i18n }} -

-
- -
-
-
- -
- -
- - - -

{{ "noItemsInList" | i18n }}

- -
-
-
- -
-

- {{ groupingTitle }} - {{ isSearching() ? ciphers.length : ciphers.length }} -

-
- -
-
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts deleted file mode 100644 index 387afcfe217..00000000000 --- a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts +++ /dev/null @@ -1,316 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Location } from "@angular/common"; -import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { first } from "rxjs/operators"; - -import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; -import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/vault/components/vault-items.component"; -import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; -import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; - -import { BrowserComponentState } from "../../../../models/browserComponentState"; -import { BrowserApi } from "../../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; -import { VaultBrowserStateService } from "../../../services/vault-browser-state.service"; -import { VaultFilterService } from "../../../services/vault-filter.service"; - -const ComponentId = "VaultItemsComponent"; - -@Component({ - selector: "app-vault-items", - templateUrl: "vault-items.component.html", -}) -export class VaultItemsComponent extends BaseVaultItemsComponent implements OnInit, OnDestroy { - groupingTitle: string; - state: BrowserComponentState; - folderId: string = null; - collectionId: string = null; - type: CipherType = null; - nestedFolders: TreeNode[]; - nestedCollections: TreeNode[]; - searchTypeSearch = false; - showOrganizations = false; - vaultFilter: VaultFilter; - deleted = true; - noneFolder = false; - showVaultFilter = false; - - private selectedTimeout: number; - private preventSelected = false; - private applySavedState = true; - private scrollingContainer = "cdk-virtual-scroll-viewport"; - - constructor( - searchService: SearchService, - private organizationService: OrganizationService, - private route: ActivatedRoute, - private router: Router, - private location: Location, - private ngZone: NgZone, - private broadcasterService: BroadcasterService, - private changeDetectorRef: ChangeDetectorRef, - private stateService: VaultBrowserStateService, - private i18nService: I18nService, - private collectionService: CollectionService, - private platformUtilsService: PlatformUtilsService, - cipherService: CipherService, - private vaultFilterService: VaultFilterService, - ) { - super(searchService, cipherService); - this.applySavedState = - (window as any).previousPopupUrl != null && - !(window as any).previousPopupUrl.startsWith("/ciphers"); - } - - async ngOnInit() { - this.searchTypeSearch = !this.platformUtilsService.isSafari(); - this.showOrganizations = await this.organizationService.hasOrganizations(); - this.vaultFilter = this.vaultFilterService.getVaultFilter(); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - if (this.applySavedState) { - this.state = await this.stateService.getBrowserVaultItemsComponentState(); - if (this.state?.searchText) { - this.searchText = this.state.searchText; - } - } - - if (params.deleted) { - this.showVaultFilter = true; - this.groupingTitle = this.i18nService.t("trash"); - this.searchPlaceholder = this.i18nService.t("searchTrash"); - await this.load(this.buildFilter(), true); - } else if (params.type) { - this.showVaultFilter = true; - this.searchPlaceholder = this.i18nService.t("searchType"); - this.type = parseInt(params.type, null); - switch (this.type) { - case CipherType.Login: - this.groupingTitle = this.i18nService.t("logins"); - break; - case CipherType.Card: - this.groupingTitle = this.i18nService.t("cards"); - break; - case CipherType.Identity: - this.groupingTitle = this.i18nService.t("identities"); - break; - case CipherType.SecureNote: - this.groupingTitle = this.i18nService.t("secureNotes"); - break; - case CipherType.SshKey: - this.groupingTitle = this.i18nService.t("sshKeys"); - break; - default: - break; - } - await this.load(this.buildFilter()); - } else if (params.folderId) { - this.showVaultFilter = true; - this.folderId = params.folderId === "none" ? null : params.folderId; - this.searchPlaceholder = this.i18nService.t("searchFolder"); - if (this.folderId != null) { - this.showOrganizations = false; - const folderNode = await this.vaultFilterService.getFolderNested(this.folderId); - if (folderNode != null && folderNode.node != null) { - this.groupingTitle = folderNode.node.name; - this.nestedFolders = - folderNode.children != null && folderNode.children.length > 0 - ? folderNode.children - : null; - } - } else { - this.noneFolder = true; - this.groupingTitle = this.i18nService.t("noneFolder"); - } - await this.load(this.buildFilter()); - } else if (params.collectionId) { - this.showVaultFilter = false; - this.collectionId = params.collectionId; - this.searchPlaceholder = this.i18nService.t("searchCollection"); - const collectionNode = await this.collectionService.getNested(this.collectionId); - if (collectionNode != null && collectionNode.node != null) { - this.groupingTitle = collectionNode.node.name; - this.nestedCollections = - collectionNode.children != null && collectionNode.children.length > 0 - ? collectionNode.children - : null; - } - await this.load( - (c) => c.collectionIds != null && c.collectionIds.indexOf(this.collectionId) > -1, - ); - } else { - this.showVaultFilter = true; - this.groupingTitle = this.i18nService.t("allItems"); - await this.load(this.buildFilter()); - } - - if (this.applySavedState && this.state != null) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserPopupUtils.setContentScrollY(window, this.state.scrollY, { - delay: 0, - containerSelector: this.scrollingContainer, - }); - } - await this.stateService.setBrowserVaultItemsComponentState(null); - }); - - this.broadcasterService.subscribe(ComponentId, (message: any) => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.ngZone.run(async () => { - switch (message.command) { - case "syncCompleted": - if (message.successfully) { - window.setTimeout(() => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.refresh(); - }, 500); - } - break; - default: - break; - } - - this.changeDetectorRef.detectChanges(); - }); - }); - } - - ngOnDestroy() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.saveState(); - this.broadcasterService.unsubscribe(ComponentId); - } - - selectCipher(cipher: CipherView) { - this.selectedTimeout = window.setTimeout(() => { - if (!this.preventSelected) { - super.selectCipher(cipher); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/view-cipher"], { - queryParams: { cipherId: cipher.id, collectionId: this.collectionId }, - }); - } - this.preventSelected = false; - }, 200); - } - - selectFolder(folder: FolderView) { - if (folder.id != null) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/ciphers"], { queryParams: { folderId: folder.id } }); - } - } - - selectCollection(collection: CollectionView) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/ciphers"], { queryParams: { collectionId: collection.id } }); - } - - async launchCipher(cipher: CipherView) { - if (cipher.type !== CipherType.Login || !cipher.login.canLaunch) { - return; - } - - if (this.selectedTimeout != null) { - window.clearTimeout(this.selectedTimeout); - } - this.preventSelected = true; - await this.cipherService.updateLastLaunchedDate(cipher.id); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab(cipher.login.launchUri); - if (BrowserPopupUtils.inPopup(window)) { - BrowserApi.closePopup(window); - } - } - - addCipher() { - if (this.deleted) { - return false; - } - super.addCipher(); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/add-cipher"], { - queryParams: { - folderId: this.folderId, - type: this.type, - collectionId: this.collectionId, - selectedVault: this.vaultFilter.selectedOrganizationId, - }, - }); - } - - back() { - (window as any).routeDirection = "b"; - this.location.back(); - } - - showGroupings() { - return ( - !this.isSearching() && - ((this.nestedFolders && this.nestedFolders.length) || - (this.nestedCollections && this.nestedCollections.length)) - ); - } - - async changeVaultSelection() { - this.vaultFilter = this.vaultFilterService.getVaultFilter(); - await this.load(this.buildFilter(), this.deleted); - } - - private buildFilter(): (cipher: CipherView) => boolean { - return (cipher) => { - let cipherPassesFilter = true; - if (this.deleted && cipherPassesFilter) { - cipherPassesFilter = cipher.isDeleted; - } - if (this.type != null && cipherPassesFilter) { - cipherPassesFilter = cipher.type === this.type; - } - if (this.folderId != null && this.folderId != "none" && cipherPassesFilter) { - cipherPassesFilter = cipher.folderId === this.folderId; - } - if (this.noneFolder) { - cipherPassesFilter = cipher.folderId == null; - } - if (this.collectionId != null && cipherPassesFilter) { - cipherPassesFilter = - cipher.collectionIds != null && cipher.collectionIds.indexOf(this.collectionId) > -1; - } - if (this.vaultFilter.selectedOrganizationId != null && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === this.vaultFilter.selectedOrganizationId; - } - if (this.vaultFilter.myVaultOnly && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === null; - } - return cipherPassesFilter; - }; - } - - private async saveState() { - this.state = { - scrollY: BrowserPopupUtils.getContentScrollY(window, this.scrollingContainer), - searchText: this.searchText, - }; - await this.stateService.setBrowserVaultItemsComponentState(this.state); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/vault-select.component.html b/apps/browser/src/vault/popup/components/vault/vault-select.component.html deleted file mode 100644 index 4f6ce3a11e6..00000000000 --- a/apps/browser/src/vault/popup/components/vault/vault-select.component.html +++ /dev/null @@ -1,82 +0,0 @@ - -
- - - - - - -
-
diff --git a/apps/browser/src/vault/popup/components/vault/vault-select.component.ts b/apps/browser/src/vault/popup/components/vault/vault-select.component.ts deleted file mode 100644 index 3c5061a516f..00000000000 --- a/apps/browser/src/vault/popup/components/vault/vault-select.component.ts +++ /dev/null @@ -1,227 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { animate, state, style, transition, trigger } from "@angular/animations"; -import { ConnectedPosition, Overlay, OverlayRef } from "@angular/cdk/overlay"; -import { TemplatePortal } from "@angular/cdk/portal"; -import { - Component, - ElementRef, - EventEmitter, - HostListener, - OnDestroy, - OnInit, - Output, - TemplateRef, - ViewChild, - ViewContainerRef, -} from "@angular/core"; -import { - BehaviorSubject, - combineLatest, - concatMap, - map, - merge, - Observable, - Subject, - takeUntil, -} from "rxjs"; - -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { PolicyType } from "@bitwarden/common/admin-console/enums"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; - -import { VaultFilterService } from "../../../services/vault-filter.service"; - -@Component({ - selector: "app-vault-select", - templateUrl: "vault-select.component.html", - animations: [ - trigger("transformPanel", [ - state( - "void", - style({ - opacity: 0, - }), - ), - transition( - "void => open", - animate( - "100ms linear", - style({ - opacity: 1, - }), - ), - ), - transition("* => void", animate("100ms linear", style({ opacity: 0 }))), - ]), - ], -}) -export class VaultSelectComponent implements OnInit, OnDestroy { - @Output() onVaultSelectionChanged = new EventEmitter(); - - @ViewChild("toggleVaults", { read: ElementRef }) - buttonRef: ElementRef; - @ViewChild("vaultSelectorTemplate", { read: TemplateRef }) templateRef: TemplateRef; - - private _selectedVault = new BehaviorSubject(null); - - isOpen = false; - loaded = false; - organizations$: Observable; - selectedVault$: Observable = this._selectedVault.asObservable(); - - enforcePersonalOwnership = false; - overlayPosition: ConnectedPosition[] = [ - { - originX: "start", - originY: "bottom", - overlayX: "start", - overlayY: "top", - }, - ]; - - private overlayRef: OverlayRef; - private _destroy = new Subject(); - - shouldShow(organizations: Organization[]): boolean { - return ( - (organizations.length > 0 && !this.enforcePersonalOwnership) || - (organizations.length > 1 && this.enforcePersonalOwnership) - ); - } - - constructor( - private vaultFilterService: VaultFilterService, - private i18nService: I18nService, - private overlay: Overlay, - private viewContainerRef: ViewContainerRef, - private platformUtilsService: PlatformUtilsService, - private organizationService: OrganizationService, - private policyService: PolicyService, - ) {} - - @HostListener("document:keydown.escape", ["$event"]) - handleKeyboardEvent(event: KeyboardEvent) { - if (this.isOpen) { - event.preventDefault(); - this.close(); - } - } - - async ngOnInit() { - this.organizations$ = this.organizationService.memberOrganizations$ - .pipe(takeUntil(this._destroy)) - .pipe(map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name")))); - - combineLatest([ - this.organizations$, - this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership), - ]) - .pipe( - concatMap(async ([organizations, enforcePersonalOwnership]) => { - this.enforcePersonalOwnership = enforcePersonalOwnership; - - if (this.shouldShow(organizations)) { - if (this.enforcePersonalOwnership && !this.vaultFilterService.vaultFilter.myVaultOnly) { - const firstOrganization = organizations[0]; - this._selectedVault.next(firstOrganization.name); - this.vaultFilterService.setVaultFilter(firstOrganization.id); - } else if (this.vaultFilterService.vaultFilter.myVaultOnly) { - this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault)); - } else if (this.vaultFilterService.vaultFilter.selectedOrganizationId != null) { - const selectedOrganization = organizations.find( - (o) => o.id === this.vaultFilterService.vaultFilter.selectedOrganizationId, - ); - this._selectedVault.next(selectedOrganization.name); - } else { - this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults)); - } - } - }), - ) - .pipe(takeUntil(this._destroy)) - .subscribe(); - - this.loaded = true; - } - - ngOnDestroy(): void { - this._destroy.next(); - this._destroy.complete(); - this._selectedVault.complete(); - } - - openOverlay() { - const viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); - const positionStrategyBuilder = this.overlay.position(); - - const positionStrategy = positionStrategyBuilder - .flexibleConnectedTo(this.buttonRef.nativeElement) - .withFlexibleDimensions(true) - .withPush(true) - .withViewportMargin(10) - .withGrowAfterOpen(true) - .withPositions(this.overlayPosition); - - this.overlayRef = this.overlay.create({ - hasBackdrop: true, - positionStrategy, - maxHeight: viewPortHeight - 160, - backdropClass: "cdk-overlay-transparent-backdrop", - scrollStrategy: this.overlay.scrollStrategies.close(), - }); - - const templatePortal = new TemplatePortal(this.templateRef, this.viewContainerRef); - this.overlayRef.attach(templatePortal); - this.isOpen = true; - - // Handle closing - merge( - this.overlayRef.outsidePointerEvents(), - this.overlayRef.backdropClick(), - this.overlayRef.detachments(), - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - ).subscribe(() => { - this.close(); - }); - } - - close() { - if (this.overlayRef) { - this.overlayRef.dispose(); - this.overlayRef = undefined; - } - this.isOpen = false; - } - - selectOrganization(organization: Organization) { - if (!organization.enabled) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("disabledOrganizationFilterError"), - ); - } else { - this._selectedVault.next(organization.name); - this.vaultFilterService.setVaultFilter(organization.id); - this.onVaultSelectionChanged.emit(); - this.close(); - } - } - selectAllVaults() { - this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults)); - this.vaultFilterService.setVaultFilter(this.vaultFilterService.allVaults); - this.onVaultSelectionChanged.emit(); - this.close(); - } - selectMyVault() { - this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault)); - this.vaultFilterService.setVaultFilter(this.vaultFilterService.myVault); - this.onVaultSelectionChanged.emit(); - this.close(); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/view-custom-fields.component.html b/apps/browser/src/vault/popup/components/vault/view-custom-fields.component.html deleted file mode 100644 index 4fbca28734b..00000000000 --- a/apps/browser/src/vault/popup/components/vault/view-custom-fields.component.html +++ /dev/null @@ -1,98 +0,0 @@ - -

- {{ "customFields" | i18n }} -

-
-
-
- {{ field.name }} - {{ field.name }} -
- {{ field.value || " " }} -
-
- {{ field.maskedValue }} - - -
-
- - - {{ field.value }} -
-
-
- - {{ "linkedValue" | i18n }} -
- {{ cipher.linkedFieldI18nKey(field.linkedId) | i18n }} -
-
-
- - - -
-
-
-
diff --git a/apps/browser/src/vault/popup/components/vault/view-custom-fields.component.ts b/apps/browser/src/vault/popup/components/vault/view-custom-fields.component.ts deleted file mode 100644 index 249f83c4444..00000000000 --- a/apps/browser/src/vault/popup/components/vault/view-custom-fields.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component } from "@angular/core"; - -import { ViewCustomFieldsComponent as BaseViewCustomFieldsComponent } from "@bitwarden/angular/vault/components/view-custom-fields.component"; -import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; - -@Component({ - selector: "app-vault-view-custom-fields", - templateUrl: "view-custom-fields.component.html", -}) -export class ViewCustomFieldsComponent extends BaseViewCustomFieldsComponent { - constructor(eventCollectionService: EventCollectionService) { - super(eventCollectionService); - } -} diff --git a/apps/browser/src/vault/popup/components/vault/view.component.html b/apps/browser/src/vault/popup/components/vault/view.component.html deleted file mode 100644 index 57a5d007d8a..00000000000 --- a/apps/browser/src/vault/popup/components/vault/view.component.html +++ /dev/null @@ -1,719 +0,0 @@ -
-
- -
-

- {{ "viewItem" | i18n }} -

-
- -
-
-
-
-

- {{ "itemInformation" | i18n }} -

-
-
- - -
- -
-
-
- - -
-
- -
-
-
-
- {{ "password" | i18n }} -
- {{ cipher.login.maskedPassword }} -
-
-
-
-
- - - - -
-
- - -
-
-
- {{ "typePasskey" | i18n }} - {{ fido2CredentialCreationDateValue }} -
-
-
- -
-
- {{ "verificationCodeTotp" | i18n }} - {{ totpCodeFormatted }} -
- -
- -
-
-
-
- {{ "verificationCodeTotp" | i18n }} - - - {{ "premiumSubcriptionRequired" | i18n }} - - -
-
-
- -
-
- {{ "cardholderName" | i18n }} - {{ cipher.card.cardholderName }} -
-
-
- {{ "number" | i18n }} - {{ - cipher.card.maskedNumber | creditCardNumber: cipher.card.brand - }} - {{ - cipher.card.number | creditCardNumber: cipher.card.brand - }} -
-
- - -
-
-
- {{ "brand" | i18n }} - {{ cipher.card.brand }} -
-
- {{ "expiration" | i18n }} - {{ cipher.card.expiration }} -
-
-
- {{ "securityCode" | i18n }} - {{ cipher.card.maskedCode }} - {{ cipher.card.code }} -
-
- - -
-
-
- -
-
- {{ "identityName" | i18n }} - {{ cipher.identity.fullName }} -
-
- {{ "username" | i18n }} - {{ cipher.identity.username }} -
-
- {{ "company" | i18n }} - {{ cipher.identity.company }} -
-
- {{ "ssn" | i18n }} - {{ cipher.identity.ssn }} -
-
- {{ "passportNumber" | i18n }} - {{ cipher.identity.passportNumber }} -
-
- {{ "licenseNumber" | i18n }} - {{ cipher.identity.licenseNumber }} -
-
- {{ "email" | i18n }} - {{ cipher.identity.email }} -
-
- {{ "phone" | i18n }} - {{ cipher.identity.phone }} -
-
- {{ "address" | i18n }} -
{{ cipher.identity.address1 }}
-
{{ cipher.identity.address2 }}
-
{{ cipher.identity.address3 }}
-
{{ cipher.identity.fullAddressPart2 }}
-
{{ cipher.identity.country }}
-
-
- -
-
- - {{ "sshPrivateKey" | i18n }} - -
-
-
- - {{ "sshPublicKey" | i18n }} - {{ cipher.sshKey.publicKey }} -
-
- - {{ "sshFingerprint" | i18n }} - {{ cipher.sshKey.keyFingerprint }} -
-
-
-
-
-
-
-
- - - - - -
-
- - -
-
-
-
-
-
-
- - -
-
-
-
-

- -

-
-
- -
-
-
-
- -
-
-

- {{ "attachments" | i18n }} -

-
- -
-
-
-
- - - - - - -
-
-
- -
-
diff --git a/apps/browser/src/vault/popup/components/vault/view.component.ts b/apps/browser/src/vault/popup/components/vault/view.component.ts deleted file mode 100644 index 242cff03c75..00000000000 --- a/apps/browser/src/vault/popup/components/vault/view.component.ts +++ /dev/null @@ -1,443 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { DatePipe, Location } from "@angular/common"; -import { ChangeDetectorRef, Component, NgZone, OnInit, OnDestroy } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { Subject, firstValueFrom, takeUntil, Subscription } from "rxjs"; -import { first, map } from "rxjs/operators"; - -import { ViewComponent as BaseViewComponent } from "@bitwarden/angular/vault/components/view.component"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; -import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; -import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; -import { CipherType } from "@bitwarden/common/vault/enums"; -import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; -import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; -import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; -import { DialogService } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; -import { PasswordRepromptService } from "@bitwarden/vault"; - -import { BrowserFido2UserInterfaceSession } from "../../../../autofill/fido2/services/browser-fido2-user-interface.service"; -import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service"; -import { BrowserApi } from "../../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; -import { fido2PopoutSessionData$ } from "../../utils/fido2-popout-session-data"; -import { closeViewVaultItemPopout, VaultPopoutType } from "../../utils/vault-popout-window"; - -const BroadcasterSubscriptionId = "ChildViewComponent"; - -export const AUTOFILL_ID = "autofill"; -export const SHOW_AUTOFILL_BUTTON = "show-autofill-button"; -export const COPY_USERNAME_ID = "copy-username"; -export const COPY_PASSWORD_ID = "copy-password"; -export const COPY_VERIFICATION_CODE_ID = "copy-totp"; - -type CopyAction = - | typeof COPY_USERNAME_ID - | typeof COPY_PASSWORD_ID - | typeof COPY_VERIFICATION_CODE_ID; -type LoadAction = typeof AUTOFILL_ID | typeof SHOW_AUTOFILL_BUTTON | CopyAction; - -@Component({ - selector: "app-vault-view", - templateUrl: "view.component.html", -}) -export class ViewComponent extends BaseViewComponent implements OnInit, OnDestroy { - showAttachments = true; - pageDetails: any[] = []; - tab: any; - senderTabId?: number; - loadAction?: LoadAction; - private static readonly copyActions = new Set([ - COPY_USERNAME_ID, - COPY_PASSWORD_ID, - COPY_VERIFICATION_CODE_ID, - ]); - uilocation?: "popout" | "popup" | "sidebar" | "tab"; - loadPageDetailsTimeout: number; - inPopout = false; - cipherType = CipherType; - private fido2PopoutSessionData$ = fido2PopoutSessionData$(); - private collectPageDetailsSubscription: Subscription; - - private destroy$ = new Subject(); - - constructor( - cipherService: CipherService, - folderService: FolderService, - totpService: TotpServiceAbstraction, - tokenService: TokenService, - i18nService: I18nService, - keyService: KeyService, - encryptService: EncryptService, - platformUtilsService: PlatformUtilsService, - auditService: AuditService, - private route: ActivatedRoute, - private router: Router, - private location: Location, - broadcasterService: BroadcasterService, - ngZone: NgZone, - changeDetectorRef: ChangeDetectorRef, - stateService: StateService, - eventCollectionService: EventCollectionService, - private autofillService: AutofillService, - private messagingService: MessagingService, - apiService: ApiService, - passwordRepromptService: PasswordRepromptService, - logService: LogService, - fileDownloadService: FileDownloadService, - dialogService: DialogService, - datePipe: DatePipe, - accountService: AccountService, - billingAccountProfileStateService: BillingAccountProfileStateService, - cipherAuthorizationService: CipherAuthorizationService, - ) { - super( - cipherService, - folderService, - totpService, - tokenService, - i18nService, - keyService, - encryptService, - platformUtilsService, - auditService, - window, - broadcasterService, - ngZone, - changeDetectorRef, - eventCollectionService, - apiService, - passwordRepromptService, - logService, - stateService, - fileDownloadService, - dialogService, - datePipe, - accountService, - billingAccountProfileStateService, - cipherAuthorizationService, - ); - } - - ngOnInit() { - this.route.queryParams.pipe(takeUntil(this.destroy$)).subscribe((value) => { - this.loadAction = value?.action; - this.senderTabId = parseInt(value?.senderTabId, 10) || undefined; - this.uilocation = value?.uilocation; - }); - - this.inPopout = this.uilocation === "popout" || BrowserPopupUtils.inPopout(window); - - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - if (params.cipherId) { - this.cipherId = params.cipherId; - } - - if (params.collectionId) { - this.collectionId = params.collectionId; - } - - if (!params.cipherId) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.close(); - } - - await this.load(); - }); - - super.ngOnInit(); - - this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.ngZone.run(async () => { - switch (message.command) { - case "tabChanged": - case "windowChanged": - if (this.loadPageDetailsTimeout != null) { - window.clearTimeout(this.loadPageDetailsTimeout); - } - this.loadPageDetailsTimeout = window.setTimeout(() => this.loadPageDetails(), 500); - break; - default: - break; - } - }); - }); - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - super.ngOnDestroy(); - this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); - } - - async load() { - await super.load(); - await this.loadPageDetails(); - await this.handleLoadAction(); - } - - async edit() { - if (this.cipher.isDeleted) { - return false; - } - if (!(await super.edit())) { - return false; - } - - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/edit-cipher"], { - queryParams: { - cipherId: this.cipher.id, - type: this.cipher.type, - isNew: false, - collectionId: this.collectionId, - }, - }); - return true; - } - - async clone() { - if (this.cipher.isDeleted) { - return false; - } - - if (!(await super.clone())) { - return false; - } - - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/clone-cipher"], { - queryParams: { - cloneMode: true, - cipherId: this.cipher.id, - }, - }); - return true; - } - - async share() { - if (!(await super.share())) { - return false; - } - - if (this.cipher.organizationId == null) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/share-cipher"], { - replaceUrl: true, - queryParams: { cipherId: this.cipher.id }, - }); - } - return true; - } - - async fillCipher() { - const didAutofill = await this.doAutofill(); - if (didAutofill) { - this.platformUtilsService.showToast("success", null, this.i18nService.t("autoFillSuccess")); - } - - return didAutofill; - } - - async fillCipherAndSave() { - const didAutofill = await this.doAutofill(); - - if (didAutofill) { - if (this.tab == null) { - throw new Error("No tab found."); - } - - if (this.cipher.login.uris == null) { - this.cipher.login.uris = []; - } else { - if (this.cipher.login.uris.some((uri) => uri.uri === this.tab.url)) { - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("autoFillSuccessAndSavedUri"), - ); - return; - } - } - - const loginUri = new LoginUriView(); - loginUri.uri = this.tab.url; - this.cipher.login.uris.push(loginUri); - - try { - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); - const cipher: Cipher = await this.cipherService.encrypt(this.cipher, activeUserId); - await this.cipherService.updateWithServer(cipher); - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("autoFillSuccessAndSavedUri"), - ); - this.messagingService.send("editedCipher"); - } catch { - this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError")); - } - } - } - - async restore() { - if (!this.cipher.isDeleted) { - return false; - } - if (await super.restore()) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.close(); - return true; - } - return false; - } - - async delete() { - if (await super.delete()) { - this.messagingService.send("deletedCipher"); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.close(); - return true; - } - return false; - } - - async close() { - const sessionData = await firstValueFrom(this.fido2PopoutSessionData$); - if (this.inPopout && sessionData.isFido2Session) { - BrowserFido2UserInterfaceSession.abortPopout(sessionData.sessionId); - return; - } - - if ( - BrowserPopupUtils.inSingleActionPopout(window, VaultPopoutType.viewVaultItem) && - this.senderTabId - ) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.focusTab(this.senderTabId); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - closeViewVaultItemPopout(`${VaultPopoutType.viewVaultItem}_${this.cipher.id}`); - return; - } - - this.location.back(); - } - - private async loadPageDetails() { - this.collectPageDetailsSubscription?.unsubscribe(); - this.pageDetails = []; - this.tab = this.senderTabId - ? await BrowserApi.getTab(this.senderTabId) - : await BrowserApi.getTabFromCurrentWindow(); - - if (!this.tab) { - return; - } - - this.collectPageDetailsSubscription = this.autofillService - .collectPageDetailsFromTab$(this.tab) - .pipe(takeUntil(this.destroy$)) - .subscribe((pageDetails) => (this.pageDetails = pageDetails)); - } - - private async doAutofill() { - const originalTabURL = this.tab.url?.length && new URL(this.tab.url); - - if (!(await this.promptPassword())) { - return false; - } - - const currentTabURL = this.tab.url?.length && new URL(this.tab.url); - - const originalTabHostPath = - originalTabURL && `${originalTabURL.origin}${originalTabURL.pathname}`; - const currentTabHostPath = currentTabURL && `${currentTabURL.origin}${currentTabURL.pathname}`; - - const tabUrlChanged = originalTabHostPath !== currentTabHostPath; - - if (this.pageDetails == null || this.pageDetails.length === 0 || tabUrlChanged) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("autofillError")); - return false; - } - - try { - this.totpCode = await this.autofillService.doAutoFill({ - tab: this.tab, - cipher: this.cipher, - pageDetails: this.pageDetails, - doc: window.document, - fillNewPassword: true, - allowTotpAutofill: true, - }); - if (this.totpCode != null) { - this.platformUtilsService.copyToClipboard(this.totpCode, { window: window }); - } - } catch { - this.platformUtilsService.showToast("error", null, this.i18nService.t("autofillError")); - this.changeDetectorRef.detectChanges(); - return false; - } - - return true; - } - - private async handleLoadAction() { - if (!this.loadAction || this.loadAction === SHOW_AUTOFILL_BUTTON) { - return; - } - - let loadActionSuccess = false; - if (this.loadAction === AUTOFILL_ID) { - loadActionSuccess = await this.fillCipher(); - } - - if (ViewComponent.copyActions.has(this.loadAction)) { - const { username, password } = this.cipher.login; - const copyParams: Record> = { - [COPY_USERNAME_ID]: { value: username, type: "username", name: "Username" }, - [COPY_PASSWORD_ID]: { value: password, type: "password", name: "Password" }, - [COPY_VERIFICATION_CODE_ID]: { - value: this.totpCode, - type: "verificationCodeTotp", - name: "TOTP", - }, - }; - const { value, type, name } = copyParams[this.loadAction as CopyAction]; - loadActionSuccess = await this.copy(value, type, name); - } - - if (this.inPopout) { - setTimeout(() => this.close(), loadActionSuccess ? 1000 : 0); - } - } -} diff --git a/apps/browser/src/vault/popup/settings/appearance.component.html b/apps/browser/src/vault/popup/settings/appearance.component.html deleted file mode 100644 index a431fc72a1f..00000000000 --- a/apps/browser/src/vault/popup/settings/appearance.component.html +++ /dev/null @@ -1,80 +0,0 @@ -
-
- -
-

- {{ "appearance" | i18n }} -

-
- -
-
-
-
-
-
- - -
-
- -
-
-
-
- - -
-
- -
-
-
-
- - -
-
- -
-
-
-
- - -
-
-
-
diff --git a/apps/browser/src/vault/popup/settings/appearance.component.ts b/apps/browser/src/vault/popup/settings/appearance.component.ts deleted file mode 100644 index e6d03c5b01f..00000000000 --- a/apps/browser/src/vault/popup/settings/appearance.component.ts +++ /dev/null @@ -1,75 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Component, OnInit } from "@angular/core"; -import { firstValueFrom } from "rxjs"; - -import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; -import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; -import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { ThemeType } from "@bitwarden/common/platform/enums"; -import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; - -import { enableAccountSwitching } from "../../../platform/flags"; - -@Component({ - selector: "vault-appearance", - templateUrl: "appearance.component.html", -}) -export class AppearanceComponent implements OnInit { - enableFavicon = false; - enableBadgeCounter = true; - theme: ThemeType; - themeOptions: any[]; - accountSwitcherEnabled = false; - enableRoutingAnimation: boolean; - - constructor( - private messagingService: MessagingService, - private domainSettingsService: DomainSettingsService, - private badgeSettingsService: BadgeSettingsServiceAbstraction, - i18nService: I18nService, - private themeStateService: ThemeStateService, - private animationControlService: AnimationControlService, - ) { - this.themeOptions = [ - { name: i18nService.t("default"), value: ThemeType.System }, - { name: i18nService.t("light"), value: ThemeType.Light }, - { name: i18nService.t("dark"), value: ThemeType.Dark }, - { name: "Nord", value: ThemeType.Nord }, - { name: i18nService.t("solarizedDark"), value: ThemeType.SolarizedDark }, - ]; - - this.accountSwitcherEnabled = enableAccountSwitching(); - } - - async ngOnInit() { - this.enableRoutingAnimation = await firstValueFrom( - this.animationControlService.enableRoutingAnimation$, - ); - - this.enableFavicon = await firstValueFrom(this.domainSettingsService.showFavicons$); - - this.enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$); - - this.theme = await firstValueFrom(this.themeStateService.selectedTheme$); - } - - async updateRoutingAnimation() { - await this.animationControlService.setEnableRoutingAnimation(this.enableRoutingAnimation); - } - - async updateFavicon() { - await this.domainSettingsService.setShowFavicons(this.enableFavicon); - } - - async updateBadgeCounter() { - await this.badgeSettingsService.setEnableBadgeCounter(this.enableBadgeCounter); - this.messagingService.send("bgUpdateContextMenu"); - } - - async saveTheme() { - await this.themeStateService.setSelectedTheme(this.theme); - } -} diff --git a/apps/browser/src/vault/popup/settings/folder-add-edit.component.html b/apps/browser/src/vault/popup/settings/folder-add-edit.component.html deleted file mode 100644 index 14393b83ddc..00000000000 --- a/apps/browser/src/vault/popup/settings/folder-add-edit.component.html +++ /dev/null @@ -1,49 +0,0 @@ -
-
-
- -
-

- {{ title }} -

-
- -
-
-
-
-
-
- - -
-
-
-
-
- -
-
-
-
diff --git a/apps/browser/src/vault/popup/settings/folder-add-edit.component.ts b/apps/browser/src/vault/popup/settings/folder-add-edit.component.ts deleted file mode 100644 index 122922a4d2d..00000000000 --- a/apps/browser/src/vault/popup/settings/folder-add-edit.component.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Component, OnInit } from "@angular/core"; -import { FormBuilder } from "@angular/forms"; -import { ActivatedRoute, Router } from "@angular/router"; -import { first } from "rxjs/operators"; - -import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/vault/components/folder-add-edit.component"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; -import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { DialogService } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; - -@Component({ - selector: "app-folder-add-edit", - templateUrl: "folder-add-edit.component.html", -}) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class FolderAddEditComponent extends BaseFolderAddEditComponent implements OnInit { - constructor( - folderService: FolderService, - folderApiService: FolderApiServiceAbstraction, - accountService: AccountService, - keyService: KeyService, - i18nService: I18nService, - platformUtilsService: PlatformUtilsService, - private router: Router, - private route: ActivatedRoute, - logService: LogService, - dialogService: DialogService, - formBuilder: FormBuilder, - ) { - super( - folderService, - folderApiService, - accountService, - keyService, - i18nService, - platformUtilsService, - logService, - dialogService, - formBuilder, - ); - } - - async ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (params) => { - if (params.folderId) { - this.folderId = params.folderId; - } - await this.init(); - }); - } - - async submit(): Promise { - if (await super.submit()) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/folders"]); - return true; - } - - return false; - } - - async delete(): Promise { - const confirmed = await super.delete(); - if (confirmed) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/folders"]); - } - return confirmed; - } -} diff --git a/apps/browser/src/vault/popup/settings/folders.component.html b/apps/browser/src/vault/popup/settings/folders.component.html deleted file mode 100644 index 47cdb0188d2..00000000000 --- a/apps/browser/src/vault/popup/settings/folders.component.html +++ /dev/null @@ -1,38 +0,0 @@ -
-
- -
-

- {{ "folders" | i18n }} -

-
- -
-
-
- -
-
- -
-
-
- -
-

{{ "noFolders" | i18n }}

-
-
-
diff --git a/apps/browser/src/vault/popup/settings/folders.component.ts b/apps/browser/src/vault/popup/settings/folders.component.ts deleted file mode 100644 index 1e3f182b43d..00000000000 --- a/apps/browser/src/vault/popup/settings/folders.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Component } from "@angular/core"; -import { Router } from "@angular/router"; -import { filter, map, Observable, switchMap } from "rxjs"; - -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { UserId } from "@bitwarden/common/types/guid"; -import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; - -@Component({ - selector: "app-folders", - templateUrl: "folders.component.html", -}) -export class FoldersComponent { - folders$: Observable; - - private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); - - constructor( - private folderService: FolderService, - private router: Router, - private accountService: AccountService, - ) { - this.folders$ = this.activeUserId$.pipe( - filter((userId): userId is UserId => userId != null), - switchMap((userId) => this.folderService.folderViews$(userId)), - map((folders) => { - // Remove the last folder, which is the "no folder" option folder - if (folders.length > 0) { - return folders.slice(0, folders.length - 1); - } - return folders; - }), - ); - } - - folderSelected(folder: FolderView) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/edit-folder"], { queryParams: { folderId: folder.id } }); - } - - addFolder() { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/add-folder"]); - } -} diff --git a/apps/browser/src/vault/popup/settings/sync.component.html b/apps/browser/src/vault/popup/settings/sync.component.html deleted file mode 100644 index 6d0a1c31a8b..00000000000 --- a/apps/browser/src/vault/popup/settings/sync.component.html +++ /dev/null @@ -1,35 +0,0 @@ -
-
- -
-

- {{ "sync" | i18n }} -

-
-
-
-
- -

- {{ "lastSync" | i18n }} {{ lastSync }} -

-
-
diff --git a/apps/browser/src/vault/popup/settings/sync.component.ts b/apps/browser/src/vault/popup/settings/sync.component.ts deleted file mode 100644 index 6585a71d94b..00000000000 --- a/apps/browser/src/vault/popup/settings/sync.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Component, OnInit } from "@angular/core"; - -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { SyncService } from "@bitwarden/common/platform/sync"; - -@Component({ - selector: "app-sync", - templateUrl: "sync.component.html", -}) -export class SyncComponent implements OnInit { - lastSync = "--"; - syncPromise: Promise; - - constructor( - private syncService: SyncService, - private platformUtilsService: PlatformUtilsService, - private i18nService: I18nService, - ) {} - - async ngOnInit() { - await this.setLastSync(); - } - - async sync() { - this.syncPromise = this.syncService.fullSync(true); - const success = await this.syncPromise; - if (success) { - await this.setLastSync(); - this.platformUtilsService.showToast("success", null, this.i18nService.t("syncingComplete")); - } else { - this.platformUtilsService.showToast("error", null, this.i18nService.t("syncingFailed")); - } - } - - async setLastSync() { - const last = await this.syncService.getLastSync(); - if (last != null) { - this.lastSync = last.toLocaleDateString() + " " + last.toLocaleTimeString(); - } else { - this.lastSync = this.i18nService.t("never"); - } - } -} diff --git a/apps/browser/src/vault/popup/settings/vault-settings.component.html b/apps/browser/src/vault/popup/settings/vault-settings.component.html deleted file mode 100644 index 4928720e46e..00000000000 --- a/apps/browser/src/vault/popup/settings/vault-settings.component.html +++ /dev/null @@ -1,56 +0,0 @@ - -
- -
-

- {{ "vault" | i18n }} -

-
- -
-
-
-
-
- - - - -
-
-
diff --git a/apps/browser/src/vault/popup/settings/vault-settings.component.ts b/apps/browser/src/vault/popup/settings/vault-settings.component.ts deleted file mode 100644 index a12f6d1d5be..00000000000 --- a/apps/browser/src/vault/popup/settings/vault-settings.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component } from "@angular/core"; -import { Router } from "@angular/router"; - -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; - -import { BrowserApi } from "../../../platform/browser/browser-api"; -import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; - -@Component({ - selector: "vault-settings", - templateUrl: "vault-settings.component.html", -}) -export class VaultSettingsComponent { - constructor( - public messagingService: MessagingService, - private router: Router, - ) {} - - async import() { - await this.router.navigate(["/import"]); - if (await BrowserApi.isPopupOpen()) { - await BrowserPopupUtils.openCurrentPagePopout(window); - } - } -} From 066773e9834e679afe308ef1b215b9c280f3dd1b Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Mon, 6 Jan 2025 16:05:29 -0500 Subject: [PATCH 13/18] [PM-16524] move integration page shared components into admin console ownership (#12664) * move integrations shared components to AC ownership * fix stories --- .../integrations/integrations.component.ts | 4 +++- .../shared/components/integrations/index.ts | 4 ++++ .../integration-card.component.html | 0 .../integration-card.component.spec.ts | 0 .../integration-card.component.ts | 2 +- .../integration-card.stories.ts | 17 ++++++--------- .../integration-grid.component.html | 0 .../integration-grid.component.spec.ts | 0 .../integration-grid.component.ts | 2 +- .../integration-grid.stories.ts | 21 +++++++------------ .../integrations/integrations.pipe.ts | 0 .../shared/components/integrations/models.ts | 0 apps/web/src/app/shared/components/index.ts | 4 ---- apps/web/src/app/shared/index.ts | 1 - .../integrations.component.spec.ts | 7 +++---- .../integrations/integrations.component.ts | 2 +- .../integrations/integrations.module.ts | 6 ++---- 17 files changed, 28 insertions(+), 42 deletions(-) create mode 100644 apps/web/src/app/admin-console/organizations/shared/components/integrations/index.ts rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-card/integration-card.component.html (100%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-card/integration-card.component.spec.ts (100%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-card/integration-card.component.ts (97%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-card/integration-card.stories.ts (74%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-grid/integration-grid.component.html (100%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-grid/integration-grid.component.spec.ts (100%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-grid/integration-grid.component.ts (91%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integration-grid/integration-grid.stories.ts (75%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/integrations.pipe.ts (100%) rename apps/web/src/app/{ => admin-console/organizations}/shared/components/integrations/models.ts (100%) delete mode 100644 apps/web/src/app/shared/components/index.ts diff --git a/apps/web/src/app/admin-console/organizations/integrations/integrations.component.ts b/apps/web/src/app/admin-console/organizations/integrations/integrations.component.ts index d7ab6a6f617..e3edb41de76 100644 --- a/apps/web/src/app/admin-console/organizations/integrations/integrations.component.ts +++ b/apps/web/src/app/admin-console/organizations/integrations/integrations.component.ts @@ -9,9 +9,11 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga import { IntegrationType } from "@bitwarden/common/enums"; import { HeaderModule } from "../../../layouts/header/header.module"; -import { FilterIntegrationsPipe, IntegrationGridComponent, Integration } from "../../../shared/"; import { SharedModule } from "../../../shared/shared.module"; import { SharedOrganizationModule } from "../shared"; +import { IntegrationGridComponent } from "../shared/components/integrations/integration-grid/integration-grid.component"; +import { FilterIntegrationsPipe } from "../shared/components/integrations/integrations.pipe"; +import { Integration } from "../shared/components/integrations/models"; @Component({ selector: "ac-integrations", diff --git a/apps/web/src/app/admin-console/organizations/shared/components/integrations/index.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/index.ts new file mode 100644 index 00000000000..c8fe9d32652 --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/index.ts @@ -0,0 +1,4 @@ +export * from "./integrations.pipe"; +export * from "./integration-card/integration-card.component"; +export * from "./integration-grid/integration-grid.component"; +export * from "./models"; diff --git a/apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.html b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.html similarity index 100% rename from apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.html rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.html diff --git a/apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.spec.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.spec.ts similarity index 100% rename from apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.spec.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.spec.ts diff --git a/apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.ts similarity index 97% rename from apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.ts index 5e47c1e0b31..681b93413e8 100644 --- a/apps/web/src/app/shared/components/integrations/integration-card/integration-card.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component.ts @@ -15,7 +15,7 @@ import { SYSTEM_THEME_OBSERVABLE } from "@bitwarden/angular/services/injection-t import { ThemeType } from "@bitwarden/common/platform/enums"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; -import { SharedModule } from "../../../shared.module"; +import { SharedModule } from "../../../../../../shared/shared.module"; @Component({ selector: "app-integration-card", diff --git a/apps/web/src/app/shared/components/integrations/integration-card/integration-card.stories.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.stories.ts similarity index 74% rename from apps/web/src/app/shared/components/integrations/integration-card/integration-card.stories.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.stories.ts index 1d1e229740f..256bfd3d827 100644 --- a/apps/web/src/app/shared/components/integrations/integration-card/integration-card.stories.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.stories.ts @@ -1,13 +1,12 @@ -import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { importProvidersFrom } from "@angular/core"; +import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; import { of } from "rxjs"; import { SYSTEM_THEME_OBSERVABLE } from "@bitwarden/angular/services/injection-tokens"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { ThemeTypes } from "@bitwarden/common/platform/enums"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; -import { I18nMockService } from "@bitwarden/components"; -import { SharedModule } from "../../../shared.module"; +import { PreloadedEnglishI18nModule } from "../../../../../../core/tests"; import { IntegrationCardComponent } from "./integration-card.component"; @@ -17,15 +16,11 @@ export default { title: "Web/Integration Layout/Integration Card", component: IntegrationCardComponent, decorators: [ + applicationConfig({ + providers: [importProvidersFrom(PreloadedEnglishI18nModule)], + }), moduleMetadata({ - imports: [SharedModule], providers: [ - { - provide: I18nService, - useFactory: () => { - return new I18nMockService({}); - }, - }, { provide: ThemeStateService, useClass: MockThemeService, diff --git a/apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.html b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.html similarity index 100% rename from apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.html rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.html diff --git a/apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.spec.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.spec.ts similarity index 100% rename from apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.spec.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.spec.ts diff --git a/apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.ts similarity index 91% rename from apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.ts index 1ec3f0d8d48..2e3158f9894 100644 --- a/apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component.ts @@ -4,7 +4,7 @@ import { Component, Input } from "@angular/core"; import { IntegrationType } from "@bitwarden/common/enums"; -import { SharedModule } from "../../../shared.module"; +import { SharedModule } from "../../../../../../shared/shared.module"; import { IntegrationCardComponent } from "../integration-card/integration-card.component"; import { Integration } from "../models"; diff --git a/apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.stories.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.stories.ts similarity index 75% rename from apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.stories.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.stories.ts index 2ec0bccec3d..b6580af2881 100644 --- a/apps/web/src/app/shared/components/integrations/integration-grid/integration-grid.stories.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.stories.ts @@ -1,14 +1,13 @@ -import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; +import { importProvidersFrom } from "@angular/core"; +import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; import { of } from "rxjs"; import { SYSTEM_THEME_OBSERVABLE } from "@bitwarden/angular/services/injection-tokens"; import { IntegrationType } from "@bitwarden/common/enums"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { ThemeTypes } from "@bitwarden/common/platform/enums"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; -import { I18nMockService } from "@bitwarden/components"; -import { SharedModule } from "../../../shared.module"; +import { PreloadedEnglishI18nModule } from "../../../../../../core/tests"; import { IntegrationCardComponent } from "../integration-card/integration-card.component"; import { IntegrationGridComponent } from "../integration-grid/integration-grid.component"; @@ -18,18 +17,12 @@ export default { title: "Web/Integration Layout/Integration Grid", component: IntegrationGridComponent, decorators: [ + applicationConfig({ + providers: [importProvidersFrom(PreloadedEnglishI18nModule)], + }), moduleMetadata({ - imports: [IntegrationCardComponent, SharedModule], + imports: [IntegrationCardComponent], providers: [ - { - provide: I18nService, - useFactory: () => { - return new I18nMockService({ - integrationCardAriaLabel: "Go to integration", - integrationCardTooltip: "Go to integration", - }); - }, - }, { provide: ThemeStateService, useClass: MockThemeService, diff --git a/apps/web/src/app/shared/components/integrations/integrations.pipe.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/integrations.pipe.ts similarity index 100% rename from apps/web/src/app/shared/components/integrations/integrations.pipe.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/integrations.pipe.ts diff --git a/apps/web/src/app/shared/components/integrations/models.ts b/apps/web/src/app/admin-console/organizations/shared/components/integrations/models.ts similarity index 100% rename from apps/web/src/app/shared/components/integrations/models.ts rename to apps/web/src/app/admin-console/organizations/shared/components/integrations/models.ts diff --git a/apps/web/src/app/shared/components/index.ts b/apps/web/src/app/shared/components/index.ts deleted file mode 100644 index 5745a7827ff..00000000000 --- a/apps/web/src/app/shared/components/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./integrations/integration-card/integration-card.component"; -export * from "./integrations/integration-grid/integration-grid.component"; -export * from "./integrations/integrations.pipe"; -export * from "./integrations/models"; diff --git a/apps/web/src/app/shared/index.ts b/apps/web/src/app/shared/index.ts index f57648c0e40..7defcdedfda 100644 --- a/apps/web/src/app/shared/index.ts +++ b/apps/web/src/app/shared/index.ts @@ -1,3 +1,2 @@ export * from "./shared.module"; export * from "./loose-components.module"; -export * from "./components/index"; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.spec.ts b/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.spec.ts index e4a65f7ddd8..5d626da9364 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.spec.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.spec.ts @@ -5,10 +5,9 @@ import { mock } from "jest-mock-extended"; import { of } from "rxjs"; import { SharedModule } from "@bitwarden/components/src/shared"; -import { - IntegrationCardComponent, - IntegrationGridComponent, -} from "@bitwarden/web-vault/app/shared"; +import { IntegrationCardComponent } from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component"; +import { IntegrationGridComponent } from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component"; +import {} from "@bitwarden/web-vault/app/shared"; import { SYSTEM_THEME_OBSERVABLE } from "../../../../../../libs/angular/src/services/injection-tokens"; import { I18nService } from "../../../../../../libs/common/src/platform/abstractions/i18n.service"; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.ts index af15c2c8b6d..cdae129de4f 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.component.ts @@ -1,7 +1,7 @@ import { Component } from "@angular/core"; import { IntegrationType } from "@bitwarden/common/enums"; -import { Integration } from "@bitwarden/web-vault/app/shared"; +import { Integration } from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/integrations/models"; @Component({ selector: "sm-integrations", diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.module.ts index b79892f5ed6..eee426e3b07 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/integrations/integrations.module.ts @@ -1,9 +1,7 @@ import { NgModule } from "@angular/core"; -import { - IntegrationCardComponent, - IntegrationGridComponent, -} from "@bitwarden/web-vault/app/shared"; +import { IntegrationCardComponent } from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/integrations/integration-card/integration-card.component"; +import { IntegrationGridComponent } from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/integrations/integration-grid/integration-grid.component"; import { SecretsManagerSharedModule } from "../shared/sm-shared.module"; From 5a46991e4e5e21b84ad0519391204ecddb0b3266 Mon Sep 17 00:00:00 2001 From: Jason Ng Date: Mon, 6 Jan 2025 16:08:29 -0500 Subject: [PATCH 14/18] [PM-16696] New Device Verification Notice Learn More (#12715) * add learn more link to new device verification notification page one --- ...new-device-verification-notice-page-one.component.html | 8 ++++++++ .../new-device-verification-notice-page-one.component.ts | 2 ++ 2 files changed, 10 insertions(+) diff --git a/libs/vault/src/components/new-device-verification-notice/new-device-verification-notice-page-one.component.html b/libs/vault/src/components/new-device-verification-notice/new-device-verification-notice-page-one.component.html index 316df3aed17..ddff560fd00 100644 --- a/libs/vault/src/components/new-device-verification-notice/new-device-verification-notice-page-one.component.html +++ b/libs/vault/src/components/new-device-verification-notice/new-device-verification-notice-page-one.component.html @@ -1,6 +1,14 @@

{{ "newDeviceVerificationNoticeContentPage1" | i18n }} + + {{ "learnMore" | i18n }}. +

Date: Mon, 6 Jan 2025 13:52:42 -0800 Subject: [PATCH 15/18] [PM-13365] - don't display totp capture when in popout (#12645) * don't display totp capture when in popout * add canCaptureTotp method * dry up logic * add unit tests * fix failing tests * add missing mock to cipher-form story --- .../services/browser-totp-capture.service.spec.ts | 15 +++++++++++++++ .../services/browser-totp-capture.service.ts | 5 +++++ .../abstractions/totp-capture.service.ts | 5 +++++ libs/vault/src/cipher-form/cipher-form.stories.ts | 1 + .../login-details-section.component.spec.ts | 4 +++- .../login-details-section.component.ts | 8 ++++++-- 6 files changed, 35 insertions(+), 3 deletions(-) diff --git a/apps/browser/src/vault/popup/services/browser-totp-capture.service.spec.ts b/apps/browser/src/vault/popup/services/browser-totp-capture.service.spec.ts index 2c9afacffd7..2b309e8f817 100644 --- a/apps/browser/src/vault/popup/services/browser-totp-capture.service.spec.ts +++ b/apps/browser/src/vault/popup/services/browser-totp-capture.service.spec.ts @@ -2,6 +2,7 @@ import { TestBed } from "@angular/core/testing"; import qrcodeParser from "qrcode-parser"; import { BrowserApi } from "../../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; import { BrowserTotpCaptureService } from "./browser-totp-capture.service"; @@ -13,12 +14,14 @@ describe("BrowserTotpCaptureService", () => { let testBed: TestBed; let service: BrowserTotpCaptureService; let mockCaptureVisibleTab: jest.SpyInstance; + let mockBrowserPopupUtilsInPopout: jest.SpyInstance; const validTotpUrl = "otpauth://totp/label?secret=123"; beforeEach(() => { mockCaptureVisibleTab = jest.spyOn(BrowserApi, "captureVisibleTab"); mockCaptureVisibleTab.mockResolvedValue("screenshot"); + mockBrowserPopupUtilsInPopout = jest.spyOn(BrowserPopupUtils, "inPopout"); testBed = TestBed.configureTestingModule({ providers: [BrowserTotpCaptureService], @@ -66,4 +69,16 @@ describe("BrowserTotpCaptureService", () => { expect(result).toBeNull(); }); + + describe("canCaptureTotp", () => { + it("should return true when not in a popout window", () => { + mockBrowserPopupUtilsInPopout.mockReturnValue(false); + expect(service.canCaptureTotp({} as Window)).toBe(true); + }); + + it("should return false when in a popout window", () => { + mockBrowserPopupUtilsInPopout.mockReturnValue(true); + expect(service.canCaptureTotp({} as Window)).toBe(false); + }); + }); }); diff --git a/apps/browser/src/vault/popup/services/browser-totp-capture.service.ts b/apps/browser/src/vault/popup/services/browser-totp-capture.service.ts index 3f8ba61ed36..ac73b271c84 100644 --- a/apps/browser/src/vault/popup/services/browser-totp-capture.service.ts +++ b/apps/browser/src/vault/popup/services/browser-totp-capture.service.ts @@ -4,6 +4,7 @@ import qrcodeParser from "qrcode-parser"; import { TotpCaptureService } from "@bitwarden/vault"; import { BrowserApi } from "../../../platform/browser/browser-api"; +import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils"; /** * Implementation of TotpCaptureService for the browser which captures the @@ -20,4 +21,8 @@ export class BrowserTotpCaptureService implements TotpCaptureService { } return null; } + + canCaptureTotp(window: Window) { + return !BrowserPopupUtils.inPopout(window); + } } diff --git a/libs/vault/src/cipher-form/abstractions/totp-capture.service.ts b/libs/vault/src/cipher-form/abstractions/totp-capture.service.ts index d6d95565869..72bbb0da12c 100644 --- a/libs/vault/src/cipher-form/abstractions/totp-capture.service.ts +++ b/libs/vault/src/cipher-form/abstractions/totp-capture.service.ts @@ -6,4 +6,9 @@ export abstract class TotpCaptureService { * Captures a TOTP secret and returns it as a string. Returns null if no TOTP secret was found. */ abstract captureTotpSecret(): Promise; + /** + * Returns whether the TOTP secret can be captured from the current tab. + * Only available in the browser extension and when not in a popout window. + */ + abstract canCaptureTotp(window: Window): boolean; } diff --git a/libs/vault/src/cipher-form/cipher-form.stories.ts b/libs/vault/src/cipher-form/cipher-form.stories.ts index 1d44e4542bc..72c4acb23cd 100644 --- a/libs/vault/src/cipher-form/cipher-form.stories.ts +++ b/libs/vault/src/cipher-form/cipher-form.stories.ts @@ -152,6 +152,7 @@ export default { provide: TotpCaptureService, useValue: { captureTotpSecret: () => Promise.resolve("some-value"), + canCaptureTotp: () => true, }, }, { diff --git a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts index 232a4b2d27b..182427f7f42 100644 --- a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts +++ b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts @@ -434,6 +434,7 @@ describe("LoginDetailsSectionComponent", () => { }); it("should call captureTotp when the capture totp button is clicked", fakeAsync(() => { + jest.spyOn(component, "canCaptureTotp", "get").mockReturnValue(true); component.captureTotp = jest.fn(); fixture.detectChanges(); @@ -445,7 +446,8 @@ describe("LoginDetailsSectionComponent", () => { })); describe("canCaptureTotp", () => { - it("should return true when totpCaptureService is present and totp is editable", () => { + it("should return true when totpCaptureService is present and totpCaptureService.canCaptureTotp is true and totp is editable", () => { + jest.spyOn(component, "canCaptureTotp", "get").mockReturnValue(true); component.loginDetailsForm.controls.totp.enable(); expect(component.canCaptureTotp).toBe(true); }); diff --git a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts index 0a6772e5ef1..2296932aca3 100644 --- a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts +++ b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts @@ -65,10 +65,14 @@ export class LoginDetailsSectionComponent implements OnInit { newPasswordGenerated: boolean; /** - * Whether the TOTP field can be captured from the current tab. Only available in the browser extension. + * Whether the TOTP field can be captured from the current tab. Only available in the browser extension and + * when not in a popout window. */ get canCaptureTotp() { - return this.totpCaptureService != null && this.loginDetailsForm.controls.totp.enabled; + return ( + !!this.totpCaptureService?.canCaptureTotp(window) && + this.loginDetailsForm.controls.totp.enabled + ); } private datePipe = inject(DatePipe); From 15faf52f57a0e0f8e0cb2b48e91216f6b1045907 Mon Sep 17 00:00:00 2001 From: Jonathan Prusik Date: Mon, 6 Jan 2025 17:10:34 -0500 Subject: [PATCH 16/18] [PM-13115] Allow users to disable extension content script injections by domain (#11826) * add disabledInteractionsUris state to the domain settings service * add routes and ui for user disabledInteractionsUris state management * use disabled URIs service state as a preemptive conditon to injecting content scripts * move disabled domains navigation button from account security settings to autofill settings * update disabled domain terminology to blocked domain terminology * update copy * handle blocked domains initializing with null value * add dismissable banner to the vault view when the active autofill tab is on the blocked domains list * add autofill blocked domain indicators to autofill suggestions section header * add BlockBrowserInjectionsByDomain feature flag and put feature behind it * update router config to new style * update tests and cleanup * use full-width-notice slot for domain script injection blocked banner * convert thrown error on content script injection block to a warning and early return * simplify and enspeeden state resolution for blockedInteractionsUris * refactor feature flag state fetching and update tests * document domain settings service * remove vault component presentational updates --- apps/browser/src/_locales/en/messages.json | 15 ++ .../background/overlay.background.spec.ts | 8 +- .../overlay.background.deprecated.spec.ts | 6 +- .../popup/settings/autofill-v1.component.html | 12 + .../popup/settings/autofill-v1.component.ts | 5 + .../popup/settings/autofill.component.html | 6 + .../popup/settings/autofill.component.ts | 7 +- .../settings/blocked-domains.component.html | 66 ++++++ .../settings/blocked-domains.component.ts | 208 ++++++++++++++++++ .../settings/excluded-domains.component.ts | 37 ++-- .../services/autofill.service.spec.ts | 13 +- .../browser/src/background/main.background.ts | 7 +- .../browser-script-injector.service.spec.ts | 102 ++++++++- .../browser-script-injector.service.ts | 28 +++ apps/browser/src/popup/app-routing.module.ts | 7 + .../src/popup/services/services.module.ts | 4 +- .../fileless-importer.background.spec.ts | 34 +-- .../service-container/service-container.ts | 43 ++-- .../src/services/jslib-services.module.ts | 10 +- .../services/domain-settings.service.spec.ts | 9 +- .../services/domain-settings.service.ts | 69 +++++- libs/common/src/enums/feature-flag.enum.ts | 2 + .../src/models/domain/domain-service.ts | 2 +- 23 files changed, 623 insertions(+), 77 deletions(-) create mode 100644 apps/browser/src/autofill/popup/settings/blocked-domains.component.html create mode 100644 apps/browser/src/autofill/popup/settings/blocked-domains.component.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 06f11406b68..85937b63304 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2324,6 +2324,9 @@ "message": "Domains", "description": "A category title describing the concept of web domains" }, + "blockedDomains": { + "message": "Blocked domains" + }, "excludedDomains": { "message": "Excluded domains" }, @@ -2333,6 +2336,15 @@ "excludedDomainsDescAlt": { "message": "Bitwarden will not ask to save login details for these domains for all logged in accounts. You must refresh the page for changes to take effect." }, + "blockedDomainsDesc": { + "message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." + }, + "autofillBlockedNotice": { + "message": "Autofill is blocked for this website. Review or change this in settings." + }, + "autofillBlockedTooltip": { + "message": "Autofill is blocked on this website. Review in settings." + }, "websiteItemLabel": { "message": "Website $number$ (URI)", "placeholders": { @@ -2351,6 +2363,9 @@ } } }, + "blockedDomainsSavedSuccess": { + "message": "Blocked domain changes saved" + }, "excludedDomainsSavedSuccess": { "message": "Excluded domain changes saved" }, diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index e7b72b72c9b..512a9ff4c2a 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -1,5 +1,5 @@ import { mock, MockProxy, mockReset } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, of } from "rxjs"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -14,6 +14,7 @@ import { } from "@bitwarden/common/autofill/services/domain-settings.service"; import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { NeverDomains } from "@bitwarden/common/models/domain/domain-service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService, Region, @@ -93,6 +94,7 @@ describe("OverlayBackground", () => { let logService: MockProxy; let cipherService: MockProxy; let autofillService: MockProxy; + let configService: MockProxy; let activeAccountStatusMock$: BehaviorSubject; let authService: MockProxy; let environmentMock$: BehaviorSubject; @@ -149,11 +151,13 @@ describe("OverlayBackground", () => { } beforeEach(() => { + configService = mock(); + configService.getFeatureFlag$.mockImplementation(() => of(true)); accountService = mockAccountServiceWith(mockUserId); fakeStateProvider = new FakeStateProvider(accountService); showFaviconsMock$ = new BehaviorSubject(true); neverDomainsMock$ = new BehaviorSubject({}); - domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); + domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService); domainSettingsService.showFavicons$ = showFaviconsMock$; domainSettingsService.neverDomains$ = neverDomainsMock$; logService = mock(); diff --git a/apps/browser/src/autofill/deprecated/background/overlay.background.deprecated.spec.ts b/apps/browser/src/autofill/deprecated/background/overlay.background.deprecated.spec.ts index 3adaf9e276c..2c22097f3d0 100644 --- a/apps/browser/src/autofill/deprecated/background/overlay.background.deprecated.spec.ts +++ b/apps/browser/src/autofill/deprecated/background/overlay.background.deprecated.spec.ts @@ -12,6 +12,7 @@ import { DefaultDomainSettingsService, DomainSettingsService, } from "@bitwarden/common/autofill/services/domain-settings.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService, Region, @@ -61,6 +62,7 @@ describe("OverlayBackground", () => { let overlayBackground: LegacyOverlayBackground; const cipherService = mock(); const autofillService = mock(); + let configService: MockProxy; let activeAccountStatusMock$: BehaviorSubject; let authService: MockProxy; @@ -92,7 +94,9 @@ describe("OverlayBackground", () => { }; beforeEach(() => { - domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); + configService = mock(); + configService.getFeatureFlag$.mockImplementation(() => of(true)); + domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService); activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked); authService = mock(); authService.activeAccountStatus$ = activeAccountStatusMock$; diff --git a/apps/browser/src/autofill/popup/settings/autofill-v1.component.html b/apps/browser/src/autofill/popup/settings/autofill-v1.component.html index 530519e88f1..1c16ee1fe12 100644 --- a/apps/browser/src/autofill/popup/settings/autofill-v1.component.html +++ b/apps/browser/src/autofill/popup/settings/autofill-v1.component.html @@ -255,4 +255,16 @@

{{ "additionalOptions" | i18n }}

{{ "showIdentitiesCurrentTabDesc" | i18n }} +
+
+ +
+
diff --git a/apps/browser/src/autofill/popup/settings/autofill-v1.component.ts b/apps/browser/src/autofill/popup/settings/autofill-v1.component.ts index 085ccba7e1e..9f015d990e9 100644 --- a/apps/browser/src/autofill/popup/settings/autofill-v1.component.ts +++ b/apps/browser/src/autofill/popup/settings/autofill-v1.component.ts @@ -36,6 +36,7 @@ export class AutofillV1Component implements OnInit { protected autoFillOverlayVisibilityOptions: any[]; protected disablePasswordManagerLink: string; protected inlineMenuPositioningImprovementsEnabled: boolean = false; + protected blockBrowserInjectionsByDomainEnabled: boolean = false; protected showInlineMenuIdentities: boolean = true; protected showInlineMenuCards: boolean = true; inlineMenuIsEnabled: boolean = false; @@ -120,6 +121,10 @@ export class AutofillV1Component implements OnInit { FeatureFlag.InlineMenuPositioningImprovements, ); + this.blockBrowserInjectionsByDomainEnabled = await this.configService.getFeatureFlag( + FeatureFlag.BlockBrowserInjectionsByDomain, + ); + this.inlineMenuIsEnabled = this.isInlineMenuEnabled(); this.showInlineMenuIdentities = diff --git a/apps/browser/src/autofill/popup/settings/autofill.component.html b/apps/browser/src/autofill/popup/settings/autofill.component.html index e8882cf7bbb..eeae0a85e3f 100644 --- a/apps/browser/src/autofill/popup/settings/autofill.component.html +++ b/apps/browser/src/autofill/popup/settings/autofill.component.html @@ -282,5 +282,11 @@

{{ "additionalOptions" | i18n }}

+ + + {{ "blockedDomains" | i18n }} + + + diff --git a/apps/browser/src/autofill/popup/settings/autofill.component.ts b/apps/browser/src/autofill/popup/settings/autofill.component.ts index da997f550b3..884503fa360 100644 --- a/apps/browser/src/autofill/popup/settings/autofill.component.ts +++ b/apps/browser/src/autofill/popup/settings/autofill.component.ts @@ -49,7 +49,6 @@ import { import { BrowserApi } from "../../../platform/browser/browser-api"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; -import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; @@ -67,7 +66,6 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co JslibModule, LinkModule, PopOutComponent, - PopupFooterComponent, PopupHeaderComponent, PopupPageComponent, RouterModule, @@ -87,6 +85,7 @@ export class AutofillComponent implements OnInit { protected inlineMenuVisibility: InlineMenuVisibilitySetting = AutofillOverlayVisibility.OnFieldFocus; protected inlineMenuPositioningImprovementsEnabled: boolean = false; + protected blockBrowserInjectionsByDomainEnabled: boolean = false; protected browserClientVendor: BrowserClientVendor = BrowserClientVendors.Unknown; protected disablePasswordManagerURI: DisablePasswordManagerUri = DisablePasswordManagerUris.Unknown; @@ -164,6 +163,10 @@ export class AutofillComponent implements OnInit { FeatureFlag.InlineMenuPositioningImprovements, ); + this.blockBrowserInjectionsByDomainEnabled = await this.configService.getFeatureFlag( + FeatureFlag.BlockBrowserInjectionsByDomain, + ); + this.showInlineMenuIdentities = this.inlineMenuPositioningImprovementsEnabled && (await firstValueFrom(this.autofillSettingsService.showInlineMenuIdentities$)); diff --git a/apps/browser/src/autofill/popup/settings/blocked-domains.component.html b/apps/browser/src/autofill/popup/settings/blocked-domains.component.html new file mode 100644 index 00000000000..bf5f40f2b90 --- /dev/null +++ b/apps/browser/src/autofill/popup/settings/blocked-domains.component.html @@ -0,0 +1,66 @@ + + + + + + + +
+

{{ "blockedDomainsDesc" | i18n }}

+ + +

{{ "domainsTitle" | i18n }}

+ {{ blockedDomainsState?.length || 0 }} +
+ + + + + {{ + "websiteItemLabel" | i18n: i + 1 + }} + +
{{ domain }}
+
+ +
+
+ +
+
+ + + +
diff --git a/apps/browser/src/autofill/popup/settings/blocked-domains.component.ts b/apps/browser/src/autofill/popup/settings/blocked-domains.component.ts new file mode 100644 index 00000000000..461f62da6dc --- /dev/null +++ b/apps/browser/src/autofill/popup/settings/blocked-domains.component.ts @@ -0,0 +1,208 @@ +import { CommonModule } from "@angular/common"; +import { + QueryList, + Component, + ElementRef, + OnDestroy, + AfterViewInit, + ViewChildren, +} from "@angular/core"; +import { FormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; +import { Subject, takeUntil } from "rxjs"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; +import { NeverDomains } from "@bitwarden/common/models/domain/domain-service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { + ButtonModule, + CardComponent, + FormFieldModule, + IconButtonModule, + ItemModule, + LinkModule, + SectionComponent, + SectionHeaderComponent, + ToastService, + TypographyModule, +} from "@bitwarden/components"; + +import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; +import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component"; +import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; +import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component"; + +@Component({ + selector: "app-blocked-domains", + templateUrl: "blocked-domains.component.html", + standalone: true, + imports: [ + ButtonModule, + CardComponent, + CommonModule, + FormFieldModule, + FormsModule, + IconButtonModule, + ItemModule, + JslibModule, + LinkModule, + PopOutComponent, + PopupFooterComponent, + PopupHeaderComponent, + PopupPageComponent, + RouterModule, + SectionComponent, + SectionHeaderComponent, + TypographyModule, + ], +}) +export class BlockedDomainsComponent implements AfterViewInit, OnDestroy { + @ViewChildren("uriInput") uriInputElements: QueryList> = + new QueryList(); + + dataIsPristine = true; + isLoading = false; + blockedDomainsState: string[] = []; + storedBlockedDomains: string[] = []; + // How many fields should be non-editable before editable fields + fieldsEditThreshold: number = 0; + + private destroy$ = new Subject(); + + constructor( + private domainSettingsService: DomainSettingsService, + private i18nService: I18nService, + private toastService: ToastService, + ) {} + + async ngAfterViewInit() { + this.domainSettingsService.blockedInteractionsUris$ + .pipe(takeUntil(this.destroy$)) + .subscribe((neverDomains: NeverDomains) => this.handleStateUpdate(neverDomains)); + + this.uriInputElements.changes.pipe(takeUntil(this.destroy$)).subscribe(({ last }) => { + this.focusNewUriInput(last); + }); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + handleStateUpdate(neverDomains: NeverDomains) { + if (neverDomains) { + this.storedBlockedDomains = Object.keys(neverDomains); + } + + this.blockedDomainsState = [...this.storedBlockedDomains]; + + // Do not allow the first x (pre-existing) fields to be edited + this.fieldsEditThreshold = this.storedBlockedDomains.length; + + this.dataIsPristine = true; + this.isLoading = false; + } + + focusNewUriInput(elementRef: ElementRef) { + if (elementRef?.nativeElement) { + elementRef.nativeElement.focus(); + } + } + + async addNewDomain() { + // add empty field to the Domains list interface + this.blockedDomainsState.push(""); + + await this.fieldChange(); + } + + async removeDomain(i: number) { + this.blockedDomainsState.splice(i, 1); + + // If a pre-existing field was dropped, lower the edit threshold + if (i < this.fieldsEditThreshold) { + this.fieldsEditThreshold--; + } + + await this.fieldChange(); + } + + async fieldChange() { + if (this.dataIsPristine) { + this.dataIsPristine = false; + } + } + + async saveChanges() { + if (this.dataIsPristine) { + return; + } + + this.isLoading = true; + + const newBlockedDomainsSaveState: NeverDomains = {}; + const uniqueBlockedDomains = new Set(this.blockedDomainsState); + + for (const uri of uniqueBlockedDomains) { + if (uri && uri !== "") { + const validatedHost = Utils.getHostname(uri); + + if (!validatedHost) { + this.toastService.showToast({ + message: this.i18nService.t("excludedDomainsInvalidDomain", uri), + title: "", + variant: "error", + }); + + // Don't reset via `handleStateUpdate` to allow existing input value correction + this.isLoading = false; + return; + } + + newBlockedDomainsSaveState[validatedHost] = null; + } + } + + try { + const existingState = new Set(this.storedBlockedDomains); + const newState = new Set(Object.keys(newBlockedDomainsSaveState)); + const stateIsUnchanged = + existingState.size === newState.size && + new Set([...existingState, ...newState]).size === existingState.size; + + // The subscriber updates don't trigger if `setNeverDomains` sets an equivalent state + if (stateIsUnchanged) { + // Reset UI state directly + const constructedNeverDomainsState = this.storedBlockedDomains.reduce( + (neverDomains: NeverDomains, uri: string) => ({ ...neverDomains, [uri]: null }), + {}, + ); + this.handleStateUpdate(constructedNeverDomainsState); + } else { + await this.domainSettingsService.setBlockedInteractionsUris(newBlockedDomainsSaveState); + } + + this.toastService.showToast({ + message: this.i18nService.t("blockedDomainsSavedSuccess"), + title: "", + variant: "success", + }); + } catch { + this.toastService.showToast({ + message: this.i18nService.t("unexpectedError"), + title: "", + variant: "error", + }); + + // Don't reset via `handleStateUpdate` to preserve input values + this.isLoading = false; + } + } + + trackByFunction(index: number, _: string) { + return index; + } +} diff --git a/apps/browser/src/autofill/popup/settings/excluded-domains.component.ts b/apps/browser/src/autofill/popup/settings/excluded-domains.component.ts index 1391ad516fb..7d429bfe4f0 100644 --- a/apps/browser/src/autofill/popup/settings/excluded-domains.component.ts +++ b/apps/browser/src/autofill/popup/settings/excluded-domains.component.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { CommonModule } from "@angular/common"; import { QueryList, @@ -17,7 +15,6 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { NeverDomains } from "@bitwarden/common/models/domain/domain-service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ButtonModule, @@ -28,6 +25,7 @@ import { LinkModule, SectionComponent, SectionHeaderComponent, + ToastService, TypographyModule, } from "@bitwarden/components"; @@ -62,7 +60,8 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co ], }) export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy { - @ViewChildren("uriInput") uriInputElements: QueryList>; + @ViewChildren("uriInput") uriInputElements: QueryList> = + new QueryList(); accountSwitcherEnabled = false; dataIsPristine = true; @@ -77,7 +76,7 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy { constructor( private domainSettingsService: DomainSettingsService, private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, + private toastService: ToastService, ) { this.accountSwitcherEnabled = enableAccountSwitching(); } @@ -156,11 +155,11 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy { const validatedHost = Utils.getHostname(uri); if (!validatedHost) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("excludedDomainsInvalidDomain", uri), - ); + this.toastService.showToast({ + message: this.i18nService.t("excludedDomainsInvalidDomain", uri), + title: "", + variant: "error", + }); // Don't reset via `handleStateUpdate` to allow existing input value correction this.isLoading = false; @@ -182,7 +181,7 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy { if (stateIsUnchanged) { // Reset UI state directly const constructedNeverDomainsState = this.storedExcludedDomains.reduce( - (neverDomains, uri) => ({ ...neverDomains, [uri]: null }), + (neverDomains: NeverDomains, uri: string) => ({ ...neverDomains, [uri]: null }), {}, ); this.handleStateUpdate(constructedNeverDomainsState); @@ -190,13 +189,17 @@ export class ExcludedDomainsComponent implements AfterViewInit, OnDestroy { await this.domainSettingsService.setNeverDomains(newExcludedDomainsSaveState); } - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("excludedDomainsSavedSuccess"), - ); + this.toastService.showToast({ + message: this.i18nService.t("excludedDomainsSavedSuccess"), + title: "", + variant: "success", + }); } catch { - this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError")); + this.toastService.showToast({ + message: this.i18nService.t("unexpectedError"), + title: "", + variant: "error", + }); // Don't reset via `handleStateUpdate` to preserve input values this.isLoading = false; diff --git a/apps/browser/src/autofill/services/autofill.service.spec.ts b/apps/browser/src/autofill/services/autofill.service.spec.ts index 91f926440a0..77d73d7ae65 100644 --- a/apps/browser/src/autofill/services/autofill.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill.service.spec.ts @@ -98,7 +98,13 @@ describe("AutofillService", () => { let messageListener: MockProxy; beforeEach(() => { - scriptInjectorService = new BrowserScriptInjectorService(platformUtilsService, logService); + configService = mock(); + configService.getFeatureFlag$.mockImplementation(() => of(false)); + scriptInjectorService = new BrowserScriptInjectorService( + domainSettingsService, + platformUtilsService, + logService, + ); inlineMenuVisibilityMock$ = new BehaviorSubject(AutofillOverlayVisibility.OnFieldFocus); showInlineMenuCardsMock$ = new BehaviorSubject(false); showInlineMenuIdentitiesMock$ = new BehaviorSubject(false); @@ -106,10 +112,10 @@ describe("AutofillService", () => { autofillSettingsService.inlineMenuVisibility$ = inlineMenuVisibilityMock$; autofillSettingsService.showInlineMenuCards$ = showInlineMenuCardsMock$; autofillSettingsService.showInlineMenuIdentities$ = showInlineMenuIdentitiesMock$; + autofillSettingsService.autofillOnPageLoad$ = of(true); activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked); authService = mock(); authService.activeAccountStatus$ = activeAccountStatusMock$; - configService = mock(); messageListener = mock(); enableChangedPasswordPromptMock$ = new BehaviorSubject(true); enableAddedLoginPromptMock$ = new BehaviorSubject(true); @@ -132,7 +138,7 @@ describe("AutofillService", () => { userNotificationsSettings, messageListener, ); - domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); + domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService); domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains); jest.spyOn(BrowserApi, "tabSendMessage"); }); @@ -385,6 +391,7 @@ describe("AutofillService", () => { ); tabMock = createChromeTabMock(); sender = { tab: tabMock, frameId: 1 }; + jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock); jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation(); jest .spyOn(autofillService, "getInlineMenuVisibility") diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 555e3a13fa0..34c10508485 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -695,7 +695,6 @@ export default class MainBackground { this.vaultTimeoutSettingsService, ); - this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider); this.fileUploadService = new FileUploadService(this.logService, this.apiService); this.cipherFileUploadService = new CipherFileUploadService( this.apiService, @@ -809,6 +808,11 @@ export default class MainBackground { this.authService, ); + this.domainSettingsService = new DefaultDomainSettingsService( + this.stateProvider, + this.configService, + ); + this.themeStateService = new DefaultThemeStateService( this.globalStateProvider, this.configService, @@ -957,6 +961,7 @@ export default class MainBackground { this.totpService = new TotpService(this.cryptoFunctionService, this.logService); this.scriptInjectorService = new BrowserScriptInjectorService( + this.domainSettingsService, this.platformUtilsService, this.logService, ); diff --git a/apps/browser/src/platform/services/browser-script-injector.service.spec.ts b/apps/browser/src/platform/services/browser-script-injector.service.spec.ts index d6ec3dfde96..0919de46776 100644 --- a/apps/browser/src/platform/services/browser-script-injector.service.spec.ts +++ b/apps/browser/src/platform/services/browser-script-injector.service.spec.ts @@ -1,8 +1,22 @@ -import { mock } from "jest-mock-extended"; +import { mock, MockProxy } from "jest-mock-extended"; +import { of } from "rxjs"; +import { + DomainSettingsService, + DefaultDomainSettingsService, +} from "@bitwarden/common/autofill/services/domain-settings.service"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { + FakeStateProvider, + FakeAccountService, + mockAccountServiceWith, +} from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; +import { createChromeTabMock } from "../../autofill/spec/autofill-mocks"; import { BrowserApi } from "../browser/browser-api"; import { @@ -11,8 +25,19 @@ import { } from "./abstractions/script-injector.service"; import { BrowserScriptInjectorService } from "./browser-script-injector.service"; +const mockEquivalentDomains = [ + ["example.com", "exampleapp.com", "example.co.uk", "ejemplo.es"], + ["bitwarden.com", "bitwarden.co.uk", "sm-bitwarden.com"], + ["example.co.uk", "exampleapp.co.uk"], +]; + describe("ScriptInjectorService", () => { const tabId = 1; + const tabMock = createChromeTabMock({ id: tabId }); + const mockBlockedURI = new URL(tabMock.url); + jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation(); + jest.spyOn(BrowserApi, "isManifestVersion"); + const combinedManifestVersionFile = "content/autofill-init.js"; const mv2SpecificFile = "content/autofill-init-mv2.js"; const mv2Details = { file: mv2SpecificFile }; @@ -22,14 +47,29 @@ describe("ScriptInjectorService", () => { runAt: "document_start", }; const manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get"); + let scriptInjectorService: BrowserScriptInjectorService; - jest.spyOn(BrowserApi, "executeScriptInTab").mockImplementation(); - jest.spyOn(BrowserApi, "isManifestVersion"); - const platformUtilsService = mock(); const logService = mock(); + const platformUtilsService = mock(); + const mockUserId = Utils.newGuid() as UserId; + const accountService: FakeAccountService = mockAccountServiceWith(mockUserId); + const fakeStateProvider: FakeStateProvider = new FakeStateProvider(accountService); + let configService: MockProxy; + let domainSettingsService: DomainSettingsService; beforeEach(() => { - scriptInjectorService = new BrowserScriptInjectorService(platformUtilsService, logService); + jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock); + configService = mock(); + configService.getFeatureFlag$.mockImplementation(() => of(false)); + domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService); + domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains); + domainSettingsService.blockedInteractionsUris$ = of(null); + scriptInjectorService = new BrowserScriptInjectorService( + domainSettingsService, + platformUtilsService, + logService, + ); + jest.spyOn(scriptInjectorService as any, "buildInjectionDetails"); }); describe("inject", () => { @@ -71,6 +111,58 @@ describe("ScriptInjectorService", () => { { world: "ISOLATED" }, ); }); + + it("skips injecting the script in manifest v3 when the tab domain is a blocked domain", async () => { + domainSettingsService.blockedInteractionsUris$ = of({ [mockBlockedURI.host]: null }); + manifestVersionSpy.mockReturnValue(3); + + await expect(scriptInjectorService["buildInjectionDetails"]).not.toHaveBeenCalled(); + }); + + it("skips injecting the script in manifest v2 when the tab domain is a blocked domain", async () => { + domainSettingsService.blockedInteractionsUris$ = of({ [mockBlockedURI.host]: null }); + manifestVersionSpy.mockReturnValue(2); + + await expect(scriptInjectorService["buildInjectionDetails"]).not.toHaveBeenCalled(); + }); + + it("injects the script in manifest v2 when given combined injection details", async () => { + manifestVersionSpy.mockReturnValue(2); + + await scriptInjectorService.inject({ + tabId, + injectDetails: { + file: combinedManifestVersionFile, + frame: "all_frames", + ...sharedInjectDetails, + }, + }); + + expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith(tabId, { + ...sharedInjectDetails, + allFrames: true, + file: combinedManifestVersionFile, + }); + }); + + it("injects the script in manifest v3 when given combined injection details", async () => { + manifestVersionSpy.mockReturnValue(3); + + await scriptInjectorService.inject({ + tabId, + injectDetails: { + file: combinedManifestVersionFile, + frame: 10, + ...sharedInjectDetails, + }, + }); + + expect(BrowserApi.executeScriptInTab).toHaveBeenCalledWith( + tabId, + { ...sharedInjectDetails, frameId: 10, file: combinedManifestVersionFile }, + { world: "ISOLATED" }, + ); + }); }); describe("injection of mv2 specific details", () => { diff --git a/apps/browser/src/platform/services/browser-script-injector.service.ts b/apps/browser/src/platform/services/browser-script-injector.service.ts index 2a6b7397a6c..c2bace669dc 100644 --- a/apps/browser/src/platform/services/browser-script-injector.service.ts +++ b/apps/browser/src/platform/services/browser-script-injector.service.ts @@ -1,3 +1,6 @@ +import { firstValueFrom } from "rxjs"; + +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -12,7 +15,10 @@ import { } from "./abstractions/script-injector.service"; export class BrowserScriptInjectorService extends ScriptInjectorService { + blockedDomains: Set = null; + constructor( + private readonly domainSettingsService: DomainSettingsService, private readonly platformUtilsService: PlatformUtilsService, private readonly logService: LogService, ) { @@ -32,6 +38,28 @@ export class BrowserScriptInjectorService extends ScriptInjectorService { throw new Error("No file specified for script injection"); } + const tab = tabId && (await BrowserApi.getTab(tabId)); + const tabURL = tab?.url ? new URL(tab.url) : null; + + // Check if the tab URI is on the disabled URIs list + let injectionAllowedInTab = true; + const blockedDomains = await firstValueFrom( + this.domainSettingsService.blockedInteractionsUris$, + ); + + if (blockedDomains && tabURL?.hostname) { + const blockedDomainsSet = new Set(Object.keys(blockedDomains)); + + injectionAllowedInTab = !(tabURL && blockedDomainsSet.has(tabURL.hostname)); + } + + if (!injectionAllowedInTab) { + this.logService.warning( + `${injectDetails.file} was not injected because ${tabURL?.hostname || "the tab URI"} is on the user's blocked domains list.`, + ); + return; + } + const injectionDetails = this.buildInjectionDetails(injectDetails, file); if (BrowserApi.isManifestVersion(3)) { diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 161c4ca0524..2d53ae7e239 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -75,6 +75,7 @@ import { Fido2V1Component } from "../autofill/popup/fido2/fido2-v1.component"; import { Fido2Component } from "../autofill/popup/fido2/fido2.component"; import { AutofillV1Component } from "../autofill/popup/settings/autofill-v1.component"; import { AutofillComponent } from "../autofill/popup/settings/autofill.component"; +import { BlockedDomainsComponent } from "../autofill/popup/settings/blocked-domains.component"; import { ExcludedDomainsV1Component } from "../autofill/popup/settings/excluded-domains-v1.component"; import { ExcludedDomainsComponent } from "../autofill/popup/settings/excluded-domains.component"; import { NotificationsSettingsV1Component } from "../autofill/popup/settings/notifications-v1.component"; @@ -348,6 +349,12 @@ const routes: Routes = [ canActivate: [authGuard], data: { elevation: 2 } satisfies RouteDataProperties, }, + { + path: "blocked-domains", + component: BlockedDomainsComponent, + canActivate: [authGuard], + data: { elevation: 2 } satisfies RouteDataProperties, + }, ...extensionRefreshSwap(ExcludedDomainsV1Component, ExcludedDomainsComponent, { path: "excluded-domains", canActivate: [authGuard], diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 5b27833636f..92eb8973235 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -327,7 +327,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: DomainSettingsService, useClass: DefaultDomainSettingsService, - deps: [StateProvider], + deps: [StateProvider, ConfigService], }), safeProvider({ provide: AbstractStorageService, @@ -365,7 +365,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: ScriptInjectorService, useClass: BrowserScriptInjectorService, - deps: [PlatformUtilsService, LogService], + deps: [DomainSettingsService, PlatformUtilsService, LogService], }), safeProvider({ provide: VaultTimeoutService, diff --git a/apps/browser/src/tools/background/fileless-importer.background.spec.ts b/apps/browser/src/tools/background/fileless-importer.background.spec.ts index 7b356b18fd5..429a0e12184 100644 --- a/apps/browser/src/tools/background/fileless-importer.background.spec.ts +++ b/apps/browser/src/tools/background/fileless-importer.background.spec.ts @@ -1,9 +1,10 @@ import { mock } from "jest-mock-extended"; -import { firstValueFrom } from "rxjs"; +import { of } from "rxjs"; import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @@ -23,18 +24,10 @@ import { FilelessImportPort, FilelessImportType } from "../enums/fileless-import import FilelessImporterBackground from "./fileless-importer.background"; -jest.mock("rxjs", () => { - const rxjs = jest.requireActual("rxjs"); - const { firstValueFrom } = rxjs; - return { - ...rxjs, - firstValueFrom: jest.fn(firstValueFrom), - }; -}); - describe("FilelessImporterBackground ", () => { let filelessImporterBackground: FilelessImporterBackground; const configService = mock(); + const domainSettingsService = mock(); const authService = mock(); const policyService = mock(); const notificationBackground = mock(); @@ -43,9 +36,16 @@ describe("FilelessImporterBackground ", () => { const platformUtilsService = mock(); const logService = mock(); let scriptInjectorService: BrowserScriptInjectorService; + let tabMock: chrome.tabs.Tab; beforeEach(() => { - scriptInjectorService = new BrowserScriptInjectorService(platformUtilsService, logService); + domainSettingsService.blockedInteractionsUris$ = of(null); + policyService.policyAppliesToActiveUser$.mockImplementation(() => of(true)); + scriptInjectorService = new BrowserScriptInjectorService( + domainSettingsService, + platformUtilsService, + logService, + ); filelessImporterBackground = new FilelessImporterBackground( configService, authService, @@ -75,12 +75,13 @@ describe("FilelessImporterBackground ", () => { beforeEach(() => { lpImporterPort = createPortSpyMock(FilelessImportPort.LpImporter); + tabMock = lpImporterPort.sender.tab; + jest.spyOn(BrowserApi, "getTab").mockImplementation(async () => tabMock); manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get"); executeScriptInTabSpy = jest.spyOn(BrowserApi, "executeScriptInTab").mockResolvedValue(null); jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Unlocked); jest.spyOn(configService, "getFeatureFlag").mockResolvedValue(true); jest.spyOn(filelessImporterBackground as any, "removeIndividualVault"); - (firstValueFrom as jest.Mock).mockResolvedValue(false); }); it("ignores the port connection if the port name is not present in the set of filelessImportNames", async () => { @@ -105,8 +106,6 @@ describe("FilelessImporterBackground ", () => { }); it("posts a message to the port indicating that the fileless import feature is disabled if the user's policy removes individual vaults", async () => { - (firstValueFrom as jest.Mock).mockResolvedValue(true); - triggerRuntimeOnConnectEvent(lpImporterPort); await flushPromises(); @@ -129,6 +128,8 @@ describe("FilelessImporterBackground ", () => { }); it("posts a message to the port indicating that the fileless import feature is enabled", async () => { + policyService.policyAppliesToActiveUser$.mockImplementationOnce(() => of(false)); + triggerRuntimeOnConnectEvent(lpImporterPort); await flushPromises(); @@ -139,6 +140,7 @@ describe("FilelessImporterBackground ", () => { }); it("triggers an injection of the `lp-suppress-import-download.js` script in manifest v3", async () => { + policyService.policyAppliesToActiveUser$.mockImplementationOnce(() => of(false)); manifestVersionSpy.mockReturnValue(3); triggerRuntimeOnConnectEvent(lpImporterPort); @@ -152,6 +154,7 @@ describe("FilelessImporterBackground ", () => { }); it("triggers an injection of the `lp-suppress-import-download-script-append-mv2.js` script in manifest v2", async () => { + policyService.policyAppliesToActiveUser$.mockImplementationOnce(() => of(false)); manifestVersionSpy.mockReturnValue(2); triggerRuntimeOnConnectEvent(lpImporterPort); @@ -170,9 +173,10 @@ describe("FilelessImporterBackground ", () => { let lpImporterPort: chrome.runtime.Port; beforeEach(async () => { + policyService.policyAppliesToActiveUser$.mockImplementation(() => of(false)); jest.spyOn(authService, "getAuthStatus").mockResolvedValue(AuthenticationStatus.Unlocked); jest.spyOn(configService, "getFeatureFlag").mockResolvedValue(true); - (firstValueFrom as jest.Mock).mockResolvedValue(false); + triggerRuntimeOnConnectEvent(createPortSpyMock(FilelessImportPort.NotificationBar)); triggerRuntimeOnConnectEvent(createPortSpyMock(FilelessImportPort.LpImporter)); await flushPromises(); diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 2afbae0782f..9f9e45e86d4 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -483,7 +483,29 @@ export class ServiceContainer { this.containerService = new ContainerService(this.keyService, this.encryptService); - this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider); + this.configApiService = new ConfigApiService(this.apiService, this.tokenService); + + this.authService = new AuthService( + this.accountService, + this.messagingService, + this.keyService, + this.apiService, + this.stateService, + this.tokenService, + ); + + this.configService = new DefaultConfigService( + this.configApiService, + this.environmentService, + this.logService, + this.stateProvider, + this.authService, + ); + + this.domainSettingsService = new DefaultDomainSettingsService( + this.stateProvider, + this.configService, + ); this.fileUploadService = new FileUploadService(this.logService, this.apiService); @@ -579,25 +601,6 @@ export class ServiceContainer { this.taskSchedulerService = new DefaultTaskSchedulerService(this.logService); - this.authService = new AuthService( - this.accountService, - this.messagingService, - this.keyService, - this.apiService, - this.stateService, - this.tokenService, - ); - - this.configApiService = new ConfigApiService(this.apiService, this.tokenService); - - this.configService = new DefaultConfigService( - this.configApiService, - this.environmentService, - this.logService, - this.stateProvider, - this.authService, - ); - this.devicesApiService = new DevicesApiServiceImplementation(this.apiService); this.deviceTrustService = new DeviceTrustService( this.keyGenerationService, diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 149d553696e..583ba82fc98 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -463,6 +463,11 @@ const safeProviders: SafeProvider[] = [ useClass: CipherFileUploadService, deps: [ApiServiceAbstraction, FileUploadServiceAbstraction], }), + safeProvider({ + provide: DomainSettingsService, + useClass: DefaultDomainSettingsService, + deps: [StateProvider, ConfigService], + }), safeProvider({ provide: CipherServiceAbstraction, useFactory: ( @@ -1243,11 +1248,6 @@ const safeProviders: SafeProvider[] = [ useClass: BadgeSettingsService, deps: [StateProvider], }), - safeProvider({ - provide: DomainSettingsService, - useClass: DefaultDomainSettingsService, - deps: [StateProvider], - }), safeProvider({ provide: BiometricStateService, useClass: DefaultBiometricStateService, diff --git a/libs/common/src/autofill/services/domain-settings.service.spec.ts b/libs/common/src/autofill/services/domain-settings.service.spec.ts index 24e3763eb45..a25653f168c 100644 --- a/libs/common/src/autofill/services/domain-settings.service.spec.ts +++ b/libs/common/src/autofill/services/domain-settings.service.spec.ts @@ -1,5 +1,8 @@ +import { MockProxy, mock } from "jest-mock-extended"; import { firstValueFrom, of } from "rxjs"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; + import { FakeStateProvider, FakeAccountService, mockAccountServiceWith } from "../../../spec"; import { Utils } from "../../platform/misc/utils"; import { UserId } from "../../types/guid"; @@ -8,6 +11,7 @@ import { DefaultDomainSettingsService, DomainSettingsService } from "./domain-se describe("DefaultDomainSettingsService", () => { let domainSettingsService: DomainSettingsService; + let configService: MockProxy; const mockUserId = Utils.newGuid() as UserId; const accountService: FakeAccountService = mockAccountServiceWith(mockUserId); const fakeStateProvider: FakeStateProvider = new FakeStateProvider(accountService); @@ -19,10 +23,13 @@ describe("DefaultDomainSettingsService", () => { ]; beforeEach(() => { - domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); + configService = mock(); + configService.getFeatureFlag$.mockImplementation(() => of(false)); + domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService); jest.spyOn(domainSettingsService, "getUrlEquivalentDomains"); domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains); + domainSettingsService.blockedInteractionsUris$ = of(null); }); describe("getUrlEquivalentDomains", () => { diff --git a/libs/common/src/autofill/services/domain-settings.service.ts b/libs/common/src/autofill/services/domain-settings.service.ts index 708341563e0..aeb3af69dae 100644 --- a/libs/common/src/autofill/services/domain-settings.service.ts +++ b/libs/common/src/autofill/services/domain-settings.service.ts @@ -1,6 +1,8 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { map, Observable } from "rxjs"; +import { map, Observable, switchMap, of } from "rxjs"; + +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { NeverDomains, @@ -8,6 +10,7 @@ import { UriMatchStrategySetting, UriMatchStrategy, } from "../../models/domain/domain-service"; +import { ConfigService } from "../../platform/abstractions/config/config.service"; import { Utils } from "../../platform/misc/utils"; import { DOMAIN_SETTINGS_DISK, @@ -23,10 +26,20 @@ const SHOW_FAVICONS = new KeyDefinition(DOMAIN_SETTINGS_DISK, "showFavicons", { deserializer: (value: boolean) => value ?? true, }); +// Domain exclusion list for notifications const NEVER_DOMAINS = new KeyDefinition(DOMAIN_SETTINGS_DISK, "neverDomains", { deserializer: (value: NeverDomains) => value ?? null, }); +// Domain exclusion list for content script injections +const BLOCKED_INTERACTIONS_URIS = new KeyDefinition( + DOMAIN_SETTINGS_DISK, + "blockedInteractionsUris", + { + deserializer: (value: NeverDomains) => value ?? null, + }, +); + const EQUIVALENT_DOMAINS = new UserKeyDefinition(DOMAIN_SETTINGS_DISK, "equivalentDomains", { deserializer: (value: EquivalentDomains) => value ?? null, clearOn: ["logout"], @@ -41,15 +54,45 @@ const DEFAULT_URI_MATCH_STRATEGY = new UserKeyDefinition( }, ); +/** + * The Domain Settings service; provides client settings state for "active client view" URI concerns + */ export abstract class DomainSettingsService { + /** + * Indicates if the favicons for ciphers' URIs should be shown instead of a placeholder + */ showFavicons$: Observable; setShowFavicons: (newValue: boolean) => Promise; + + /** + * User-specified URIs for which the client notifications should not appear + */ neverDomains$: Observable; setNeverDomains: (newValue: NeverDomains) => Promise; + + /** + * User-specified URIs for which client content script injections should not occur, and the state + * of banner/notice visibility for those domains within the client + */ + blockedInteractionsUris$: Observable; + setBlockedInteractionsUris: (newValue: NeverDomains) => Promise; + + /** + * URIs which should be treated as equivalent to each other for various concerns (autofill, etc) + */ equivalentDomains$: Observable; setEquivalentDomains: (newValue: EquivalentDomains, userId: UserId) => Promise; + + /** + * User-specified default for URI-matching strategies (for example, when determining relevant + * ciphers for an active browser tab). Can be overridden by cipher-specific settings. + */ defaultUriMatchStrategy$: Observable; setDefaultUriMatchStrategy: (newValue: UriMatchStrategySetting) => Promise; + + /** + * Helper function for the common resolution of a given URL against equivalent domains + */ getUrlEquivalentDomains: (url: string) => Observable>; } @@ -60,19 +103,37 @@ export class DefaultDomainSettingsService implements DomainSettingsService { private neverDomainsState: GlobalState; readonly neverDomains$: Observable; + private blockedInteractionsUrisState: GlobalState; + readonly blockedInteractionsUris$: Observable; + private equivalentDomainsState: ActiveUserState; readonly equivalentDomains$: Observable; private defaultUriMatchStrategyState: ActiveUserState; readonly defaultUriMatchStrategy$: Observable; - constructor(private stateProvider: StateProvider) { + constructor( + private stateProvider: StateProvider, + private configService: ConfigService, + ) { this.showFaviconsState = this.stateProvider.getGlobal(SHOW_FAVICONS); this.showFavicons$ = this.showFaviconsState.state$.pipe(map((x) => x ?? true)); this.neverDomainsState = this.stateProvider.getGlobal(NEVER_DOMAINS); this.neverDomains$ = this.neverDomainsState.state$.pipe(map((x) => x ?? null)); + // Needs to be global to prevent pre-login injections + this.blockedInteractionsUrisState = this.stateProvider.getGlobal(BLOCKED_INTERACTIONS_URIS); + + this.blockedInteractionsUris$ = this.configService + .getFeatureFlag$(FeatureFlag.BlockBrowserInjectionsByDomain) + .pipe( + switchMap((featureIsEnabled) => + featureIsEnabled ? this.blockedInteractionsUrisState.state$ : of({} as NeverDomains), + ), + map((disabledUris) => (Object.keys(disabledUris).length ? disabledUris : null)), + ); + this.equivalentDomainsState = this.stateProvider.getActive(EQUIVALENT_DOMAINS); this.equivalentDomains$ = this.equivalentDomainsState.state$.pipe(map((x) => x ?? null)); @@ -90,6 +151,10 @@ export class DefaultDomainSettingsService implements DomainSettingsService { await this.neverDomainsState.update(() => newValue); } + async setBlockedInteractionsUris(newValue: NeverDomains): Promise { + await this.blockedInteractionsUrisState.update(() => newValue); + } + async setEquivalentDomains(newValue: EquivalentDomains, userId: UserId): Promise { await this.stateProvider.getUser(userId, EQUIVALENT_DOMAINS).update(() => newValue); } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 135119bf133..0ab7d47acfc 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -27,6 +27,7 @@ export enum FeatureFlag { SSHKeyVaultItem = "ssh-key-vault-item", SSHAgent = "ssh-agent", NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements", + BlockBrowserInjectionsByDomain = "block-browser-injections-by-domain", AC2476_DeprecateStripeSourcesAPI = "AC-2476-deprecate-stripe-sources-api", CipherKeyEncryption = "cipher-key-encryption", VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint", @@ -81,6 +82,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.SSHKeyVaultItem]: FALSE, [FeatureFlag.SSHAgent]: FALSE, [FeatureFlag.NotificationBarAddLoginImprovements]: FALSE, + [FeatureFlag.BlockBrowserInjectionsByDomain]: FALSE, [FeatureFlag.AC2476_DeprecateStripeSourcesAPI]: FALSE, [FeatureFlag.CipherKeyEncryption]: FALSE, [FeatureFlag.VerifiedSsoDomainEndpoint]: FALSE, diff --git a/libs/common/src/models/domain/domain-service.ts b/libs/common/src/models/domain/domain-service.ts index 9ff53cc8787..a6b5ecfdaac 100644 --- a/libs/common/src/models/domain/domain-service.ts +++ b/libs/common/src/models/domain/domain-service.ts @@ -21,5 +21,5 @@ export const UriMatchStrategy = { export type UriMatchStrategySetting = (typeof UriMatchStrategy)[keyof typeof UriMatchStrategy]; // using uniqueness properties of object shape over Set for ease of state storability -export type NeverDomains = { [id: string]: null }; +export type NeverDomains = { [id: string]: null | { bannerIsDismissed?: boolean } }; export type EquivalentDomains = string[][]; From 1075d7a79859f7b63d2364de497bddd07c4efd5d Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Mon, 6 Jan 2025 18:56:21 -0500 Subject: [PATCH 17/18] PM-16685 - Web - Fix locking (#12722) --- libs/common/src/services/vault-timeout/vault-timeout.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/common/src/services/vault-timeout/vault-timeout.service.ts b/libs/common/src/services/vault-timeout/vault-timeout.service.ts index f465174bf40..55d5bffa99a 100644 --- a/libs/common/src/services/vault-timeout/vault-timeout.service.ts +++ b/libs/common/src/services/vault-timeout/vault-timeout.service.ts @@ -138,7 +138,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { await this.collectionService.clearActiveUserCache(); } - await this.folderService.clearDecryptedFolderState(userId); + await this.folderService.clearDecryptedFolderState(lockingUserId); await this.masterPasswordService.clearMasterKey(lockingUserId); await this.stateService.setUserKeyAutoUnlock(null, { userId: lockingUserId }); From 003f5fdae9ce3fb84281f42219153971af4df26b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 13:38:19 +0100 Subject: [PATCH 18/18] [deps]: Lock file maintenance (#12709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Daniel García --- apps/desktop/desktop_native/Cargo.lock | 93 +++++++++++++------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index b40246fca2d..96c7d8955db 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "async-broadcast" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ "event-listener", "event-listener-strategy", @@ -354,9 +354,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" dependencies = [ "proc-macro2", "quote", @@ -567,9 +567,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.6" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "shlex", ] @@ -811,9 +811,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d44ff199ff93242c3afe480ab588d544dd08d72e92885e152ffebc670f076ad" +checksum = "ad7c7515609502d316ab9a24f67dc045132d93bfd3f00713389e90d9898bf30d" dependencies = [ "cc", "cxxbridge-cmd", @@ -825,9 +825,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fd8f17ad454fc1e4f4ab83abffcc88a532e90350d3ffddcb73030220fcbd52" +checksum = "8bfd16fca6fd420aebbd80d643c201ee4692114a0de208b790b9cd02ceae65fb" dependencies = [ "cc", "codespan-reporting", @@ -839,9 +839,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717c9c806a9e07fdcb34c84965a414ea40fafe57667187052cf1eb7f5e8a8a9" +checksum = "6c33fd49f5d956a1b7ee5f7a9768d58580c6752838d92e39d0d56439efdedc35" dependencies = [ "clap", "codespan-reporting", @@ -852,15 +852,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f6515329bf3d98f4073101c7866ff2bec4e635a13acb82e3f3753fff0bf43cb" +checksum = "be0f1077278fac36299cce8446effd19fe93a95eedb10d39265f3bf67b3036c9" [[package]] name = "cxxbridge-macro" -version = "1.0.135" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb93e6a7ce8ec985c02bbb758237a31598b340acbbc3c19c5a4fa6adaaac92ab" +checksum = "3da7e4d6e74af6b79031d264b2f13c3ea70af1978083741c41ffce9308f1f24f" dependencies = [ "proc-macro2", "quote", @@ -1134,7 +1134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1190,9 +1190,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "fs-err" @@ -1354,9 +1354,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "goblin" @@ -1519,7 +1519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -1961,9 +1961,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -2300,9 +2300,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -2482,9 +2482,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" @@ -2584,18 +2584,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -2604,9 +2604,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -2803,9 +2803,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -2814,9 +2814,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791" +checksum = "4c33cd241af0f2e9e3b5c32163b873b29956890b5342e6745b917ce9d490f4af" dependencies = [ "core-foundation-sys", "libc", @@ -2828,15 +2828,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3050,9 +3051,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" @@ -3340,7 +3341,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -3636,9 +3637,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" dependencies = [ "memchr", ]