diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts
index c546db3c97e..20286435edb 100644
--- a/apps/browser/src/auth/popup/settings/account-security.component.ts
+++ b/apps/browser/src/auth/popup/settings/account-security.component.ts
@@ -559,9 +559,11 @@ export class AccountSecurityComponent implements OnInit, OnDestroy {
}
async fingerprint() {
- const fingerprint = await this.cryptoService.getFingerprint(
- await this.stateService.getUserId(),
+ const activeUserId = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
+ const publicKey = await firstValueFrom(this.cryptoService.userPublicKey$(activeUserId));
+ const fingerprint = await this.cryptoService.getFingerprint(activeUserId, publicKey);
const dialogRef = FingerprintDialogComponent.open(this.dialogService, {
fingerprint,
diff --git a/apps/browser/src/autofill/content/autofill-init.spec.ts b/apps/browser/src/autofill/content/autofill-init.spec.ts
index ebfbda75b56..b98d297d136 100644
--- a/apps/browser/src/autofill/content/autofill-init.spec.ts
+++ b/apps/browser/src/autofill/content/autofill-init.spec.ts
@@ -74,7 +74,7 @@ describe("AutofillInit", () => {
Object.defineProperty(document, "readyState", { value: "complete", writable: true });
autofillInit.init();
- jest.advanceTimersByTime(250);
+ jest.advanceTimersByTime(750);
expect(sendExtensionMessageSpy).toHaveBeenCalledWith("bgCollectPageDetails", {
sender: "autofillInit",
diff --git a/apps/browser/src/autofill/content/autofill-init.ts b/apps/browser/src/autofill/content/autofill-init.ts
index e901000dbb9..6c34508cb00 100644
--- a/apps/browser/src/autofill/content/autofill-init.ts
+++ b/apps/browser/src/autofill/content/autofill-init.ts
@@ -78,7 +78,7 @@ class AutofillInit implements AutofillInitInterface {
this.clearCollectPageDetailsOnLoadTimeout();
this.collectPageDetailsOnLoadTimeout = setTimeout(
() => this.sendExtensionMessage("bgCollectPageDetails", { sender: "autofillInit" }),
- 250,
+ 750,
);
};
diff --git a/apps/browser/src/autofill/popup/fido2/fido2-cipher-row.component.html b/apps/browser/src/autofill/popup/fido2/fido2-cipher-row.component.html
index 0328a91bff5..8b2504696d7 100644
--- a/apps/browser/src/autofill/popup/fido2/fido2-cipher-row.component.html
+++ b/apps/browser/src/autofill/popup/fido2/fido2-cipher-row.component.html
@@ -15,7 +15,9 @@
class="bwi bwi-collection text-muted"
>
- {{ getSubName(cipher) }}
- {{ cipher.subTitle }}
+
+ {{ getSubName(cipher) }}
+ {{ cipher.subTitle }}
+
diff --git a/apps/browser/src/autofill/popup/fido2/fido2.component.ts b/apps/browser/src/autofill/popup/fido2/fido2.component.ts
index c389e9ad5b8..cf0fd90a8fd 100644
--- a/apps/browser/src/autofill/popup/fido2/fido2.component.ts
+++ b/apps/browser/src/autofill/popup/fido2/fido2.component.ts
@@ -287,7 +287,7 @@ export class Fido2Component implements OnInit, OnDestroy {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "overwritePasskey" },
content: { key: "overwritePasskeyAlert" },
- type: "info",
+ type: "warning",
});
if (!confirmed) {
diff --git a/apps/browser/src/autofill/services/autofill-constants.ts b/apps/browser/src/autofill/services/autofill-constants.ts
index c379daaf2d8..656387f00bc 100644
--- a/apps/browser/src/autofill/services/autofill-constants.ts
+++ b/apps/browser/src/autofill/services/autofill-constants.ts
@@ -34,28 +34,30 @@ export class AutoFillConstants {
"totpcode",
"2facode",
"approvals_code",
- "code",
"mfacode",
- "otc",
"otc-code",
- "otp",
+ "onetimecode",
"otp-code",
"otpcode",
- "pin",
+ "onetimepassword",
"security_code",
"twofactor",
"twofa",
"twofactorcode",
"verificationCode",
+ "verification code",
];
+ static readonly AmbiguousTotpFieldNames: string[] = ["code", "pin", "otc", "otp"];
+
static readonly SearchFieldNames: string[] = ["search", "query", "find", "go"];
static readonly FieldIgnoreList: string[] = ["captcha", "findanything", "forgot"];
static readonly PasswordFieldExcludeList: string[] = [
+ "hint",
...AutoFillConstants.FieldIgnoreList,
- "onetimepassword",
+ ...AutoFillConstants.TotpFieldNames,
];
static readonly ExcludedAutofillLoginTypes: string[] = [
diff --git a/apps/browser/src/autofill/services/autofill.service.spec.ts b/apps/browser/src/autofill/services/autofill.service.spec.ts
index 455c171e59a..7bd08caaf33 100644
--- a/apps/browser/src/autofill/services/autofill.service.spec.ts
+++ b/apps/browser/src/autofill/services/autofill.service.spec.ts
@@ -2260,29 +2260,23 @@ describe("AutofillService", () => {
options,
);
- expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenCalledTimes(4);
- expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenNthCalledWith(
- 1,
+ expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenCalledWith(
usernameField,
AutoFillConstants.UsernameFieldNames,
);
- expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenNthCalledWith(
- 2,
+ expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenCalledWith(
emailField,
AutoFillConstants.UsernameFieldNames,
);
- expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenNthCalledWith(
- 3,
+ expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenCalledWith(
telephoneField,
AutoFillConstants.UsernameFieldNames,
);
- expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenNthCalledWith(
- 4,
+ expect(AutofillService.fieldIsFuzzyMatch).toHaveBeenCalledWith(
totpField,
AutoFillConstants.UsernameFieldNames,
);
- expect(AutofillService.fieldIsFuzzyMatch).not.toHaveBeenNthCalledWith(
- 5,
+ expect(AutofillService.fieldIsFuzzyMatch).not.toHaveBeenCalledWith(
nonViewableField,
AutoFillConstants.UsernameFieldNames,
);
@@ -2328,6 +2322,7 @@ describe("AutofillService", () => {
it("will not attempt to fuzzy match a totp field if totp autofill is not allowed", async () => {
options.allowTotpAutofill = false;
+ jest.spyOn(autofillService as any, "findMatchingFieldIndex");
await autofillService["generateLoginFillScript"](
fillScript,
@@ -2336,7 +2331,7 @@ describe("AutofillService", () => {
options,
);
- expect(AutofillService.fieldIsFuzzyMatch).not.toHaveBeenCalledWith(
+ expect(autofillService["findMatchingFieldIndex"]).not.toHaveBeenCalledWith(
expect.anything(),
AutoFillConstants.TotpFieldNames,
);
@@ -2386,7 +2381,6 @@ describe("AutofillService", () => {
false,
false,
);
- expect(AutofillService.fieldIsFuzzyMatch).not.toHaveBeenCalled();
expect(AutofillService.fillByOpid).toHaveBeenCalledTimes(2);
expect(AutofillService.fillByOpid).toHaveBeenNthCalledWith(
1,
diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts
index de79fd974ef..ea68b80e84f 100644
--- a/apps/browser/src/autofill/services/autofill.service.ts
+++ b/apps/browser/src/autofill/services/autofill.service.ts
@@ -887,7 +887,10 @@ export default class AutofillService implements AutofillServiceInterface {
options.allowTotpAutofill &&
f.viewable &&
(f.type === "text" || f.type === "number") &&
- (AutofillService.fieldIsFuzzyMatch(f, AutoFillConstants.TotpFieldNames) ||
+ (AutofillService.fieldIsFuzzyMatch(f, [
+ ...AutoFillConstants.TotpFieldNames,
+ ...AutoFillConstants.AmbiguousTotpFieldNames,
+ ]) ||
f.autoCompleteType === "one-time-code")
) {
totps.push(f);
@@ -2558,6 +2561,11 @@ export default class AutofillService implements AutofillServiceInterface {
return;
}
+ // We want to avoid treating TOTP fields as password fields
+ if (AutofillService.fieldIsFuzzyMatch(f, AutoFillConstants.TotpFieldNames)) {
+ return;
+ }
+
const isLikePassword = () => {
if (f.type !== "text") {
return false;
@@ -2670,12 +2678,18 @@ export default class AutofillService implements AutofillServiceInterface {
(withoutForm || f.form === passwordField.form) &&
(canBeHidden || f.viewable) &&
(f.type === "text" || f.type === "number") &&
- AutofillService.fieldIsFuzzyMatch(f, AutoFillConstants.TotpFieldNames)
+ AutofillService.fieldIsFuzzyMatch(f, [
+ ...AutoFillConstants.TotpFieldNames,
+ ...AutoFillConstants.AmbiguousTotpFieldNames,
+ ])
) {
totpField = f;
if (
- this.findMatchingFieldIndex(f, AutoFillConstants.TotpFieldNames) > -1 ||
+ this.findMatchingFieldIndex(f, [
+ ...AutoFillConstants.TotpFieldNames,
+ ...AutoFillConstants.AmbiguousTotpFieldNames,
+ ]) > -1 ||
f.autoCompleteType === "one-time-code"
) {
// We found an exact match. No need to keep looking.
diff --git a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts
index 0b04b83ce4e..9a98f65f7a2 100644
--- a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts
+++ b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts
@@ -30,7 +30,6 @@ export class InlineMenuFieldQualificationService
this.webAuthnAutocompleteValue,
]);
private fieldIgnoreListString = AutoFillConstants.FieldIgnoreList.join(",");
- private passwordFieldExcludeListString = AutoFillConstants.PasswordFieldExcludeList.join(",");
private currentPasswordAutocompleteValue = "current-password";
private newPasswordAutoCompleteValue = "new-password";
private autofillFieldKeywordsMap: AutofillKeywordsMap = new WeakMap();
@@ -927,7 +926,7 @@ export class InlineMenuFieldQualificationService
return false;
}
- return !(this.passwordFieldExcludeListString.indexOf(cleanedValue) > -1);
+ return !AutoFillConstants.PasswordFieldExcludeList.some((i) => cleanedValue.indexOf(i) > -1);
}
/**
@@ -1094,13 +1093,29 @@ export class InlineMenuFieldQualificationService
];
const keywordsSet = new Set();
for (let i = 0; i < keywords.length; i++) {
- if (typeof keywords[i] === "string") {
- keywords[i]
- .toLowerCase()
- .replace(/-/g, "")
- .replace(/[^a-zA-Z0-9]+/g, "|")
- .split("|")
- .forEach((keyword) => keywordsSet.add(keyword));
+ if (keywords[i] && typeof keywords[i] === "string") {
+ let keywordEl = keywords[i].toLowerCase();
+ keywordsSet.add(keywordEl);
+
+ // Remove hyphens from all potential keywords, we want to treat these as a single word.
+ keywordEl = keywordEl.replace(/-/g, "");
+
+ // Split the keyword by non-alphanumeric characters to get the keywords without treating a space as a separator.
+ keywordEl.split(/[^\p{L}\d]+/gu).forEach((keyword) => {
+ if (keyword) {
+ keywordsSet.add(keyword);
+ }
+ });
+
+ // Collapse all spaces and split by non-alphanumeric characters to get the keywords
+ keywordEl
+ .replace(/\s/g, "")
+ .split(/[^\p{L}\d]+/gu)
+ .forEach((keyword) => {
+ if (keyword) {
+ keywordsSet.add(keyword);
+ }
+ });
}
}
diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts
index 3b2b18c66e3..2829b3ee586 100644
--- a/apps/cli/src/commands/get.command.ts
+++ b/apps/cli/src/commands/get.command.ts
@@ -551,7 +551,11 @@ export class GetCommand extends DownloadCommand {
private async getFingerprint(id: string) {
let fingerprint: string[] = null;
if (id === "me") {
- fingerprint = await this.cryptoService.getFingerprint(await this.stateService.getUserId());
+ const activeUserId = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
+ );
+ const publicKey = await firstValueFrom(this.cryptoService.userPublicKey$(activeUserId));
+ fingerprint = await this.cryptoService.getFingerprint(activeUserId, publicKey);
} else if (Utils.isGuid(id)) {
try {
const response = await this.apiService.getUserPublicKey(id);
diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts
index c339990ab95..c5867281972 100644
--- a/apps/cli/src/service-container/service-container.ts
+++ b/apps/cli/src/service-container/service-container.ts
@@ -2,7 +2,7 @@ import * as fs from "fs";
import * as path from "path";
import * as jsdom from "jsdom";
-import { firstValueFrom } from "rxjs";
+import { firstValueFrom, map } from "rxjs";
import {
OrganizationUserApiService,
@@ -119,7 +119,6 @@ import {
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service";
import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-state.provider";
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
-import { UserId } from "@bitwarden/common/types/guid";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
@@ -788,13 +787,13 @@ export class ServiceContainer {
this.authService.logOut(() => {
/* Do nothing */
});
- const userId = (await this.stateService.getUserId()) as UserId;
+ const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
await Promise.all([
- this.eventUploadService.uploadEvents(userId as UserId),
+ this.eventUploadService.uploadEvents(userId),
this.cryptoService.clearKeys(),
this.cipherService.clear(userId),
this.folderService.clear(userId),
- this.collectionService.clear(userId as UserId),
+ this.collectionService.clear(userId),
]);
await this.stateEventRunnerService.handleEvent("logout", userId);
diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts
index d65283598cd..efe7cfa8e29 100644
--- a/apps/desktop/src/app/accounts/settings.component.ts
+++ b/apps/desktop/src/app/accounts/settings.component.ts
@@ -196,22 +196,23 @@ export class SettingsComponent implements OnInit, OnDestroy {
async ngOnInit() {
this.vaultTimeoutOptions = await this.generateVaultTimeoutOptions();
-
- this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword();
-
- this.isWindows = (await this.platformUtilsService.getDevice()) === DeviceType.WindowsDesktop;
+ const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
this.isLinux = (await this.platformUtilsService.getDevice()) === DeviceType.LinuxDesktop;
- if ((await this.stateService.getUserId()) == null) {
+ if (activeAccount == null || activeAccount.id == null) {
return;
}
- this.currentUserEmail = await firstValueFrom(
- this.accountService.activeAccount$.pipe(map((a) => a?.email)),
- );
- this.currentUserId = (await this.stateService.getUserId()) as UserId;
+ this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword();
+
+ this.isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop;
+
+ this.currentUserEmail = activeAccount.email;
+ this.currentUserId = activeAccount.id;
this.availableVaultTimeoutActions$ = this.refreshTimeoutSettings$.pipe(
- switchMap(() => this.vaultTimeoutSettingsService.availableVaultTimeoutActions$()),
+ switchMap(() =>
+ this.vaultTimeoutSettingsService.availableVaultTimeoutActions$(activeAccount.id),
+ ),
);
// Load timeout policy
@@ -236,12 +237,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
}),
);
- const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
-
// Load initial values
- this.userHasPinSet = await this.pinService.isPinSet(userId);
-
- const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
+ this.userHasPinSet = await this.pinService.isPinSet(activeAccount.id);
const initialValues = {
vaultTimeout: await firstValueFrom(
diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts
index fee477e4cad..4fd50912725 100644
--- a/apps/desktop/src/app/app.component.ts
+++ b/apps/desktop/src/app/app.component.ts
@@ -235,7 +235,8 @@ export class AppComponent implements OnInit, OnDestroy {
this.modalService.closeAll();
if (
message.userId == null ||
- message.userId === (await this.stateService.getUserId())
+ message.userId ===
+ (await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))))
) {
await this.router.navigate(["lock"]);
}
@@ -274,9 +275,11 @@ export class AppComponent implements OnInit, OnDestroy {
await this.openModal(PremiumComponent, this.premiumRef);
break;
case "showFingerprintPhrase": {
- const fingerprint = await this.cryptoService.getFingerprint(
- await this.stateService.getUserId(),
+ const activeUserId = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
+ const publicKey = await firstValueFrom(this.cryptoService.userPublicKey$(activeUserId));
+ const fingerprint = await this.cryptoService.getFingerprint(activeUserId, publicKey);
const dialogRef = FingerprintDialogComponent.open(this.dialogService, { fingerprint });
await firstValueFrom(dialogRef.closed);
break;
diff --git a/apps/desktop/src/app/layout/account-switcher.component.ts b/apps/desktop/src/app/layout/account-switcher.component.ts
index c6dbadade42..147c0c498ef 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.ts
+++ b/apps/desktop/src/app/layout/account-switcher.component.ts
@@ -201,8 +201,11 @@ export class AccountSwitcherComponent implements OnInit {
}): Promise<{ [userId: string]: InactiveAccount }> {
const inactiveAccounts: { [userId: string]: InactiveAccount } = {};
+ const activeUserId = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
+ );
for (const userId in baseAccounts) {
- if (userId == null || userId === (await this.stateService.getUserId())) {
+ if (userId == null || userId === activeUserId) {
continue;
}
diff --git a/apps/desktop/src/auth/lock.component.spec.ts b/apps/desktop/src/auth/lock.component.spec.ts
index 2d867019a8f..6bf34428828 100644
--- a/apps/desktop/src/auth/lock.component.spec.ts
+++ b/apps/desktop/src/auth/lock.component.spec.ts
@@ -461,11 +461,10 @@ describe("LockComponent", () => {
});
describe("canUseBiometric", () => {
- it("should call getUserId() on stateService", async () => {
- stateServiceMock.getUserId.mockResolvedValue("userId");
+ it("should call biometric.enabled with current active user", async () => {
await component["canUseBiometric"]();
- expect(ipc.keyManagement.biometric.enabled).toHaveBeenCalledWith("userId");
+ expect(ipc.keyManagement.biometric.enabled).toHaveBeenCalledWith(mockUserId);
});
});
diff --git a/apps/desktop/src/auth/lock.component.ts b/apps/desktop/src/auth/lock.component.ts
index 13451d402f6..6ab39f92a6a 100644
--- a/apps/desktop/src/auth/lock.component.ts
+++ b/apps/desktop/src/auth/lock.component.ts
@@ -1,6 +1,6 @@
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
-import { firstValueFrom, switchMap } from "rxjs";
+import { firstValueFrom, map, switchMap } from "rxjs";
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
@@ -182,7 +182,7 @@ export class LockComponent extends BaseLockComponent implements OnInit, OnDestro
}
private async canUseBiometric() {
- const userId = await this.stateService.getUserId();
+ const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
return await ipc.keyManagement.biometric.enabled(userId);
}
diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts
index 483e1a52c44..578bc9111cf 100644
--- a/apps/web/src/app/app.component.ts
+++ b/apps/web/src/app/app.component.ts
@@ -23,7 +23,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { StateEventRunnerService } from "@bitwarden/common/platform/state";
import { SyncService } from "@bitwarden/common/platform/sync";
-import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@@ -277,7 +276,7 @@ export class AppComponent implements OnDestroy, OnInit {
await this.displayLogoutReason(logoutReason);
await this.eventUploadService.uploadEvents();
- const userId = (await this.stateService.getUserId()) as UserId;
+ const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
const logoutPromise = firstValueFrom(
this.authService.authStatusFor$(userId).pipe(
diff --git a/apps/web/src/app/auth/settings/account/profile.component.ts b/apps/web/src/app/auth/settings/account/profile.component.ts
index 8b659e579da..70cb70c5817 100644
--- a/apps/web/src/app/auth/settings/account/profile.component.ts
+++ b/apps/web/src/app/auth/settings/account/profile.component.ts
@@ -1,13 +1,12 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
-import { Subject, takeUntil } from "rxjs";
+import { firstValueFrom, map, Subject, takeUntil } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
+import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { UpdateProfileRequest } from "@bitwarden/common/auth/models/request/update-profile.request";
import { ProfileResponse } from "@bitwarden/common/models/response/profile.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
-import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
-import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { DialogService, ToastService } from "@bitwarden/components";
import { ChangeAvatarDialogComponent } from "./change-avatar-dialog.component";
@@ -30,8 +29,7 @@ export class ProfileComponent implements OnInit, OnDestroy {
constructor(
private apiService: ApiService,
private i18nService: I18nService,
- private platformUtilsService: PlatformUtilsService,
- private stateService: StateService,
+ private accountService: AccountService,
private dialogService: DialogService,
private toastService: ToastService,
) {}
@@ -39,7 +37,9 @@ export class ProfileComponent implements OnInit, OnDestroy {
async ngOnInit() {
this.profile = await this.apiService.getProfile();
this.loading = false;
- this.fingerprintMaterial = await this.stateService.getUserId();
+ this.fingerprintMaterial = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
+ );
this.formGroup.get("name").setValue(this.profile.name);
this.formGroup.get("email").setValue(this.profile.email);
diff --git a/apps/web/src/app/auth/settings/security/security-keys.component.ts b/apps/web/src/app/auth/settings/security/security-keys.component.ts
index 8de629dc83e..a8892def5c1 100644
--- a/apps/web/src/app/auth/settings/security/security-keys.component.ts
+++ b/apps/web/src/app/auth/settings/security/security-keys.component.ts
@@ -1,8 +1,9 @@
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
+import { firstValueFrom, map } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
+import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
-import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { DialogService } from "@bitwarden/components";
import { ApiKeyComponent } from "./api-key.component";
@@ -21,7 +22,7 @@ export class SecurityKeysComponent implements OnInit {
constructor(
private userVerificationService: UserVerificationService,
- private stateService: StateService,
+ private accountService: AccountService,
private apiService: ApiService,
private dialogService: DialogService,
) {}
@@ -31,7 +32,9 @@ export class SecurityKeysComponent implements OnInit {
}
async viewUserApiKey() {
- const entityId = await this.stateService.getUserId();
+ const entityId = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
+ );
await ApiKeyComponent.open(this.dialogService, {
data: {
keyType: "user",
@@ -47,7 +50,9 @@ export class SecurityKeysComponent implements OnInit {
}
async rotateUserApiKey() {
- const entityId = await this.stateService.getUserId();
+ const entityId = await firstValueFrom(
+ this.accountService.activeAccount$.pipe(map((a) => a?.id)),
+ );
await ApiKeyComponent.open(this.dialogService, {
data: {
keyType: "user",
diff --git a/libs/common/src/platform/abstractions/state.service.ts b/libs/common/src/platform/abstractions/state.service.ts
index 1ffe5b4353e..619bab8f034 100644
--- a/libs/common/src/platform/abstractions/state.service.ts
+++ b/libs/common/src/platform/abstractions/state.service.ts
@@ -58,6 +58,14 @@ export abstract class StateService {
setCryptoMasterKeyAuto: (value: string, options?: StorageOptions) => Promise;
getDuckDuckGoSharedKey: (options?: StorageOptions) => Promise;
setDuckDuckGoSharedKey: (value: string, options?: StorageOptions) => Promise;
+
+ /**
+ * @deprecated Use `TokenService.hasAccessToken$()` or `AuthService.authStatusFor$` instead.
+ */
getIsAuthenticated: (options?: StorageOptions) => Promise;
+
+ /**
+ * @deprecated Use `AccountService.activeAccount$` instead.
+ */
getUserId: (options?: StorageOptions) => Promise;
}
diff --git a/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts b/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts
index 487a2578b5e..942b8ce451a 100644
--- a/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts
+++ b/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts
@@ -138,8 +138,6 @@ describe("VaultTimeoutService", () => {
return new BehaviorSubject(accounts[userId]?.vaultTimeout);
});
- stateService.getUserId.mockResolvedValue(globalSetups?.userId);
-
// Set desired user active and known users on accounts service : note the only thing that matters here is that the ID are set
if (globalSetups?.userId) {
accountService.activeAccountSubject.next({
diff --git a/package-lock.json b/package-lock.json
index 6498bb54c37..f5e233c2328 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -178,7 +178,7 @@
"tsconfig-paths-webpack-plugin": "4.1.0",
"type-fest": "2.19.0",
"typescript": "5.1.6",
- "url": "0.11.3",
+ "url": "0.11.4",
"util": "0.12.5",
"wait-on": "8.0.1",
"webpack": "5.94.0",
@@ -37794,14 +37794,17 @@
"license": "MIT"
},
"node_modules/url": {
- "version": "0.11.3",
- "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz",
- "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==",
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
+ "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
"dev": true,
"license": "MIT",
"dependencies": {
"punycode": "^1.4.1",
- "qs": "^6.11.2"
+ "qs": "^6.12.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
"node_modules/url-parse": {
diff --git a/package.json b/package.json
index d16b7d70365..ed4e95c0127 100644
--- a/package.json
+++ b/package.json
@@ -139,7 +139,7 @@
"tsconfig-paths-webpack-plugin": "4.1.0",
"type-fest": "2.19.0",
"typescript": "5.1.6",
- "url": "0.11.3",
+ "url": "0.11.4",
"util": "0.12.5",
"wait-on": "8.0.1",
"webpack": "5.94.0",