mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 13:53:34 +00:00
[PM-24158] Add Premium Check (#16042)
* [PM-24158] Add initial premium check * [PM-24158] Add premium membership dialog fix * [PM-24158] Small updates * [PM-24158] Set hasPremium to false upon initialization * [PM-24158] Partial update to settings component tests * [PM-24158] Fix billing mocked return value and add mac OS autotype test * [PM-24158] Add missing premium checks * [PM-24158] Update provider * [PM-24158] Renamed autotype resolved value * [PM-24158] Update missed resolvedAutotypeEnabled refactor * [PM-24158] Fix tests
This commit is contained in:
@@ -330,6 +330,33 @@
|
|||||||
"enableBrowserIntegrationFingerprintDesc" | i18n
|
"enableBrowserIntegrationFingerprintDesc" | i18n
|
||||||
}}</small>
|
}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group" *ngIf="showEnableAutotype">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label for="enableAutotype">
|
||||||
|
<input
|
||||||
|
id="enableAutotype"
|
||||||
|
type="checkbox"
|
||||||
|
formControlName="enableAutotype"
|
||||||
|
(change)="saveEnableAutotype()"
|
||||||
|
/>
|
||||||
|
{{ "enableAutotypeTransitionKey" | i18n }}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
bitBadge
|
||||||
|
variant="success"
|
||||||
|
(click)="openPremiumDialog()"
|
||||||
|
*ngIf="!hasPremium"
|
||||||
|
>
|
||||||
|
{{ "premium" | i18n }}
|
||||||
|
</button>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<small class="help-block" *ngIf="form.value.enableAutotype">
|
||||||
|
<b>{{ "important" | i18n }}</b>
|
||||||
|
{{ "enableAutotypeDescriptionTransitionKey" | i18n }}
|
||||||
|
<b>{{ "editShortcut" | i18n }}</b></small
|
||||||
|
>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label for="enableHardwareAcceleration">
|
<label for="enableHardwareAcceleration">
|
||||||
@@ -413,22 +440,6 @@
|
|||||||
"enableDuckDuckGoBrowserIntegrationDesc" | i18n
|
"enableDuckDuckGoBrowserIntegrationDesc" | i18n
|
||||||
}}</small>
|
}}</small>
|
||||||
</div>
|
</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">
|
<div class="form-group">
|
||||||
<label for="theme">{{ "theme" | i18n }}</label>
|
<label for="theme">{{ "theme" | i18n }}</label>
|
||||||
<select
|
<select
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
|||||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||||
import { DeviceType } from "@bitwarden/common/enums";
|
import { DeviceType } from "@bitwarden/common/enums";
|
||||||
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
||||||
import {
|
import {
|
||||||
@@ -70,6 +71,8 @@ describe("SettingsComponent", () => {
|
|||||||
const keyService = mock<KeyService>();
|
const keyService = mock<KeyService>();
|
||||||
const dialogService = mock<DialogService>();
|
const dialogService = mock<DialogService>();
|
||||||
const desktopAutotypeService = mock<DesktopAutotypeService>();
|
const desktopAutotypeService = mock<DesktopAutotypeService>();
|
||||||
|
const billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
|
const configService = mock<ConfigService>();
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
@@ -99,7 +102,7 @@ describe("SettingsComponent", () => {
|
|||||||
},
|
},
|
||||||
{ provide: AccountService, useValue: accountService },
|
{ provide: AccountService, useValue: accountService },
|
||||||
{ provide: BiometricStateService, useValue: biometricStateService },
|
{ provide: BiometricStateService, useValue: biometricStateService },
|
||||||
{ provide: ConfigService, useValue: mock<ConfigService>() },
|
{ provide: ConfigService, useValue: configService },
|
||||||
{
|
{
|
||||||
provide: DesktopAutofillSettingsService,
|
provide: DesktopAutofillSettingsService,
|
||||||
useValue: desktopAutofillSettingsService,
|
useValue: desktopAutofillSettingsService,
|
||||||
@@ -127,6 +130,7 @@ describe("SettingsComponent", () => {
|
|||||||
{ provide: MessagingService, useValue: messagingService },
|
{ provide: MessagingService, useValue: messagingService },
|
||||||
{ provide: ToastService, useValue: mock<ToastService>() },
|
{ provide: ToastService, useValue: mock<ToastService>() },
|
||||||
{ provide: DesktopAutotypeService, useValue: desktopAutotypeService },
|
{ provide: DesktopAutotypeService, useValue: desktopAutotypeService },
|
||||||
|
{ provide: BillingAccountProfileStateService, useValue: billingAccountProfileStateService },
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA],
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
@@ -177,7 +181,9 @@ describe("SettingsComponent", () => {
|
|||||||
i18nService.userSetLocale$ = of("en");
|
i18nService.userSetLocale$ = of("en");
|
||||||
pinServiceAbstraction.isPinSet.mockResolvedValue(false);
|
pinServiceAbstraction.isPinSet.mockResolvedValue(false);
|
||||||
policyService.policiesByType$.mockReturnValue(of([null]));
|
policyService.policiesByType$.mockReturnValue(of([null]));
|
||||||
desktopAutotypeService.autotypeEnabled$ = of(false);
|
desktopAutotypeService.resolvedAutotypeEnabled$ = of(false);
|
||||||
|
billingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(false));
|
||||||
|
configService.getFeatureFlag$.mockReturnValue(of(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@@ -638,4 +644,27 @@ describe("SettingsComponent", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("desktop autotype", () => {
|
||||||
|
it("autotype should be hidden on mac os", async () => {
|
||||||
|
// Set OS
|
||||||
|
platformUtilsService.getDevice.mockReturnValue(DeviceType.MacOsDesktop);
|
||||||
|
|
||||||
|
// Recreate component to apply the correct device
|
||||||
|
fixture = TestBed.createComponent(SettingsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
await component.ngOnInit();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
// `enableAutotype` label shouldn't be found
|
||||||
|
const showEnableAutotypeLabelElement = fixture.debugElement.query(
|
||||||
|
By.css("label[for='enableAutotype']"),
|
||||||
|
);
|
||||||
|
expect(showEnableAutotypeLabelElement).toBeNull();
|
||||||
|
|
||||||
|
// `showEnableAutotype` should be false
|
||||||
|
expect(component.showEnableAutotype).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { UserVerificationService as UserVerificationServiceAbstraction } from "@
|
|||||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||||
import { DeviceType } from "@bitwarden/common/enums";
|
import { DeviceType } from "@bitwarden/common/enums";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction";
|
||||||
@@ -50,6 +51,7 @@ import {
|
|||||||
SelectModule,
|
SelectModule,
|
||||||
ToastService,
|
ToastService,
|
||||||
TypographyModule,
|
TypographyModule,
|
||||||
|
BadgeComponent,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { KeyService, BiometricStateService, BiometricsStatus } from "@bitwarden/key-management";
|
import { KeyService, BiometricStateService, BiometricsStatus } from "@bitwarden/key-management";
|
||||||
import { PermitCipherDetailsPopoverComponent } from "@bitwarden/vault";
|
import { PermitCipherDetailsPopoverComponent } from "@bitwarden/vault";
|
||||||
@@ -58,6 +60,7 @@ import { SetPinComponent } from "../../auth/components/set-pin.component";
|
|||||||
import { SshAgentPromptType } from "../../autofill/models/ssh-agent-setting";
|
import { SshAgentPromptType } from "../../autofill/models/ssh-agent-setting";
|
||||||
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
|
import { DesktopAutofillSettingsService } from "../../autofill/services/desktop-autofill-settings.service";
|
||||||
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
|
import { DesktopAutotypeService } from "../../autofill/services/desktop-autotype.service";
|
||||||
|
import { PremiumComponent } from "../../billing/app/accounts/premium.component";
|
||||||
import { DesktopBiometricsService } from "../../key-management/biometrics/desktop.biometrics.service";
|
import { DesktopBiometricsService } from "../../key-management/biometrics/desktop.biometrics.service";
|
||||||
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
|
import { DesktopSettingsService } from "../../platform/services/desktop-settings.service";
|
||||||
import { NativeMessagingManifestService } from "../services/native-messaging-manifest.service";
|
import { NativeMessagingManifestService } from "../services/native-messaging-manifest.service";
|
||||||
@@ -67,6 +70,7 @@ import { NativeMessagingManifestService } from "../services/native-messaging-man
|
|||||||
templateUrl: "settings.component.html",
|
templateUrl: "settings.component.html",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
|
BadgeComponent,
|
||||||
CheckboxModule,
|
CheckboxModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormFieldModule,
|
FormFieldModule,
|
||||||
@@ -130,6 +134,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
pinEnabled$: Observable<boolean> = of(true);
|
pinEnabled$: Observable<boolean> = of(true);
|
||||||
|
|
||||||
|
hasPremium: boolean = false;
|
||||||
|
|
||||||
form = this.formBuilder.group({
|
form = this.formBuilder.group({
|
||||||
// Security
|
// Security
|
||||||
vaultTimeout: [null as VaultTimeout | null],
|
vaultTimeout: [null as VaultTimeout | null],
|
||||||
@@ -158,7 +164,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
sshAgentPromptBehavior: SshAgentPromptType.Always,
|
sshAgentPromptBehavior: SshAgentPromptType.Always,
|
||||||
allowScreenshots: false,
|
allowScreenshots: false,
|
||||||
enableDuckDuckGoBrowserIntegration: false,
|
enableDuckDuckGoBrowserIntegration: false,
|
||||||
enableAutotype: false,
|
enableAutotype: this.formBuilder.control<boolean>({
|
||||||
|
value: false,
|
||||||
|
disabled: true,
|
||||||
|
}),
|
||||||
theme: [null as Theme | null],
|
theme: [null as Theme | null],
|
||||||
locale: [null as string | null],
|
locale: [null as string | null],
|
||||||
});
|
});
|
||||||
@@ -193,6 +202,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
private validationService: ValidationService,
|
private validationService: ValidationService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
|
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
this.isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
this.isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
||||||
this.isLinux = this.platformUtilsService.getDevice() === DeviceType.LinuxDesktop;
|
this.isLinux = this.platformUtilsService.getDevice() === DeviceType.LinuxDesktop;
|
||||||
@@ -268,10 +278,14 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
// Autotype is for Windows initially
|
// Autotype is for Windows initially
|
||||||
const isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop;
|
const isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop;
|
||||||
const windowsDesktopAutotypeFeatureFlag = await this.configService.getFeatureFlag(
|
if (isWindows) {
|
||||||
FeatureFlag.WindowsDesktopAutotype,
|
this.configService
|
||||||
);
|
.getFeatureFlag$(FeatureFlag.WindowsDesktopAutotype)
|
||||||
this.showEnableAutotype = isWindows && windowsDesktopAutotypeFeatureFlag;
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((enabled) => {
|
||||||
|
this.showEnableAutotype = enabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword();
|
this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword();
|
||||||
|
|
||||||
@@ -377,7 +391,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
this.desktopSettingsService.sshAgentPromptBehavior$,
|
this.desktopSettingsService.sshAgentPromptBehavior$,
|
||||||
),
|
),
|
||||||
allowScreenshots: !(await firstValueFrom(this.desktopSettingsService.preventScreenshots$)),
|
allowScreenshots: !(await firstValueFrom(this.desktopSettingsService.preventScreenshots$)),
|
||||||
enableAutotype: await firstValueFrom(this.desktopAutotypeService.autotypeEnabled$),
|
enableAutotype: await firstValueFrom(this.desktopAutotypeService.resolvedAutotypeEnabled$),
|
||||||
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
theme: await firstValueFrom(this.themeStateService.selectedTheme$),
|
||||||
locale: await firstValueFrom(this.i18nService.userSetLocale$),
|
locale: await firstValueFrom(this.i18nService.userSetLocale$),
|
||||||
};
|
};
|
||||||
@@ -402,6 +416,19 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
this.form.controls.vaultTimeoutAction.setValue(action, { emitEvent: false });
|
this.form.controls.vaultTimeoutAction.setValue(action, { emitEvent: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isWindows) {
|
||||||
|
this.billingAccountProfileStateService
|
||||||
|
.hasPremiumFromAnySource$(activeAccount.id)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((hasPremium) => {
|
||||||
|
this.hasPremium = hasPremium;
|
||||||
|
|
||||||
|
if (this.hasPremium) {
|
||||||
|
this.form.controls.enableAutotype.enable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Form events
|
// Form events
|
||||||
this.form.controls.vaultTimeout.valueChanges
|
this.form.controls.vaultTimeout.valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
@@ -865,6 +892,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async openPremiumDialog() {
|
||||||
|
await this.dialogService.open(PremiumComponent);
|
||||||
|
}
|
||||||
|
|
||||||
async saveEnableAutotype() {
|
async saveEnableAutotype() {
|
||||||
await this.desktopAutotypeService.setAutotypeEnabledState(this.form.value.enableAutotype);
|
await this.desktopAutotypeService.setAutotypeEnabledState(this.form.value.enableAutotype);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import {
|
|||||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||||
import { ClientType } from "@bitwarden/common/enums";
|
import { ClientType } from "@bitwarden/common/enums";
|
||||||
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/key-management/crypto";
|
import { KeyGenerationService } from "@bitwarden/common/key-management/crypto";
|
||||||
@@ -462,6 +463,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
ConfigService,
|
ConfigService,
|
||||||
GlobalStateProvider,
|
GlobalStateProvider,
|
||||||
PlatformUtilsServiceAbstraction,
|
PlatformUtilsServiceAbstraction,
|
||||||
|
BillingAccountProfileStateService,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { combineLatest, filter, firstValueFrom, map, Observable, of, switchMap }
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||||
import { DeviceType } from "@bitwarden/common/enums";
|
import { DeviceType } from "@bitwarden/common/enums";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
@@ -25,7 +26,7 @@ export const AUTOTYPE_ENABLED = new KeyDefinition<boolean>(
|
|||||||
export class DesktopAutotypeService {
|
export class DesktopAutotypeService {
|
||||||
private readonly autotypeEnabledState = this.globalStateProvider.get(AUTOTYPE_ENABLED);
|
private readonly autotypeEnabledState = this.globalStateProvider.get(AUTOTYPE_ENABLED);
|
||||||
|
|
||||||
autotypeEnabled$: Observable<boolean> = of(false);
|
resolvedAutotypeEnabled$: Observable<boolean> = of(false);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
@@ -34,6 +35,7 @@ export class DesktopAutotypeService {
|
|||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
private globalStateProvider: GlobalStateProvider,
|
private globalStateProvider: GlobalStateProvider,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
ipc.autofill.listenAutotypeRequest(async (windowTitle, callback) => {
|
ipc.autofill.listenAutotypeRequest(async (windowTitle, callback) => {
|
||||||
const possibleCiphers = await this.matchCiphersToWindowTitle(windowTitle);
|
const possibleCiphers = await this.matchCiphersToWindowTitle(windowTitle);
|
||||||
@@ -48,23 +50,30 @@ export class DesktopAutotypeService {
|
|||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
if (this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop) {
|
if (this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop) {
|
||||||
this.autotypeEnabled$ = combineLatest([
|
this.resolvedAutotypeEnabled$ = combineLatest([
|
||||||
this.autotypeEnabledState.state$,
|
this.autotypeEnabledState.state$,
|
||||||
this.configService.getFeatureFlag$(FeatureFlag.WindowsDesktopAutotype),
|
this.configService.getFeatureFlag$(FeatureFlag.WindowsDesktopAutotype),
|
||||||
this.accountService.activeAccount$.pipe(
|
this.accountService.activeAccount$.pipe(
|
||||||
map((account) => account?.id),
|
map((activeAccount) => activeAccount?.id),
|
||||||
switchMap((userId) => this.authService.authStatusFor$(userId)),
|
switchMap((userId) => this.authService.authStatusFor$(userId)),
|
||||||
),
|
),
|
||||||
|
this.accountService.activeAccount$.pipe(
|
||||||
|
map((activeAccount) => activeAccount?.id),
|
||||||
|
switchMap((userId) =>
|
||||||
|
this.billingAccountProfileStateService.hasPremiumFromAnySource$(userId),
|
||||||
|
),
|
||||||
|
),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map(
|
map(
|
||||||
([autotypeEnabled, windowsDesktopAutotypeFeatureFlag, authStatus]) =>
|
([autotypeEnabled, windowsDesktopAutotypeFeatureFlag, authStatus, hasPremium]) =>
|
||||||
autotypeEnabled &&
|
autotypeEnabled &&
|
||||||
windowsDesktopAutotypeFeatureFlag &&
|
windowsDesktopAutotypeFeatureFlag &&
|
||||||
authStatus == AuthenticationStatus.Unlocked,
|
authStatus == AuthenticationStatus.Unlocked &&
|
||||||
|
hasPremium,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.autotypeEnabled$.subscribe((enabled) => {
|
this.resolvedAutotypeEnabled$.subscribe((enabled) => {
|
||||||
ipc.autofill.configureAutotype(enabled);
|
ipc.autofill.configureAutotype(enabled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
>
|
>
|
||||||
<b>{{ "premiumPurchase" | i18n }}</b>
|
<b>{{ "premiumPurchase" | i18n }}</b>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" data-dismiss="modal">{{ "close" | i18n }}</button>
|
<button type="button" bitDialogClose>{{ "close" | i18n }}</button>
|
||||||
<div class="right" *ngIf="!(isPremium$ | async)">
|
<div class="right" *ngIf="!(isPremium$ | async)">
|
||||||
<button
|
<button
|
||||||
#refreshBtn
|
#refreshBtn
|
||||||
|
|||||||
@@ -4095,5 +4095,14 @@
|
|||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Confirm"
|
"message": "Confirm"
|
||||||
|
},
|
||||||
|
"enableAutotypeTransitionKey": {
|
||||||
|
"message": "Enable autotype shortcut"
|
||||||
|
},
|
||||||
|
"enableAutotypeDescriptionTransitionKey": {
|
||||||
|
"message": "Be sure you are in the correct field before using the shortcut to avoid filling data into the wrong place."
|
||||||
|
},
|
||||||
|
"editShortcut": {
|
||||||
|
"message": "Edit shortcut"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user