mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 03:33:30 +00:00
feat(notification-processing): [PM-19877] System Notification Implementation - Trying to have the notification present to prompt the browser extension to popup
This commit is contained in:
@@ -19,6 +19,11 @@
|
||||
"build:prod:firefox": "cross-env NODE_ENV=production npm run build:firefox",
|
||||
"build:prod:opera": "cross-env NODE_ENV=production npm run build:opera",
|
||||
"build:prod:safari": "cross-env NODE_ENV=production npm run build:safari",
|
||||
"build:nonprod:chrome": "cross-env npm run build:chrome",
|
||||
"build:nonprod:edge": "cross-env npm run build:edge",
|
||||
"build:nonprod:firefox": "cross-env npm run build:firefox",
|
||||
"build:nonprod:opera": "cross-env npm run build:opera",
|
||||
"build:nonprod:safari": "cross-env npm run build:safari",
|
||||
"dist:chrome": "npm run build:prod:chrome && mkdir -p dist && ./scripts/compress.sh dist-chrome.zip",
|
||||
"dist:edge": "npm run build:prod:edge && mkdir -p dist && ./scripts/compress.sh dist-edge.zip",
|
||||
"dist:firefox": "npm run build:prod:firefox && mkdir -p dist && ./scripts/compress.sh dist-firefox.zip",
|
||||
@@ -27,6 +32,15 @@
|
||||
"dist:firefox:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:firefox",
|
||||
"dist:opera:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:opera",
|
||||
"dist:safari:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:safari",
|
||||
"dist:chrome:nonprod": "npm run build:nonprod:chrome && mkdir -p dist && ./scripts/compress.sh dist-chrome.zip",
|
||||
"dist:edge:nonprod": "npm run build:nonprod:edge && mkdir -p dist && ./scripts/compress.sh dist-edge.zip",
|
||||
"dist:firefox:nonprod": "npm run build:nonprod:firefox && mkdir -p dist && ./scripts/compress.sh dist-firefox.zip",
|
||||
"dist:opera:nonprod": "npm run build:nonprod:opera && mkdir -p dist && ./scripts/compress.sh dist-opera.zip",
|
||||
"dist:safari:nonprod": "npm run build:nonprod:safari && ./scripts/package-safari.ps1",
|
||||
"dist:edge:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:edge:nonprod",
|
||||
"dist:firefox:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:firefox:nonprod",
|
||||
"dist:opera:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:opera:nonprod",
|
||||
"dist:safari:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:safari:nonprod",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:watch:all": "jest --watchAll",
|
||||
|
||||
@@ -130,8 +130,11 @@ import {
|
||||
WebPushNotificationsApiService,
|
||||
WorkerWebPushConnectionService,
|
||||
} from "@bitwarden/common/platform/notifications/internal";
|
||||
import { SystemNotificationService } from "@bitwarden/common/platform/notifications/system-notification-service";
|
||||
import { UnsupportedSystemNotificationService } from "@bitwarden/common/platform/notifications/unsupported-system-notification.service";
|
||||
import {
|
||||
ButtonActions,
|
||||
SystemNotificationsService,
|
||||
} from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import { UnsupportedSystemNotificationsService } from "@bitwarden/common/platform/notifications/unsupported-system-notifications.service";
|
||||
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
|
||||
import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service";
|
||||
import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service";
|
||||
@@ -347,7 +350,7 @@ export default class MainBackground {
|
||||
exportService: VaultExportServiceAbstraction;
|
||||
searchService: SearchServiceAbstraction;
|
||||
notificationsService: ServerNotificationsService;
|
||||
systemNotificationService: SystemNotificationService;
|
||||
systemNotificationService: SystemNotificationsService;
|
||||
actionsService: ActionsService;
|
||||
stateService: StateServiceAbstraction;
|
||||
userNotificationSettingsService: UserNotificationSettingsServiceAbstraction;
|
||||
@@ -1129,7 +1132,9 @@ export default class MainBackground {
|
||||
this.webPushConnectionService = new UnsupportedWebPushConnectionService();
|
||||
}
|
||||
|
||||
this.actionsService = new BrowserActionsService(this.platformUtilsService);
|
||||
this.logService.info(`The background service is registered as ${navigator.userAgent}`);
|
||||
|
||||
this.actionsService = new BrowserActionsService(this.logService, this.platformUtilsService);
|
||||
|
||||
const userAgent = navigator.userAgent;
|
||||
|
||||
@@ -1144,9 +1149,23 @@ export default class MainBackground {
|
||||
this.platformUtilsService,
|
||||
);
|
||||
} else {
|
||||
this.systemNotificationService = new UnsupportedSystemNotificationService();
|
||||
this.systemNotificationService = new UnsupportedSystemNotificationsService();
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
await this.systemNotificationService.create({
|
||||
id: Math.random() * 100000 + "",
|
||||
type: ButtonActions.AuthRequestNotification,
|
||||
title: "Test Notification",
|
||||
body: "Body",
|
||||
buttons: [
|
||||
{
|
||||
title: "First Button",
|
||||
},
|
||||
],
|
||||
});
|
||||
}, 1);
|
||||
|
||||
this.notificationsService = new DefaultNotificationsService(
|
||||
this.logService,
|
||||
this.syncService,
|
||||
@@ -1158,6 +1177,7 @@ export default class MainBackground {
|
||||
new SignalRConnectionService(this.apiService, this.logService),
|
||||
this.authService,
|
||||
this.webPushConnectionService,
|
||||
this.systemNotificationService,
|
||||
this.actionsService,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,31 +1,44 @@
|
||||
import { DeviceType } from "@bitwarden/common/enums";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ActionsService } from "@bitwarden/common/platform/actions/actions-service";
|
||||
import { LogService } from "@bitwarden/logging";
|
||||
|
||||
import { SafariApp } from "../../browser/safariApp";
|
||||
import { BrowserApi } from "../browser/browser-api";
|
||||
|
||||
export class BrowserActionsService implements ActionsService {
|
||||
constructor(private platformUtilsService: PlatformUtilsService) {}
|
||||
constructor(
|
||||
private logService: LogService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
) {}
|
||||
|
||||
async openPopup(): Promise<void> {
|
||||
switch (this.platformUtilsService.getDevice()) {
|
||||
case DeviceType.ChromeBrowser:
|
||||
const deviceType = this.platformUtilsService.getDevice();
|
||||
|
||||
switch (deviceType) {
|
||||
case DeviceType.FirefoxExtension:
|
||||
case DeviceType.ChromeExtension: {
|
||||
const browserAction = BrowserApi.getBrowserAction();
|
||||
|
||||
// We might get back mv2 or mv3 browserAction, only mv3 supports the openPopup function,
|
||||
// so check for that function existing.
|
||||
if ("openPopup" in browserAction && typeof browserAction.openPopup === "function") {
|
||||
await browserAction.openPopup();
|
||||
return;
|
||||
} else {
|
||||
this.logService.warning(
|
||||
`No openPopup function found on browser actions. On browser: ${deviceType} and manifest version: ${BrowserApi.manifestVersion}`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeviceType.SafariBrowser:
|
||||
case DeviceType.SafariExtension:
|
||||
break;
|
||||
await SafariApp.sendMessageToApp("showPopover", null, true);
|
||||
return;
|
||||
default:
|
||||
this.logService.warning(
|
||||
`Tried to open the popup from an unsupported device type: ${deviceType}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
openPopupToUrl(url: string): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import {
|
||||
SystemNotificationClearInfo,
|
||||
SystemNotificationCreateInfo,
|
||||
SystemNotificationEvent,
|
||||
SystemNotificationService,
|
||||
} from "@bitwarden/common/platform/notifications/system-notification-service";
|
||||
SystemNotificationsService,
|
||||
} from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
|
||||
export class ChromeExtensionSystemNotificationService implements SystemNotificationService {
|
||||
export class ChromeExtensionSystemNotificationService implements SystemNotificationsService {
|
||||
private systemNotificationClickedSubject = new Subject<SystemNotificationEvent>();
|
||||
notificationClicked$: Observable<SystemNotificationEvent>;
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ import { Message, MessageListener, MessageSender } from "@bitwarden/common/platf
|
||||
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
|
||||
import { flagEnabled } from "@bitwarden/common/platform/misc/flags";
|
||||
import { ServerNotificationsService } from "@bitwarden/common/platform/notifications";
|
||||
import { SystemNotificationService } from "@bitwarden/common/platform/notifications/system-notification-service";
|
||||
import { SystemNotificationsService } from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling";
|
||||
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||
@@ -257,7 +257,7 @@ const safeProviders: SafeProvider[] = [
|
||||
safeProvider({
|
||||
provide: ActionsService,
|
||||
useClass: BrowserActionsService,
|
||||
deps: [PlatformUtilsServiceAbstraction],
|
||||
deps: [LogService, PlatformUtilsServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: KeyService,
|
||||
@@ -616,7 +616,7 @@ const safeProviders: SafeProvider[] = [
|
||||
deps: [],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: SystemNotificationService,
|
||||
provide: SystemNotificationsService,
|
||||
useClass: ChromeExtensionSystemNotificationService,
|
||||
deps: [LogService, PlatformUtilsServiceAbstraction],
|
||||
}),
|
||||
|
||||
@@ -217,6 +217,7 @@ import {
|
||||
WebPushConnectionService,
|
||||
WebPushNotificationsApiService,
|
||||
} from "@bitwarden/common/platform/notifications/internal";
|
||||
import { SystemNotificationsService } from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
import {
|
||||
DefaultTaskSchedulerService,
|
||||
TaskSchedulerService,
|
||||
@@ -967,6 +968,7 @@ const safeProviders: SafeProvider[] = [
|
||||
SignalRConnectionService,
|
||||
AuthServiceAbstraction,
|
||||
WebPushConnectionService,
|
||||
SystemNotificationsService,
|
||||
ActionsService,
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -3,13 +3,4 @@ export abstract class ActionsService {
|
||||
* Opens the popup.
|
||||
*/
|
||||
abstract openPopup(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Opens the popup and navigates to a url.
|
||||
*
|
||||
* Stubbed for now.
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
abstract openPopupToUrl(url: string): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,4 @@ export class UnsupportedActionsService implements ActionsService {
|
||||
openPopup(): Promise<void> {
|
||||
throw new Error("Open Popup unsupported.");
|
||||
}
|
||||
|
||||
openPopupToUrl(url: string): Promise<void> {
|
||||
throw new Error("Open Popup to Url unsupported.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@ import {
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { LogoutReason } from "@bitwarden/auth/common";
|
||||
import { ActionsService } from "@bitwarden/common/platform/actions";
|
||||
import {
|
||||
ButtonActions,
|
||||
SystemNotificationEvent,
|
||||
SystemNotificationsService,
|
||||
} from "@bitwarden/common/platform/notifications/system-notifications-service";
|
||||
|
||||
import { AccountService } from "../../../auth/abstractions/account.service";
|
||||
import { AuthService } from "../../../auth/abstractions/auth.service";
|
||||
@@ -56,8 +61,20 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract
|
||||
private readonly signalRConnectionService: SignalRConnectionService,
|
||||
private readonly authService: AuthService,
|
||||
private readonly webPushConnectionService: WebPushConnectionService,
|
||||
private readonly actionsService: ActionsService,
|
||||
private readonly systemNotificationService: SystemNotificationsService,
|
||||
private readonly actionService: ActionsService,
|
||||
) {
|
||||
this.systemNotificationService.notificationClicked$
|
||||
.pipe(
|
||||
map(async (value: SystemNotificationEvent) => {
|
||||
switch (value.type) {
|
||||
case ButtonActions.AuthRequestNotification:
|
||||
await this.actionService.openPopup();
|
||||
}
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
this.notifications$ = this.accountService.activeAccount$.pipe(
|
||||
map((account) => account?.id),
|
||||
distinctUntilChanged(),
|
||||
@@ -215,7 +232,6 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract
|
||||
await this.syncService.syncDeleteSend(notification.payload as SyncSendNotification);
|
||||
break;
|
||||
case NotificationType.AuthRequest:
|
||||
await this.actionsService.openPopup();
|
||||
this.messagingService.send("openLoginApproval", {
|
||||
notificationId: notification.payload.id,
|
||||
});
|
||||
|
||||
@@ -35,11 +35,11 @@ export type SystemNotificationClearInfo = {
|
||||
|
||||
export type SystemNotificationEvent = {
|
||||
id: string;
|
||||
type: string;
|
||||
type: ButtonActionsKeys;
|
||||
buttonIdentifier: number;
|
||||
};
|
||||
|
||||
export abstract class SystemNotificationService {
|
||||
export abstract class SystemNotificationsService {
|
||||
abstract notificationClicked$: Observable<SystemNotificationEvent>;
|
||||
abstract create(createInfo: SystemNotificationCreateInfo): Promise<undefined>;
|
||||
abstract clear(clearInfo: SystemNotificationClearInfo): undefined;
|
||||
@@ -4,10 +4,10 @@ import {
|
||||
SystemNotificationClearInfo,
|
||||
SystemNotificationCreateInfo,
|
||||
SystemNotificationEvent,
|
||||
SystemNotificationService,
|
||||
} from "./system-notification-service";
|
||||
SystemNotificationsService,
|
||||
} from "./system-notifications-service";
|
||||
|
||||
export class UnsupportedSystemNotificationService implements SystemNotificationService {
|
||||
export class UnsupportedSystemNotificationsService implements SystemNotificationsService {
|
||||
private systemNotificationClickedSubject = new Subject<SystemNotificationEvent>();
|
||||
notificationClicked$ = throwError(() => new Error("Notification clicked is not supported."));
|
||||
|
||||
Reference in New Issue
Block a user