1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-06 19:53:59 +00:00

PM-21845: Add autotype to desktop settings and add a barebones service

This commit is contained in:
Colton Hurst
2025-06-05 17:26:37 -04:00
parent a085e87225
commit 8f184ca5c7
8 changed files with 115 additions and 3 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">{{
"enableAutotypeDesc" | i18n
}}</small>
</div>
<div class="form-group">
<label for="theme">{{ "theme" | i18n }}</label>
<select

View File

@@ -71,6 +71,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
showAlwaysShowDock = false;
requireEnableTray = false;
showDuckDuckGoIntegrationOption = false;
showEnableAutotype = false;
showOpenAtLoginOption = false;
isWindows: boolean;
isLinux: boolean;
@@ -132,6 +133,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],
});
@@ -164,6 +166,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
private configService: ConfigService,
) {
const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
const isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop;
// Workaround to avoid ghosting trays https://github.com/electron/electron/issues/17622
this.requireEnableTray = this.platformUtilsService.getDevice() === DeviceType.LinuxDesktop;
@@ -189,6 +192,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
// DuckDuckGo browser is only for macos initially
this.showDuckDuckGoIntegrationOption = isMac;
// Autotype is only for Windows initially
this.showEnableAutotype = isWindows;
const localeOptions: any[] = [];
this.i18nService.supportedTranslationLocales.forEach((locale) => {
let name = locale;
@@ -331,6 +337,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
this.desktopSettingsService.sshAgentPromptBehavior$,
),
allowScreenshots: !(await firstValueFrom(this.desktopSettingsService.preventScreenshots$)),
enableAutotype: await firstValueFrom(this.desktopSettingsService.autotypeEnabled$),
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
locale: await firstValueFrom(this.i18nService.userSetLocale$),
};
@@ -834,6 +841,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
}
}
async saveEnableAutotype() {
await this.desktopSettingsService.setAutotypeEnabled(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,
@@ -100,6 +102,7 @@ export class InitService {
containerService.attachToGlobal(this.win);
await this.autofillService.init();
await this.autotypeService.init();
};
}
}

View File

@@ -140,6 +140,7 @@ import { DesktopSetPasswordJitService } from "./desktop-set-password-jit.service
import { InitService } from "./init.service";
import { NativeMessagingManifestService } from "./native-messaging-manifest.service";
import { RendererCryptoFunctionService } from "./renderer-crypto-function.service";
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
const RELOAD_CALLBACK = new SafeInjectionToken<() => any>("RELOAD_CALLBACK");
@@ -451,6 +452,14 @@ const safeProviders: SafeProvider[] = [
useClass: DefaultSshImportPromptService,
deps: [DialogService, ToastService, PlatformUtilsServiceAbstraction, I18nServiceAbstraction],
}),
safeProvider({
provide: DesktopAutotypeService,
deps: [
CipherServiceAbstraction,
LogService,
DesktopSettingsService,
],
}),
];
@NgModule({

View File

@@ -0,0 +1,49 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Injectable, OnDestroy } from "@angular/core";
import {
catchError,
combineLatest,
concatMap,
EMPTY,
filter,
firstValueFrom,
from,
map,
of,
skip,
Subject,
switchMap,
takeUntil,
timeout,
TimeoutError,
timer,
withLatestFrom,
} from "rxjs";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
@Injectable({
providedIn: "root",
})
export class DesktopAutotypeService implements OnDestroy {
private destroy$ = new Subject<void>();
constructor(
private cipherService: CipherService,
private logService: LogService,
private desktopSettingsService: DesktopSettingsService,
) {}
async init() {
let autotypeEnabled = await firstValueFrom(this.desktopSettingsService.autotypeEnabled$);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

View File

@@ -43,11 +43,11 @@ if (
const Main = require("./main").Main;
// Testing autotype hotkey registration
const r = autotype.registerHotkey();
//const r = autotype.registerHotkey();
// eslint-disable-next-line no-console
console.log("registerHotkey(): ");
//console.log("registerHotkey(): ");
// eslint-disable-next-line no-console
console.log(r);
//console.log(r);
const main = new Main();
main.bootstrap();

View File

@@ -3812,5 +3812,11 @@
"message": "Learn more about SSH agent",
"description": "Two part message",
"example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent"
},
"enableAutotype": {
"message": "Enable Autotype"
},
"enableAutotypeDesc": {
"message": "Warning: Bitwarden gives you full control of autotype, and does not validate input locations. Please be careful! (Currently this feature is available on Windows only.)"
}
}

View File

@@ -97,6 +97,10 @@ const PREVENT_SCREENSHOTS = new KeyDefinition<boolean>(
},
);
const AUTOTYPE_ENABLED = new KeyDefinition<boolean>(DESKTOP_SETTINGS_DISK, "autotypeEnabled", {
deserializer: (b) => b,
});
/**
* Various settings for controlling application behavior specific to the desktop client.
*/
@@ -193,6 +197,12 @@ export class DesktopSettingsService {
modalMode$ = this.modalModeState.state$;
private readonly autotypeEnabled = this.stateProvider.getGlobal(AUTOTYPE_ENABLED);
/**
* The application setting for whether or not autotype is enabled.
*/
autotypeEnabled$ = this.autotypeEnabled.state$.pipe(map(Boolean));
constructor(private stateProvider: StateProvider) {
this.window$ = this.windowState.state$.pipe(
map((window) =>
@@ -339,4 +349,12 @@ export class DesktopSettingsService {
async setPreventScreenshots(value: boolean) {
await this.preventScreenshotState.update(() => value);
}
/**
* Sets the setting for whether or not autotype is enabled.
* @param value `true` if autotype is enabled, `false` if it is not.
*/
async setAutotypeEnabled(value: boolean) {
await this.autotypeEnabled.update(() => value);
}
}