From a735faeac771e672469abc1561fdbe4d972b6eb9 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Sat, 17 May 2025 18:43:11 +0200 Subject: [PATCH] TMP --- apps/browser/src/_locales/en/messages.json | 11 +++++- .../settings/account-security.component.html | 21 +++++------ .../settings/account-security.component.ts | 36 +++++++++++++++++-- .../background-synced-unlock.service.ts | 7 ++-- .../vault-timeout-input.component.ts | 9 ++++- .../services/vault-timeout.service.ts | 14 ++++++-- .../src/lock/components/lock.component.html | 11 +++--- .../src/lock/components/lock.component.ts | 5 ++- 8 files changed, 85 insertions(+), 29 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index ca19964619d..90f6bdc32d3 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2162,7 +2162,16 @@ "message": "Too many invalid PIN entry attempts. Logging out." }, "syncUnlockWithDesktop": { - "message": "Synchronize unlock state with desktop app." + "message": "Unlock with desktop integration" + }, + "lockScreenSynchronizedNote": { + "message": "This user's account is synchronized with the desktop app." + }, + "lockScreenContinueInDesktop": { + "message": "Continue in desktop app" + }, + "lockScreenDesktopNotRunning": { + "message": "This user's account is synchronized with the desktop app, but the desktop app is not running." }, "unlockWithBiometrics": { "message": "Unlock with biometrics" diff --git a/apps/browser/src/auth/popup/settings/account-security.component.html b/apps/browser/src/auth/popup/settings/account-security.component.html index da3d27b4468..584ef82a72e 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.html +++ b/apps/browser/src/auth/popup/settings/account-security.component.html @@ -11,7 +11,7 @@

{{ "unlockMethods" | i18n }}

- + {{ @@ -37,7 +36,7 @@ @@ -63,8 +62,7 @@ disableMargin *ngIf=" this.form.value.pin && - showMasterPasswordOnClientRestartOption && - !this.form.value.syncUnlockWithDesktop + showMasterPasswordOnClientRestartOption " > - + {{ "vaultTimeoutAction1" | i18n }} {{ "vaultTimeoutPolicyAffectingOptions" | i18n }} - - The desktop app's vault timeout settings will be used to lock the vault on this device. - 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 a9b044c5b3b..7ef126d26e5 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -9,7 +9,6 @@ import { combineLatest, concatMap, distinctUntilChanged, - filter, firstValueFrom, map, Observable, @@ -250,11 +249,35 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { takeUntil(this.destroy$), ) .subscribe(); + this.syncedUnlockStateService.syncedUnlockEnabled$ + .pipe( + map((enabled) => { + if (enabled) { + this.form.controls.pin.disable({ emitEvent: false }); + this.form.controls.pinLockWithMasterPassword.disable({ emitEvent: false }); + this.form.controls.biometric.disable({ emitEvent: false }); + this.form.controls.enableAutoBiometricsPrompt.disable({ emitEvent: false }); + this.form.controls.vaultTimeoutAction.disable({ emitEvent: false }); + } else { + this.form.controls.pin.enable({ emitEvent: false }); + this.form.controls.pinLockWithMasterPassword.enable({ emitEvent: false }); + this.form.controls.biometric.enable({ emitEvent: false }); + this.form.controls.enableAutoBiometricsPrompt.enable({ emitEvent: false }); + this.form.controls.vaultTimeoutAction.enable({ emitEvent: false }); + } + }), + takeUntil(this.destroy$), + ) + .subscribe(); timer(0, 1000) .pipe( - filter(() => !this.form.controls.syncUnlockWithDesktop.value), switchMap(async () => { + if (this.form.controls.syncUnlockWithDesktop.value) { + this.form.controls.biometric.disable({ emitEvent: false }); + return; + } + const status = await this.biometricsService.getBiometricsStatusForUser(activeAccount.id); const biometricSettingAvailable = await this.biometricsService.canEnableBiometricUnlock(); if (!biometricSettingAvailable) { @@ -394,6 +417,11 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { takeUntil(this.destroy$), ) .subscribe(([availableActions, policy]) => { + if (this.form.controls.syncUnlockWithDesktop.value) { + this.form.controls.vaultTimeoutAction.disable({ emitEvent: false }); + return; + } + if (policy?.data?.action || availableActions.length <= 1) { this.form.controls.vaultTimeoutAction.disable({ emitEvent: false }); } else { @@ -403,6 +431,10 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { } async saveVaultTimeout(previousValue: VaultTimeout, newValue: VaultTimeout) { + if (newValue == null) { + return; + } + if (newValue === VaultTimeoutStringType.Never) { const confirmed = await this.dialogService.openSimpleDialog({ title: { key: "warning" }, diff --git a/apps/browser/src/key-management/synced-unlock/background-synced-unlock.service.ts b/apps/browser/src/key-management/synced-unlock/background-synced-unlock.service.ts index f7f5c80ddc8..5c16f662123 100644 --- a/apps/browser/src/key-management/synced-unlock/background-synced-unlock.service.ts +++ b/apps/browser/src/key-management/synced-unlock/background-synced-unlock.service.ts @@ -5,7 +5,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { SyncedUnlockService } from "@bitwarden/common/key-management/synced-unlock/abstractions/synced-unlock.service"; -import { VaultTimeoutService } from "@bitwarden/common/key-management/vault-timeout"; +import { VaultTimeoutService } from "@bitwarden/common/key-management/vault-timeout/services/vault-timeout.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; @@ -33,7 +33,10 @@ export class BackgroundSyncedUnlockService extends SyncedUnlockService { timer(0, 1000) .pipe( concatMap(async () => { - if (this.nativeMessagingBackground().connected) { + const isConnected = await this.isConnected(); + // Needed to resolve dependency cycle + this.vaultTimeoutService.setDesktopAppConnected(isConnected); + if (isConnected) { if (!(await firstValueFrom(this.syncedUnlockStateService.syncedUnlockEnabled$))) { return; } diff --git a/libs/auth/src/angular/vault-timeout-input/vault-timeout-input.component.ts b/libs/auth/src/angular/vault-timeout-input/vault-timeout-input.component.ts index 82bc53bb147..874b87fbcc2 100644 --- a/libs/auth/src/angular/vault-timeout-input/vault-timeout-input.component.ts +++ b/libs/auth/src/angular/vault-timeout-input/vault-timeout-input.component.ts @@ -14,7 +14,7 @@ import { ValidationErrors, Validator, } from "@angular/forms"; -import { filter, map, Observable, Subject, switchMap, takeUntil } from "rxjs"; +import { filter, map, Observable, Subject, switchMap, take, takeUntil } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -110,6 +110,7 @@ export class VaultTimeoutInputComponent }); @Input() vaultTimeoutOptions: VaultTimeoutOption[]; + @Input() disabled: boolean; vaultTimeoutPolicy: Policy; vaultTimeoutPolicyHours: number; @@ -189,6 +190,12 @@ export class VaultTimeoutInputComponent } ngOnChanges() { + if (this.disabled) { + this.form.disable(); + } else { + this.form.enable(); + } + if ( !this.vaultTimeoutOptions.find((p) => p.value === VaultTimeoutInputComponent.CUSTOM_VALUE) ) { diff --git a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts index 1bf07fbc944..6be6571317d 100644 --- a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts +++ b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts @@ -21,12 +21,14 @@ import { UserId } from "../../../types/guid"; import { CipherService } from "../../../vault/abstractions/cipher.service"; import { FolderService } from "../../../vault/abstractions/folder/folder.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "../../master-password/abstractions/master-password.service.abstraction"; +import { SyncedUnlockService } from "../../synced-unlock/abstractions/synced-unlock.service"; import { VaultTimeoutSettingsService } from "../abstractions/vault-timeout-settings.service"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../abstractions/vault-timeout.service"; import { VaultTimeoutAction } from "../enums/vault-timeout-action.enum"; export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { private inited = false; + private isDesktopAppConnected = false; constructor( private accountService: AccountService, @@ -44,7 +46,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { private taskSchedulerService: TaskSchedulerService, protected logService: LogService, private biometricService: BiometricsService, - private syncedUnlockService: SyncedUnlockStateServiceAbstraction, + private syncedUnlockStateService: SyncedUnlockStateServiceAbstraction, private lockedCallback: (userId?: string) => Promise = null, private loggedOutCallback: ( logoutReason: LogoutReason, @@ -76,10 +78,16 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { ); } + // This is needed to prevent dependency cycle between vault timeout and synced unlock service + setDesktopAppConnected(isConnected: boolean): void { + this.isDesktopAppConnected = isConnected; + } + async checkVaultTimeout(): Promise { if ( - (await firstValueFrom(this.syncedUnlockService.syncedUnlockEnabled$)) && - this.platformUtilsService.getClientType() === ClientType.Browser + (await firstValueFrom(this.syncedUnlockStateService.syncedUnlockEnabled$)) && + this.platformUtilsService.getClientType() === ClientType.Browser && + this.isDesktopAppConnected ) { return; } diff --git a/libs/key-management-ui/src/lock/components/lock.component.html b/libs/key-management-ui/src/lock/components/lock.component.html index 46817e2168a..b56a2ea2ff9 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.html +++ b/libs/key-management-ui/src/lock/components/lock.component.html @@ -8,18 +8,17 @@
- This user's account is synchronized with the desktop app. + {{ "lockScreenSynchronizedNote" | i18n }}
- - This account has unlock synchronization enabled, but the desktop app is not running. + + {{ "lockScreenDesktopNotRunning" | i18n }} diff --git a/libs/key-management-ui/src/lock/components/lock.component.ts b/libs/key-management-ui/src/lock/components/lock.component.ts index bcf9ebc25e7..b4ab3b5fce4 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.ts @@ -138,7 +138,7 @@ export class LockComponent implements OnInit, OnDestroy { unlockViaDesktop = false; isDesktopOpen = false; - showLocalUnlockOptions = false; + showLocalUnlockOptions = true; desktopUnlockFormGroup: FormGroup = new FormGroup({}); constructor( @@ -189,6 +189,9 @@ export class LockComponent implements OnInit, OnDestroy { await this.desktopOnInit(); } else if (this.clientType === ClientType.Browser) { this.biometricUnlockBtnText = this.lockComponentService.getBiometricsUnlockBtnText(); + if (await firstValueFrom(this.syncedUnlockStateService.syncedUnlockEnabled$)) { + this.showLocalUnlockOptions = false; + } } }