1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-07 11:03:30 +00:00

[PM-22783] Add Feature Flag, Settings Toggle, and Services for Autotype MVP (#15262)

* [PM-22783] Add initial feature flag and settings toggle for autotype MVP

* [PM-22783] Undo Cargo.lock changes

* [PM-22783] Disable console.log block

* [PM-22783] Lint fix

* [PM-22783] Small updates

* [PM-22783] Build fix

* [PM-22783] Use combineLatest in updating the desktop autotype service

* [PM-22783] Check if the user is on Windows

* [PM-22783] Undo access selector html change, linting keeps removing this

* [PM-22783] Fix failing test

* [PM-22783] Update autotypeEnabled to be stored in service

* [PM-22783] Add todo comments

* [PM-22783] Add SlimConfigService and MainDesktopAutotypeService

* [PM-22783] Small fixes
This commit is contained in:
Colton Hurst
2025-07-15 11:49:15 -04:00
committed by GitHub
parent 4412dbb502
commit d545912b67
12 changed files with 217 additions and 4 deletions

View File

@@ -489,6 +489,22 @@
"enableDuckDuckGoBrowserIntegrationDesc" | i18n
}}</small>
</div>
<div class="form-group" *ngIf="showEnableAutotype">
<div class="checkbox">
<label for="enableAutotype">
<input
id="enableAutotype"
type="checkbox"
formControlName="enableAutotype"
(change)="saveEnableAutotype()"
/>
{{ "enableAutotype" | i18n }}
</label>
</div>
<small class="help-block"
><b>{{ "important" | i18n }}</b> {{ "enableAutotypeDescription" | i18n }}</small
>
</div>
<div class="form-group">
<label for="theme">{{ "theme" | i18n }}</label>
<select

View File

@@ -39,6 +39,7 @@ import { BiometricStateService, BiometricsStatus, KeyService } from "@bitwarden/
import { SetPinComponent } from "../../auth/components/set-pin.component";
import { SshAgentPromptType } from "../../autofill/models/ssh-agent-setting";
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
import { DesktopBiometricsService } from "../../key-management/biometrics/desktop.biometrics.service";
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
import { NativeMessagingManifestService } from "../services/native-messaging-manifest.service";
@@ -69,6 +70,7 @@ describe("SettingsComponent", () => {
const messagingService = mock<MessagingService>();
const keyService = mock<KeyService>();
const dialogService = mock<DialogService>();
const desktopAutotypeService = mock<DesktopAutotypeService>();
beforeEach(async () => {
jest.clearAllMocks();
@@ -124,6 +126,7 @@ describe("SettingsComponent", () => {
{ provide: VaultTimeoutSettingsService, useValue: vaultTimeoutSettingsService },
{ provide: ValidationService, useValue: validationService },
{ provide: MessagingService, useValue: messagingService },
{ provide: DesktopAutotypeService, useValue: desktopAutotypeService },
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
@@ -160,6 +163,7 @@ describe("SettingsComponent", () => {
themeStateService.selectedTheme$ = of(ThemeType.System);
i18nService.userSetLocale$ = of("en");
pinServiceAbstraction.isPinSet.mockResolvedValue(false);
desktopAutotypeService.autotypeEnabled$ = of(false);
});
afterEach(() => {

View File

@@ -24,6 +24,7 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { DeviceType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import {
VaultTimeout,
VaultTimeoutAction,
@@ -48,6 +49,7 @@ import { KeyService, BiometricStateService, BiometricsStatus } from "@bitwarden/
import { SetPinComponent } from "../../auth/components/set-pin.component";
import { SshAgentPromptType } from "../../autofill/models/ssh-agent-setting";
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
import { DesktopBiometricsService } from "../../key-management/biometrics/desktop.biometrics.service";
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
import { NativeMessagingManifestService } from "../services/native-messaging-manifest.service";
@@ -72,6 +74,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
showAlwaysShowDock = false;
requireEnableTray = false;
showDuckDuckGoIntegrationOption = false;
showEnableAutotype = false;
showOpenAtLoginOption = false;
isWindows: boolean;
isLinux: boolean;
@@ -133,6 +136,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
sshAgentPromptBehavior: SshAgentPromptType.Always,
allowScreenshots: false,
enableDuckDuckGoBrowserIntegration: false,
enableAutotype: false,
theme: [null as Theme | null],
locale: [null as string | null],
});
@@ -156,6 +160,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
private dialogService: DialogService,
private userVerificationService: UserVerificationServiceAbstraction,
private desktopSettingsService: DesktopSettingsService,
private desktopAutotypeService: DesktopAutotypeService,
private biometricStateService: BiometricStateService,
private biometricsService: DesktopBiometricsService,
private desktopAutofillSettingsService: DesktopAutofillSettingsService,
@@ -236,9 +241,12 @@ export class SettingsComponent implements OnInit, OnDestroy {
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
this.isLinux = (await this.platformUtilsService.getDevice()) === DeviceType.LinuxDesktop;
if (activeAccount == null || activeAccount.id == null) {
return;
}
// Autotype is for Windows initially
const isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop;
const windowsDesktopAutotypeFeatureFlag = await this.configService.getFeatureFlag(
FeatureFlag.WindowsDesktopAutotype,
);
this.showEnableAutotype = isWindows && windowsDesktopAutotypeFeatureFlag;
this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword();
@@ -333,6 +341,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
this.desktopSettingsService.sshAgentPromptBehavior$,
),
allowScreenshots: !(await firstValueFrom(this.desktopSettingsService.preventScreenshots$)),
enableAutotype: await firstValueFrom(this.desktopAutotypeService.autotypeEnabled$),
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
locale: await firstValueFrom(this.i18nService.userSetLocale$),
};
@@ -853,6 +862,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
}
}
async saveEnableAutotype() {
await this.desktopAutotypeService.setAutotypeEnabledState(this.form.value.enableAutotype);
}
private async generateVaultTimeoutOptions(): Promise<VaultTimeoutOption[]> {
let vaultTimeoutOptions: VaultTimeoutOption[] = [
{ name: this.i18nService.t("oneMinute"), value: 1 },

View File

@@ -24,6 +24,7 @@ import { UserId } from "@bitwarden/common/types/guid";
import { KeyService as KeyServiceAbstraction } from "@bitwarden/key-management";
import { DesktopAutofillService } from "../../autofill/services/desktop-autofill.service";
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
import { SshAgentService } from "../../autofill/services/ssh-agent.service";
import { I18nRendererService } from "../../platform/services/i18n.renderer.service";
import { VersionService } from "../../platform/services/version.service";
@@ -50,6 +51,7 @@ export class InitService {
private versionService: VersionService,
private sshAgentService: SshAgentService,
private autofillService: DesktopAutofillService,
private autotypeService: DesktopAutotypeService,
private sdkLoadService: SdkLoadService,
private configService: ConfigService,
private bulkEncryptService: BulkEncryptService,

View File

@@ -51,7 +51,7 @@ import {
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
import { ClientType } from "@bitwarden/common/enums";
import { ClientType, DeviceType } from "@bitwarden/common/enums";
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
@@ -113,6 +113,7 @@ import { DesktopLoginComponentService } from "../../auth/login/desktop-login-com
import { DesktopTwoFactorAuthDuoComponentService } from "../../auth/services/desktop-two-factor-auth-duo-component.service";
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
import { DesktopAutofillService } from "../../autofill/services/desktop-autofill.service";
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
import { DesktopFido2UserInterfaceService } from "../../autofill/services/desktop-fido2-user-interface.service";
import { DesktopBiometricsService } from "../../key-management/biometrics/desktop.biometrics.service";
import { RendererBiometricsService } from "../../key-management/biometrics/renderer-biometrics.service";
@@ -469,6 +470,20 @@ const safeProviders: SafeProvider[] = [
useClass: DefaultSshImportPromptService,
deps: [DialogService, ToastService, PlatformUtilsServiceAbstraction, I18nServiceAbstraction],
}),
safeProvider({
provide: DesktopAutotypeService,
useFactory: (
configService: ConfigService,
globalStateProvider: GlobalStateProvider,
platformUtilsService: PlatformUtilsServiceAbstraction,
) =>
new DesktopAutotypeService(
configService,
globalStateProvider,
platformUtilsService.getDevice() === DeviceType.WindowsDesktop,
),
deps: [ConfigService, GlobalStateProvider, PlatformUtilsServiceAbstraction],
}),
];
@NgModule({