mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 03:33:30 +00:00
fix(browser-approval): [PM-23620] Auth Request Answering Service - Work in progress.
This commit is contained in:
@@ -31,6 +31,7 @@ import { DefaultPolicyService } from "@bitwarden/common/admin-console/services/p
|
||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service";
|
||||
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service";
|
||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
|
||||
@@ -41,6 +42,7 @@ import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/ab
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
||||
import { AuthRequestAnsweringService } from "@bitwarden/common/auth/services/auth-request-answering/auth-request-answering.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
||||
import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation";
|
||||
@@ -124,7 +126,7 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym
|
||||
import { ServerNotificationsService } from "@bitwarden/common/platform/notifications";
|
||||
// eslint-disable-next-line no-restricted-imports -- Needed for service creation
|
||||
import {
|
||||
DefaultNotificationsService,
|
||||
DefaultServerNotificationsService,
|
||||
SignalRConnectionService,
|
||||
UnsupportedWebPushConnectionService,
|
||||
WebPushNotificationsApiService,
|
||||
@@ -346,9 +348,10 @@ export default class MainBackground {
|
||||
importService: ImportServiceAbstraction;
|
||||
exportService: VaultExportServiceAbstraction;
|
||||
searchService: SearchServiceAbstraction;
|
||||
notificationsService: ServerNotificationsService;
|
||||
serverNotificationsService: ServerNotificationsService;
|
||||
systemNotificationService: SystemNotificationsService;
|
||||
actionsService: ActionsService;
|
||||
authRequestAnsweringService: AuthRequestAnsweringServiceAbstraction;
|
||||
stateService: StateServiceAbstraction;
|
||||
userNotificationSettingsService: UserNotificationSettingsServiceAbstraction;
|
||||
autofillSettingsService: AutofillSettingsServiceAbstraction;
|
||||
@@ -1145,7 +1148,24 @@ export default class MainBackground {
|
||||
this.systemNotificationService = new UnsupportedSystemNotificationsService();
|
||||
}
|
||||
|
||||
this.notificationsService = new DefaultNotificationsService(
|
||||
// void Promise.all([this.configService.getFeatureFlag(FeatureFlag.PM14938_BrowserExtensionLoginApproval)])
|
||||
// .then((isBrowserExtensionLoginApprovalFFOn) => {
|
||||
// if (isBrowserExtensionLoginApprovalFFOn) {
|
||||
// this.authRequestAnsweringService = new AuthRequestAnsweringService(
|
||||
// this.systemNotificationService,
|
||||
// this.actionsService,
|
||||
// );
|
||||
// } else {
|
||||
// this.authRequestAnsweringService = new UnsupportedAuthRequestAnsweringService();
|
||||
// }
|
||||
// });
|
||||
|
||||
this.authRequestAnsweringService = new AuthRequestAnsweringService(
|
||||
this.systemNotificationService,
|
||||
this.actionsService,
|
||||
);
|
||||
|
||||
this.serverNotificationsService = new DefaultServerNotificationsService(
|
||||
this.logService,
|
||||
this.syncService,
|
||||
this.appIdService,
|
||||
@@ -1156,6 +1176,7 @@ export default class MainBackground {
|
||||
new SignalRConnectionService(this.apiService, this.logService),
|
||||
this.authService,
|
||||
this.webPushConnectionService,
|
||||
this.authRequestAnsweringService,
|
||||
);
|
||||
|
||||
this.fido2UserInterfaceService = new BrowserFido2UserInterfaceService(this.authService);
|
||||
@@ -1216,7 +1237,7 @@ export default class MainBackground {
|
||||
this,
|
||||
this.autofillService,
|
||||
this.platformUtilsService as BrowserPlatformUtilsService,
|
||||
this.notificationsService,
|
||||
this.serverNotificationsService,
|
||||
this.autofillSettingsService,
|
||||
this.processReloadService,
|
||||
this.environmentService,
|
||||
@@ -1255,7 +1276,7 @@ export default class MainBackground {
|
||||
this.apiService,
|
||||
this.organizationService,
|
||||
this.authService,
|
||||
this.notificationsService,
|
||||
this.serverNotificationsService,
|
||||
messageListener,
|
||||
);
|
||||
|
||||
@@ -1332,7 +1353,7 @@ export default class MainBackground {
|
||||
|
||||
this.idleBackground = new IdleBackground(
|
||||
this.vaultTimeoutService,
|
||||
this.notificationsService,
|
||||
this.serverNotificationsService,
|
||||
this.accountService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
);
|
||||
@@ -1390,7 +1411,7 @@ export default class MainBackground {
|
||||
this.endUserNotificationService = new DefaultEndUserNotificationService(
|
||||
this.stateProvider,
|
||||
this.apiService,
|
||||
this.notificationsService,
|
||||
this.serverNotificationsService,
|
||||
this.authService,
|
||||
this.logService,
|
||||
);
|
||||
@@ -1484,7 +1505,7 @@ export default class MainBackground {
|
||||
setTimeout(async () => {
|
||||
await this.fullSync(false);
|
||||
this.backgroundSyncService.init();
|
||||
this.notificationsService.startListening();
|
||||
this.serverNotificationsService.startListening();
|
||||
|
||||
this.taskService.listenForTaskNotifications();
|
||||
|
||||
|
||||
@@ -588,6 +588,16 @@ const safeProviders: SafeProvider[] = [
|
||||
PlatformUtilsService,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: ActionsService,
|
||||
useClass: BrowserActionsService,
|
||||
deps: [LogService, PlatformUtilsService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: SystemNotificationsService,
|
||||
useClass: BrowserSystemNotificationService,
|
||||
deps: [LogService, PlatformUtilsService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: Fido2UserVerificationService,
|
||||
useClass: Fido2UserVerificationService,
|
||||
|
||||
@@ -93,6 +93,7 @@ import {
|
||||
InternalAccountService,
|
||||
} from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AnonymousHubService as AnonymousHubServiceAbstraction } from "@bitwarden/common/auth/abstractions/anonymous-hub.service";
|
||||
import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service";
|
||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
|
||||
@@ -210,8 +211,8 @@ import { GlobalState } from "@bitwarden/common/platform/models/domain/global-sta
|
||||
import { ServerNotificationsService } from "@bitwarden/common/platform/notifications";
|
||||
// eslint-disable-next-line no-restricted-imports -- Needed for service creation
|
||||
import {
|
||||
DefaultNotificationsService,
|
||||
NoopNotificationsService,
|
||||
DefaultServerNotificationsService,
|
||||
UnsupportedServerNotificationsService,
|
||||
SignalRConnectionService,
|
||||
UnsupportedWebPushConnectionService,
|
||||
WebPushConnectionService,
|
||||
@@ -385,6 +386,9 @@ import {
|
||||
WINDOW,
|
||||
} from "./injection-tokens";
|
||||
import { ModalService } from "./modal.service";
|
||||
import { AuthRequestAnsweringService } from "@bitwarden/common/auth/services/auth-request-answering/auth-request-answering.service";
|
||||
import { SystemNotificationsService } from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import { UnsupportedSystemNotificationsService } from "@bitwarden/common/platform/notifications/unsupported-system-notifications.service";
|
||||
|
||||
/**
|
||||
* Provider definitions used in the ngModule.
|
||||
@@ -951,11 +955,26 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: UnsupportedActionsService,
|
||||
deps: [],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: ActionsService,
|
||||
useClass: UnsupportedActionsService,
|
||||
deps: [],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: SystemNotificationsService,
|
||||
useClass: UnsupportedSystemNotificationsService,
|
||||
deps: [],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: AuthRequestAnsweringServiceAbstraction,
|
||||
useClass: AuthRequestAnsweringService,
|
||||
deps: [SystemNotificationsService, ActionsService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: ServerNotificationsService,
|
||||
useClass: devFlagEnabled("noopNotifications")
|
||||
? NoopNotificationsService
|
||||
: DefaultNotificationsService,
|
||||
? UnsupportedServerNotificationsService
|
||||
: DefaultServerNotificationsService,
|
||||
deps: [
|
||||
LogService,
|
||||
SyncService,
|
||||
@@ -967,6 +986,7 @@ const safeProviders: SafeProvider[] = [
|
||||
SignalRConnectionService,
|
||||
AuthServiceAbstraction,
|
||||
WebPushConnectionService,
|
||||
AuthRequestAnsweringServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Component, HostListener, OnDestroy, OnInit } from "@angular/core";
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
@@ -160,6 +160,21 @@ export class SelfHostedEnvConfigDialogComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener("document:keydown.control.b", ["$event"])
|
||||
onCtrlB(event: KeyboardEvent) {
|
||||
if (process.env.ENV === "development") {
|
||||
event.preventDefault();
|
||||
this.formGroup.patchValue({
|
||||
baseUrl: "",
|
||||
webVaultUrl: "https://localhost:8080",
|
||||
apiUrl: "http://localhost:4000",
|
||||
identityUrl: "http://localhost:33656",
|
||||
iconsUrl: "http://localhost:50024",
|
||||
notificationsUrl: "http://localhost:61840",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
this.showErrorSummary = false;
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { SystemNotificationEvent } from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
|
||||
export abstract class AuthRequestAnsweringServiceAbstraction {
|
||||
abstract receivedPendingAuthRequest(userId: UserId, notificationId: string): Promise<void>;
|
||||
|
||||
abstract handleAuthRequestNotificationClicked(event: SystemNotificationEvent): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { filter, mergeMap } from "rxjs";
|
||||
|
||||
import { ActionsService } from "@bitwarden/common/platform/actions";
|
||||
import {
|
||||
ButtonActions,
|
||||
ButtonLocation,
|
||||
SystemNotificationEvent,
|
||||
SystemNotificationsService,
|
||||
} from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
|
||||
import { AuthRequestAnsweringServiceAbstraction } from "../../abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
|
||||
export class AuthRequestAnsweringService implements AuthRequestAnsweringServiceAbstraction {
|
||||
constructor(
|
||||
private readonly systemNotificationsService: SystemNotificationsService,
|
||||
private readonly actionService: ActionsService,
|
||||
) {
|
||||
this.systemNotificationsService.notificationClicked$
|
||||
.pipe(
|
||||
filter(
|
||||
(event: SystemNotificationEvent) => event.type === ButtonActions.AuthRequestNotification,
|
||||
),
|
||||
mergeMap((event: SystemNotificationEvent) =>
|
||||
this.handleAuthRequestNotificationClicked(event),
|
||||
),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
async handleAuthRequestNotificationClicked(event: SystemNotificationEvent): Promise<void> {
|
||||
if (event.buttonIdentifier === ButtonLocation.NotificationButton) {
|
||||
// TODO: Uncomment this before going into review
|
||||
// await this.systemNotificationService.clear({
|
||||
// id: event.id,
|
||||
// })
|
||||
await this.actionService.openPopup();
|
||||
}
|
||||
}
|
||||
|
||||
async receivedPendingAuthRequest(userId: UserId, notificationId: string): Promise<void> {
|
||||
await this.systemNotificationsService.create({
|
||||
id: notificationId,
|
||||
type: ButtonActions.AuthRequestNotification,
|
||||
title: "Test (i18n)",
|
||||
body: "Pending Auth Request to Approve (i18n)",
|
||||
buttons: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { SystemNotificationEvent } from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import { UserId } from "@bitwarden/user-core";
|
||||
|
||||
import { AuthRequestAnsweringServiceAbstraction } from "../../abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
|
||||
export class UnsupportedAuthRequestAnsweringService
|
||||
implements AuthRequestAnsweringServiceAbstraction
|
||||
{
|
||||
constructor() {}
|
||||
async handleAuthRequestNotificationClicked(event: SystemNotificationEvent): Promise<void> {
|
||||
throw new Error("Received pending auth request not supported.");
|
||||
}
|
||||
|
||||
async receivedPendingAuthRequest(userId: UserId, notificationId: string): Promise<void> {
|
||||
throw new Error("Received pending auth request not supported.");
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { BehaviorSubject, bufferCount, firstValueFrom, ObservedValueOf, Subject
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { LogoutReason } from "@bitwarden/auth/common";
|
||||
import { SystemNotificationsService } from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
|
||||
import { awaitAsync } from "../../../../spec";
|
||||
import { Matrix } from "../../../../spec/matrix";
|
||||
@@ -21,9 +22,9 @@ import { SupportStatus } from "../../misc/support-status";
|
||||
import { SyncService } from "../../sync";
|
||||
|
||||
import {
|
||||
DefaultNotificationsService,
|
||||
DefaultServerNotificationsService,
|
||||
DISABLED_NOTIFICATIONS_URL,
|
||||
} from "./default-notifications.service";
|
||||
} from "./default-server-notifications.service";
|
||||
import { SignalRConnectionService, SignalRNotification } from "./signalr-connection.service";
|
||||
import { WebPushConnectionService, WebPushConnector } from "./webpush-connection.service";
|
||||
import { WorkerWebPushConnectionService } from "./worker-webpush-connection.service";
|
||||
@@ -38,6 +39,7 @@ describe("NotificationsService", () => {
|
||||
let signalRNotificationConnectionService: MockProxy<SignalRConnectionService>;
|
||||
let authService: MockProxy<AuthService>;
|
||||
let webPushNotificationConnectionService: MockProxy<WebPushConnectionService>;
|
||||
let systemNotificationService: MockProxy<SystemNotificationsService>;
|
||||
|
||||
let activeAccount: BehaviorSubject<ObservedValueOf<AccountService["activeAccount$"]>>;
|
||||
|
||||
@@ -52,7 +54,7 @@ describe("NotificationsService", () => {
|
||||
notificationsUrl: string,
|
||||
) => Subject<SignalRNotification>;
|
||||
|
||||
let sut: DefaultNotificationsService;
|
||||
let sut: DefaultServerNotificationsService;
|
||||
|
||||
beforeEach(() => {
|
||||
syncService = mock<SyncService>();
|
||||
@@ -93,7 +95,7 @@ describe("NotificationsService", () => {
|
||||
() => new Subject<SignalRNotification>(),
|
||||
);
|
||||
|
||||
sut = new DefaultNotificationsService(
|
||||
sut = new DefaultServerNotificationsService(
|
||||
mock<LogService>(),
|
||||
syncService,
|
||||
appIdService,
|
||||
@@ -104,6 +106,7 @@ describe("NotificationsService", () => {
|
||||
signalRNotificationConnectionService,
|
||||
authService,
|
||||
webPushNotificationConnectionService,
|
||||
systemNotificationService,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { LogoutReason } from "@bitwarden/auth/common";
|
||||
import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
|
||||
import { AccountService } from "../../../auth/abstractions/account.service";
|
||||
import { AuthService } from "../../../auth/abstractions/auth.service";
|
||||
@@ -32,14 +33,14 @@ import { EnvironmentService } from "../../abstractions/environment.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { MessagingService } from "../../abstractions/messaging.service";
|
||||
import { supportSwitch } from "../../misc/support-status";
|
||||
import { ServerNotificationsService as NotificationsServiceAbstraction } from "../server-notifications-service";
|
||||
import { ServerNotificationsService } from "../server-notifications-service";
|
||||
|
||||
import { ReceiveMessage, SignalRConnectionService } from "./signalr-connection.service";
|
||||
import { WebPushConnectionService } from "./webpush-connection.service";
|
||||
|
||||
export const DISABLED_NOTIFICATIONS_URL = "http://-";
|
||||
|
||||
export class DefaultNotificationsService implements NotificationsServiceAbstraction {
|
||||
export class DefaultServerNotificationsService implements ServerNotificationsService {
|
||||
notifications$: Observable<readonly [NotificationResponse, UserId]>;
|
||||
|
||||
private activitySubject = new BehaviorSubject<"active" | "inactive">("active");
|
||||
@@ -55,6 +56,7 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract
|
||||
private readonly signalRConnectionService: SignalRConnectionService,
|
||||
private readonly authService: AuthService,
|
||||
private readonly webPushConnectionService: WebPushConnectionService,
|
||||
private readonly authRequestAnsweringService: AuthRequestAnsweringServiceAbstraction,
|
||||
) {
|
||||
this.notifications$ = this.accountService.activeAccount$.pipe(
|
||||
map((account) => account?.id),
|
||||
@@ -213,6 +215,10 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract
|
||||
await this.syncService.syncDeleteSend(notification.payload as SyncSendNotification);
|
||||
break;
|
||||
case NotificationType.AuthRequest:
|
||||
await this.authRequestAnsweringService.receivedPendingAuthRequest(
|
||||
notification.payload.userId,
|
||||
notification.payload.id,
|
||||
);
|
||||
this.messagingService.send("openLoginApproval", {
|
||||
notificationId: notification.payload.id,
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from "./worker-webpush-connection.service";
|
||||
export * from "./signalr-connection.service";
|
||||
export * from "./default-notifications.service";
|
||||
export * from "./noop-notifications.service";
|
||||
export * from "./default-server-notifications.service";
|
||||
export * from "./unsupported-server-notifications.service";
|
||||
export * from "./unsupported-webpush-connection.service";
|
||||
export * from "./webpush-connection.service";
|
||||
export * from "./websocket-webpush-connection.service";
|
||||
|
||||
@@ -6,7 +6,7 @@ import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { ServerNotificationsService } from "../server-notifications-service";
|
||||
|
||||
export class NoopNotificationsService implements ServerNotificationsService {
|
||||
export class UnsupportedServerNotificationsService implements ServerNotificationsService {
|
||||
notifications$: Observable<readonly [NotificationResponse, UserId]> = new Subject();
|
||||
|
||||
constructor(private logService: LogService) {}
|
||||
@@ -4,7 +4,7 @@ import { NotificationResponse } from "@bitwarden/common/models/response/notifica
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Needed to link to API
|
||||
import type { DefaultNotificationsService } from "./internal";
|
||||
import type { DefaultServerNotificationsService } from "./internal";
|
||||
|
||||
/**
|
||||
* A service offering abilities to interact with push notifications from the server.
|
||||
@@ -13,7 +13,7 @@ export abstract class ServerNotificationsService {
|
||||
/**
|
||||
* @deprecated This method should not be consumed, an observable to listen to server
|
||||
* notifications will be available one day but it is not ready to be consumed generally.
|
||||
* Please add code reacting to notifications in {@link DefaultNotificationsService.processNotification}
|
||||
* Please add code reacting to notifications in {@link DefaultServerNotificationsService.processNotification}
|
||||
*/
|
||||
abstract notifications$: Observable<readonly [NotificationResponse, UserId]>;
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ export class UnsupportedSystemNotificationsService implements SystemNotification
|
||||
throw new Error("Create OS Notification unsupported.");
|
||||
}
|
||||
|
||||
clear(clearInfo: SystemNotificationClearInfo): undefined {
|
||||
clear(clearInfo: SystemNotificationClearInfo): Promise<undefined> {
|
||||
throw new Error("Clear OS Notification unsupported.");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user