mirror of
https://github.com/bitwarden/browser
synced 2026-01-05 18:13:26 +00:00
[PM-26056] Consolidated session timeout component (#16988)
* consolidated session timeout settings component * rename preferences to appearance * race condition bug on computed signal * outdated header for browser * unnecessary padding * remove required on action, fix build * rename localization key * missing user id * required * cleanup task * eslint fix signals rollback * takeUntilDestroyed, null checks * move browser specific logic outside shared component * explicit input type * input name * takeUntilDestroyed, no toast * unit tests * cleanup * cleanup, correct link to deprecation jira * tech debt todo with jira * missing web localization key when policy is on * relative import * extracting timeout options to component service * duplicate localization key * fix failing test * subsequent timeout action selecting opening without dialog on first dialog cancellation * default locale can be null * unit tests failing * rename, simplifications * one if else feature flag * timeout input component rendering before async pipe completion
This commit is contained in:
@@ -31,36 +31,50 @@
|
||||
</h2>
|
||||
<ng-container *ngIf="showSecurity">
|
||||
<bit-section disableMargin>
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "vaultTimeoutHeader" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
@if (consolidatedSessionTimeoutComponent$ | async) {
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "sessionTimeoutHeader" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
|
||||
<auth-vault-timeout-input
|
||||
[vaultTimeoutOptions]="vaultTimeoutOptions"
|
||||
[formControl]="form.controls.vaultTimeout"
|
||||
ngDefaultControl
|
||||
>
|
||||
</auth-vault-timeout-input>
|
||||
<bit-session-timeout-settings
|
||||
[refreshTimeoutActionSettings]="refreshTimeoutSettings$"
|
||||
/>
|
||||
} @else {
|
||||
<bit-section-header>
|
||||
<h2 bitTypography="h6">{{ "vaultTimeoutHeader" | i18n }}</h2>
|
||||
</bit-section-header>
|
||||
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="vaultTimeoutAction">{{ "vaultTimeoutAction1" | i18n }}</bit-label>
|
||||
<bit-select id="vaultTimeoutAction" formControlName="vaultTimeoutAction">
|
||||
<bit-option
|
||||
*ngFor="let action of availableVaultTimeoutActions"
|
||||
[value]="action"
|
||||
[label]="action | i18n"
|
||||
<auth-vault-timeout-input
|
||||
[vaultTimeoutOptions]="vaultTimeoutOptions"
|
||||
[formControl]="form.controls.vaultTimeout"
|
||||
ngDefaultControl
|
||||
>
|
||||
</auth-vault-timeout-input>
|
||||
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label for="vaultTimeoutAction">{{
|
||||
"vaultTimeoutAction1" | i18n
|
||||
}}</bit-label>
|
||||
<bit-select id="vaultTimeoutAction" formControlName="vaultTimeoutAction">
|
||||
<bit-option
|
||||
*ngFor="let action of availableVaultTimeoutActions"
|
||||
[value]="action"
|
||||
[label]="action | i18n"
|
||||
>
|
||||
</bit-option>
|
||||
</bit-select>
|
||||
|
||||
<bit-hint
|
||||
*ngIf="!availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock)"
|
||||
>
|
||||
</bit-option>
|
||||
</bit-select>
|
||||
{{ "unlockMethodNeededToChangeTimeoutActionDesc" | i18n }}<br />
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-hint *ngIf="!availableVaultTimeoutActions.includes(VaultTimeoutAction.Lock)">
|
||||
{{ "unlockMethodNeededToChangeTimeoutActionDesc" | i18n }}<br />
|
||||
<bit-hint *ngIf="hasVaultTimeoutPolicy" class="tw-mt-4">
|
||||
{{ "vaultTimeoutPolicyAffectingOptions" | i18n }}
|
||||
</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-hint *ngIf="hasVaultTimeoutPolicy" class="tw-mt-4">
|
||||
{{ "vaultTimeoutPolicyAffectingOptions" | i18n }}
|
||||
</bit-hint>
|
||||
}
|
||||
</bit-section>
|
||||
<div class="form-group tw-mt-4" *ngIf="(pinEnabled$ | async) || this.form.value.pin">
|
||||
<div class="checkbox">
|
||||
|
||||
@@ -191,7 +191,7 @@ describe("SettingsComponent", () => {
|
||||
desktopAutotypeService.autotypeEnabledUserSetting$ = of(false);
|
||||
desktopAutotypeService.autotypeKeyboardShortcut$ = of(["Control", "Shift", "B"]);
|
||||
billingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(false));
|
||||
configService.getFeatureFlag$.mockReturnValue(of(true));
|
||||
configService.getFeatureFlag$.mockReturnValue(of(false));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
import { KeyService, BiometricStateService, BiometricsStatus } from "@bitwarden/key-management";
|
||||
import { SessionTimeoutSettingsComponent } from "@bitwarden/key-management-ui";
|
||||
import { PermitCipherDetailsPopoverComponent } from "@bitwarden/vault";
|
||||
|
||||
import { SetPinComponent } from "../../auth/components/set-pin.component";
|
||||
@@ -95,6 +96,7 @@ import { NativeMessagingManifestService } from "../services/native-messaging-man
|
||||
SelectModule,
|
||||
TypographyModule,
|
||||
VaultTimeoutInputComponent,
|
||||
SessionTimeoutSettingsComponent,
|
||||
PermitCipherDetailsPopoverComponent,
|
||||
PremiumBadgeComponent,
|
||||
],
|
||||
@@ -146,6 +148,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
pinEnabled$: Observable<boolean> = of(true);
|
||||
isWindowsV2BiometricsEnabled: boolean = false;
|
||||
|
||||
consolidatedSessionTimeoutComponent$: Observable<boolean>;
|
||||
|
||||
form = this.formBuilder.group({
|
||||
// Security
|
||||
vaultTimeout: [null as VaultTimeout | null],
|
||||
@@ -184,7 +188,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
locale: [null as string | null],
|
||||
});
|
||||
|
||||
private refreshTimeoutSettings$ = new BehaviorSubject<void>(undefined);
|
||||
protected refreshTimeoutSettings$ = new BehaviorSubject<void>(undefined);
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
@@ -282,12 +286,17 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
value: SshAgentPromptType.RememberUntilLock,
|
||||
},
|
||||
];
|
||||
|
||||
this.consolidatedSessionTimeoutComponent$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.ConsolidatedSessionTimeoutComponent,
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.vaultTimeoutOptions = await this.generateVaultTimeoutOptions();
|
||||
|
||||
this.isWindowsV2BiometricsEnabled = await this.biometricsService.isWindowsV2BiometricsEnabled();
|
||||
|
||||
this.vaultTimeoutOptions = await this.generateVaultTimeoutOptions();
|
||||
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
||||
|
||||
// Autotype is for Windows initially
|
||||
|
||||
@@ -109,7 +109,10 @@ import {
|
||||
BiometricStateService,
|
||||
BiometricsService,
|
||||
} from "@bitwarden/key-management";
|
||||
import { LockComponentService } from "@bitwarden/key-management-ui";
|
||||
import {
|
||||
LockComponentService,
|
||||
SessionTimeoutSettingsComponentService,
|
||||
} from "@bitwarden/key-management-ui";
|
||||
import { SerializedMemoryStorageService } from "@bitwarden/storage-core";
|
||||
import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault";
|
||||
|
||||
@@ -125,6 +128,7 @@ import { DesktopBiometricsService } from "../../key-management/biometrics/deskto
|
||||
import { RendererBiometricsService } from "../../key-management/biometrics/renderer-biometrics.service";
|
||||
import { ElectronKeyService } from "../../key-management/electron-key.service";
|
||||
import { DesktopLockComponentService } from "../../key-management/lock/services/desktop-lock-component.service";
|
||||
import { DesktopSessionTimeoutSettingsComponentService } from "../../key-management/session-timeout/services/desktop-session-timeout-settings-component.service";
|
||||
import { flagEnabled } from "../../platform/flags";
|
||||
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
|
||||
import { ElectronLogRendererService } from "../../platform/services/electron-log.renderer.service";
|
||||
@@ -480,6 +484,11 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: DesktopAutotypeDefaultSettingPolicy,
|
||||
deps: [AccountServiceAbstraction, AuthServiceAbstraction, InternalPolicyService, ConfigService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: SessionTimeoutSettingsComponentService,
|
||||
useClass: DesktopSessionTimeoutSettingsComponentService,
|
||||
deps: [I18nServiceAbstraction],
|
||||
}),
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { defer, from, map, Observable } from "rxjs";
|
||||
|
||||
import {
|
||||
VaultTimeout,
|
||||
VaultTimeoutOption,
|
||||
VaultTimeoutStringType,
|
||||
} from "@bitwarden/common/key-management/vault-timeout";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SessionTimeoutSettingsComponentService } from "@bitwarden/key-management-ui";
|
||||
|
||||
export class DesktopSessionTimeoutSettingsComponentService
|
||||
implements SessionTimeoutSettingsComponentService
|
||||
{
|
||||
availableTimeoutOptions$: Observable<VaultTimeoutOption[]> = defer(() =>
|
||||
from(ipc.platform.powermonitor.isLockMonitorAvailable()).pipe(
|
||||
map((isLockMonitorAvailable) => {
|
||||
const options: VaultTimeoutOption[] = [
|
||||
{ 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 },
|
||||
{ name: this.i18nService.t("onIdle"), value: VaultTimeoutStringType.OnIdle },
|
||||
{ name: this.i18nService.t("onSleep"), value: VaultTimeoutStringType.OnSleep },
|
||||
];
|
||||
|
||||
if (isLockMonitorAvailable) {
|
||||
options.push({
|
||||
name: this.i18nService.t("onLocked"),
|
||||
value: VaultTimeoutStringType.OnLocked,
|
||||
});
|
||||
}
|
||||
|
||||
options.push(
|
||||
{ name: this.i18nService.t("onRestart"), value: VaultTimeoutStringType.OnRestart },
|
||||
{ name: this.i18nService.t("never"), value: VaultTimeoutStringType.Never },
|
||||
);
|
||||
|
||||
return options;
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
constructor(private readonly i18nService: I18nService) {}
|
||||
|
||||
onTimeoutSave(_: VaultTimeout): void {}
|
||||
}
|
||||
@@ -4220,5 +4220,11 @@
|
||||
},
|
||||
"upgradeToPremium": {
|
||||
"message": "Upgrade to Premium"
|
||||
},
|
||||
"sessionTimeoutSettingsAction": {
|
||||
"message": "Timeout action"
|
||||
},
|
||||
"sessionTimeoutHeader": {
|
||||
"message": "Session timeout"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user