1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-06 11:43:51 +00:00

restructure service architecture

This commit is contained in:
rr-bw
2025-11-07 16:39:46 -08:00
parent 6f1179cde3
commit 84df82efac
5 changed files with 30 additions and 64 deletions

View File

@@ -42,7 +42,7 @@ export class ExtensionAuthRequestAnsweringService
);
}
override async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise<void> {
async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise<void> {
if (!authRequestId) {
throw new Error("authRequestId not found.");
}

View File

@@ -8,7 +8,6 @@ import { PendingAuthRequestsStateService } from "@bitwarden/common/auth/services
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { SystemNotificationEvent } from "@bitwarden/common/platform/system-notifications/system-notifications.service";
import { UserId } from "@bitwarden/user-core";
export class DesktopAuthRequestAnsweringService
@@ -38,7 +37,7 @@ export class DesktopAuthRequestAnsweringService
* Desktop notification do not run any auth-request-specific actions.
* All clicks simply open the Desktop window. See electron-main-messaging.service.ts.
*/
override async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise<void> {
async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise<void> {
// Always persist the pending marker for this user to global state.
await this.pendingAuthRequestsState.add(userId);
@@ -67,10 +66,4 @@ export class DesktopAuthRequestAnsweringService
);
}
}
async handleAuthRequestNotificationClicked(event: SystemNotificationEvent) {
// Not implemented for Desktop because click handling is already setup in electron-main-messaging.service.ts.
// See click handler in ipcMain.handle("loginRequest"...
throw new Error("handleAuthRequestNotificationClicked() not implemented for this client");
}
}

View File

@@ -1,6 +1,5 @@
import { Observable } from "rxjs";
import { SystemNotificationEvent } from "@bitwarden/common/platform/system-notifications/system-notifications.service";
import { UserId } from "@bitwarden/user-core";
export abstract class AuthRequestAnsweringService {
@@ -27,20 +26,6 @@ export abstract class AuthRequestAnsweringService {
*/
abstract userMeetsConditionsToShowApprovalDialog(userId: UserId): Promise<boolean>;
/**
* When a system notification is clicked, this function is used to process that event.
* - Implemented in Extension only
*
* @param event The event passed in. Check initNotificationSubscriptions in main.background.ts.
*/
abstract handleAuthRequestNotificationClicked(event: SystemNotificationEvent): Promise<void>;
/**
* Process notifications that have been received but didn't meet the conditions to display the
* approval dialog.
*/
abstract processPendingAuthRequests(): Promise<void>;
/**
* Sets up listeners for scenarios where the user unlocks and we want to process
* any pending auth requests in state.

View File

@@ -19,7 +19,6 @@ import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/for
import { getOptionalUserId, getUserId } from "@bitwarden/common/auth/services/account.service";
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { SystemNotificationEvent } from "@bitwarden/common/platform/system-notifications/system-notifications.service";
import { UserId } from "@bitwarden/user-core";
import { AuthRequestAnsweringService } from "../../abstractions/auth-request-answering/auth-request-answering.service.abstraction";
@@ -38,10 +37,6 @@ export class DefaultAuthRequestAnsweringService implements AuthRequestAnsweringS
protected readonly pendingAuthRequestsState: PendingAuthRequestsStateService,
) {}
async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise<void> {
throw new Error("receivedPendingAuthRequest() not implemented for this client");
}
async userMeetsConditionsToShowApprovalDialog(userId: UserId): Promise<boolean> {
const authStatus = await firstValueFrom(this.authService.activeAccountStatus$);
const activeUserId: UserId | null = await firstValueFrom(
@@ -60,33 +55,6 @@ export class DefaultAuthRequestAnsweringService implements AuthRequestAnsweringS
return meetsConditions;
}
async handleAuthRequestNotificationClicked(event: SystemNotificationEvent): Promise<void> {
throw new Error("handleAuthRequestNotificationClicked() not implemented for this client");
}
async processPendingAuthRequests(): Promise<void> {
// Prune any stale pending requests (older than 15 minutes)
// This comes from GlobalSettings.cs
// public TimeSpan UserRequestExpiration { get; set; } = TimeSpan.FromMinutes(15);
const fifteenMinutesMs = 15 * 60 * 1000;
await this.pendingAuthRequestsState.pruneOlderThan(fifteenMinutesMs);
const pendingAuthRequestsInState: PendingAuthUserMarker[] =
(await firstValueFrom(this.pendingAuthRequestsState.getAll$())) ?? [];
if (pendingAuthRequestsInState.length > 0) {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
const pendingAuthRequestsForActiveUser = pendingAuthRequestsInState.some(
(e) => e.userId === activeUserId,
);
if (pendingAuthRequestsForActiveUser) {
this.messagingService.send("openLoginApproval");
}
}
}
setupUnlockListenersForProcessingAuthRequests(destroy$: Observable<void>): void {
// When account switching to a user who is Unlocked, process any pending auth requests.
this.accountService.activeAccount$
@@ -118,4 +86,31 @@ export class DefaultAuthRequestAnsweringService implements AuthRequestAnsweringS
void this.processPendingAuthRequests();
});
}
/**
* Process notifications that have been received but didn't meet the conditions to display the
* approval dialog.
*/
private async processPendingAuthRequests(): Promise<void> {
// Prune any stale pending requests (older than 15 minutes)
// This comes from GlobalSettings.cs
// public TimeSpan UserRequestExpiration { get; set; } = TimeSpan.FromMinutes(15);
const fifteenMinutesMs = 15 * 60 * 1000;
await this.pendingAuthRequestsState.pruneOlderThan(fifteenMinutesMs);
const pendingAuthRequestsInState: PendingAuthUserMarker[] =
(await firstValueFrom(this.pendingAuthRequestsState.getAll$())) ?? [];
if (pendingAuthRequestsInState.length > 0) {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
const pendingAuthRequestsForActiveUser = pendingAuthRequestsInState.some(
(e) => e.userId === activeUserId,
);
if (pendingAuthRequestsForActiveUser) {
this.messagingService.send("openLoginApproval");
}
}
}
}

View File

@@ -1,17 +1,10 @@
import { SystemNotificationEvent } from "@bitwarden/common/platform/system-notifications/system-notifications.service";
import { UserId } from "@bitwarden/user-core";
import { AuthRequestAnsweringService } from "../../abstractions/auth-request-answering/auth-request-answering.service.abstraction";
export class NoopAuthRequestAnsweringService implements AuthRequestAnsweringService {
async userMeetsConditionsToShowApprovalDialog(userId: UserId): Promise<boolean> {
// no-op
throw new Error("userMeetsConditionsToShowApprovalDialog() not implemented for this client");
}
async handleAuthRequestNotificationClicked(event: SystemNotificationEvent) {} // no-op
async processPendingAuthRequests(): Promise<void> {} // no-op
setupUnlockListenersForProcessingAuthRequests(): void {} // no-op
setupUnlockListenersForProcessingAuthRequests(): void {}
}