diff --git a/apps/browser/src/auth/services/auth-request-answering/extension-auth-request-answering.service.ts b/apps/browser/src/auth/services/auth-request-answering/extension-auth-request-answering.service.ts index 175d6e899b0..a647e870b3c 100644 --- a/apps/browser/src/auth/services/auth-request-answering/extension-auth-request-answering.service.ts +++ b/apps/browser/src/auth/services/auth-request-answering/extension-auth-request-answering.service.ts @@ -42,7 +42,7 @@ export class ExtensionAuthRequestAnsweringService ); } - override async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise { + async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise { if (!authRequestId) { throw new Error("authRequestId not found."); } diff --git a/apps/desktop/src/auth/services/auth-request-answering/desktop-auth-request-answering.service.ts b/apps/desktop/src/auth/services/auth-request-answering/desktop-auth-request-answering.service.ts index 1a091b498b0..69865522481 100644 --- a/apps/desktop/src/auth/services/auth-request-answering/desktop-auth-request-answering.service.ts +++ b/apps/desktop/src/auth/services/auth-request-answering/desktop-auth-request-answering.service.ts @@ -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 { + async receivedPendingAuthRequest(userId: UserId, authRequestId: string): Promise { // 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"); - } } diff --git a/libs/common/src/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction.ts b/libs/common/src/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction.ts index 68ed182b0aa..7881e0f1a80 100644 --- a/libs/common/src/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction.ts +++ b/libs/common/src/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction.ts @@ -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; - /** - * 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; - - /** - * Process notifications that have been received but didn't meet the conditions to display the - * approval dialog. - */ - abstract processPendingAuthRequests(): Promise; - /** * Sets up listeners for scenarios where the user unlocks and we want to process * any pending auth requests in state. diff --git a/libs/common/src/auth/services/auth-request-answering/default-auth-request-answering.service.ts b/libs/common/src/auth/services/auth-request-answering/default-auth-request-answering.service.ts index 132d43b9a3c..90713366bb8 100644 --- a/libs/common/src/auth/services/auth-request-answering/default-auth-request-answering.service.ts +++ b/libs/common/src/auth/services/auth-request-answering/default-auth-request-answering.service.ts @@ -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 { - throw new Error("receivedPendingAuthRequest() not implemented for this client"); - } - async userMeetsConditionsToShowApprovalDialog(userId: UserId): Promise { 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 { - throw new Error("handleAuthRequestNotificationClicked() not implemented for this client"); - } - - async processPendingAuthRequests(): Promise { - // 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 { // 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 { + // 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"); + } + } + } } diff --git a/libs/common/src/auth/services/auth-request-answering/noop-auth-request-answering.service.ts b/libs/common/src/auth/services/auth-request-answering/noop-auth-request-answering.service.ts index e027422fcd6..416e6d06833 100644 --- a/libs/common/src/auth/services/auth-request-answering/noop-auth-request-answering.service.ts +++ b/libs/common/src/auth/services/auth-request-answering/noop-auth-request-answering.service.ts @@ -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 { - // no-op throw new Error("userMeetsConditionsToShowApprovalDialog() not implemented for this client"); } - - async handleAuthRequestNotificationClicked(event: SystemNotificationEvent) {} // no-op - - async processPendingAuthRequests(): Promise {} // no-op - - setupUnlockListenersForProcessingAuthRequests(): void {} // no-op + setupUnlockListenersForProcessingAuthRequests(): void {} }