mirror of
https://github.com/bitwarden/browser
synced 2026-02-08 12:40:26 +00:00
TMP
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<h2 bitTypography="h6">{{ "unlockMethods" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
<bit-card>
|
||||
<bit-form-control [disableMargin]="this.form.value.syncUnlockWithDesktop">
|
||||
<bit-form-control>
|
||||
<input
|
||||
bitCheckbox
|
||||
id="syncUnlockWithDesktop"
|
||||
@@ -24,7 +24,6 @@
|
||||
</bit-form-control>
|
||||
<bit-form-control
|
||||
[disableMargin]="!((pinEnabled$ | async) || this.form.value.pin)"
|
||||
*ngIf="!this.form.value.syncUnlockWithDesktop"
|
||||
>
|
||||
<input bitCheckbox id="biometric" type="checkbox" formControlName="biometric" />
|
||||
<bit-label for="biometric" class="tw-whitespace-normal">{{
|
||||
@@ -37,7 +36,7 @@
|
||||
<bit-form-control
|
||||
class="tw-pl-5"
|
||||
[disableMargin]="!((pinEnabled$ | async) || this.form.value.pin)"
|
||||
*ngIf="this.form.value.biometric && !this.form.value.syncUnlockWithDesktop"
|
||||
*ngIf="this.form.value.biometric"
|
||||
>
|
||||
<input
|
||||
bitCheckbox
|
||||
@@ -52,7 +51,7 @@
|
||||
<bit-form-control
|
||||
[disableMargin]="!(this.form.value.pin && showMasterPasswordOnClientRestartOption)"
|
||||
*ngIf="
|
||||
((pinEnabled$ | async) || this.form.value.pin) && !this.form.value.syncUnlockWithDesktop
|
||||
((pinEnabled$ | async) || this.form.value.pin)
|
||||
"
|
||||
>
|
||||
<input bitCheckbox id="pin" type="checkbox" formControlName="pin" />
|
||||
@@ -63,8 +62,7 @@
|
||||
disableMargin
|
||||
*ngIf="
|
||||
this.form.value.pin &&
|
||||
showMasterPasswordOnClientRestartOption &&
|
||||
!this.form.value.syncUnlockWithDesktop
|
||||
showMasterPasswordOnClientRestartOption
|
||||
"
|
||||
>
|
||||
<input
|
||||
@@ -89,12 +87,12 @@
|
||||
<auth-vault-timeout-input
|
||||
[vaultTimeoutOptions]="vaultTimeoutOptions"
|
||||
[formControl]="form.controls.vaultTimeout"
|
||||
ngDefaultControl
|
||||
*ngIf="!this.form.value.syncUnlockWithDesktop"
|
||||
[disabled]="form.controls.syncUnlockWithDesktop.value"
|
||||
ngDefaultControl
|
||||
>
|
||||
</auth-vault-timeout-input>
|
||||
|
||||
<bit-form-field disableMargin *ngIf="!this.form.value.syncUnlockWithDesktop">
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="vaultTimeoutAction">{{ "vaultTimeoutAction1" | i18n }}</bit-label>
|
||||
<bit-select id="vaultTimeoutAction" formControlName="vaultTimeoutAction">
|
||||
<bit-option
|
||||
@@ -111,14 +109,11 @@
|
||||
</bit-form-field>
|
||||
|
||||
<bit-hint
|
||||
*ngIf="hasVaultTimeoutPolicy && !this.form.value.syncUnlockWithDesktop"
|
||||
*ngIf="hasVaultTimeoutPolicy"
|
||||
class="tw-mt-4"
|
||||
>
|
||||
{{ "vaultTimeoutPolicyAffectingOptions" | i18n }}
|
||||
</bit-hint>
|
||||
<bit-hint *ngIf="this.form.value.syncUnlockWithDesktop">
|
||||
The desktop app's vault timeout settings will be used to lock the vault on this device.
|
||||
</bit-hint>
|
||||
</bit-card>
|
||||
</bit-section>
|
||||
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
) {
|
||||
|
||||
@@ -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<void> = 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<void> {
|
||||
if (
|
||||
(await firstValueFrom(this.syncedUnlockService.syncedUnlockEnabled$)) &&
|
||||
this.platformUtilsService.getClientType() === ClientType.Browser
|
||||
(await firstValueFrom(this.syncedUnlockStateService.syncedUnlockEnabled$)) &&
|
||||
this.platformUtilsService.getClientType() === ClientType.Browser &&
|
||||
this.isDesktopAppConnected
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,18 +8,17 @@
|
||||
<ng-container *ngIf="!showLocalUnlockOptions">
|
||||
<form [bitSubmit]="submit" [formGroup]="desktopUnlockFormGroup">
|
||||
<div class="tw-flex tw-flex-col tw-space-y-3">
|
||||
<bit-hint class="tw-text-center"
|
||||
>This user's account is synchronized with the desktop app.</bit-hint
|
||||
>
|
||||
<bit-hint class="tw-text-center">{{ "lockScreenSynchronizedNote" | i18n }}</bit-hint
|
||||
>
|
||||
<button type="submit" bitButton bitFormButton buttonType="primary" block>
|
||||
Continue in desktop app
|
||||
{{ "lockScreenContinueInDesktop" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="showLocalUnlockOptions">
|
||||
<bit-hint class="tw-text-center" *ngIf="unlockViaDesktop">
|
||||
This account has unlock synchronization enabled, but the desktop app is not running.
|
||||
<bit-hint class="tw-text-center tw-mb-3" *ngIf="unlockViaDesktop">
|
||||
{{ "lockScreenDesktopNotRunning" | i18n }}
|
||||
</bit-hint>
|
||||
|
||||
<!-- Biometrics Unlock -->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user