diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 7906190e2be..68d2cc0f87f 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -19,8 +19,10 @@ "postinstall": "electron-rebuild", "start": "cross-env ELECTRON_IS_DEV=0 ELECTRON_NO_UPDATER=1 electron ./build", "build-native": "cd desktop_native && npm run build", - "build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"", + "build": "concurrently -n Main,Rend,Prel -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\" \"npm run build:preload\"", "build:dev": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main:dev\" \"npm run build:renderer:dev\"", + "build:preload": "cross-env NODE_ENV=production webpack --config webpack.preload.js", + "build:preload:watch": "cross-env NODE_ENV=production webpack --config webpack.preload.js --watch", "build:main": "cross-env NODE_ENV=production webpack --config webpack.main.js", "build:main:dev": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.main.js", "build:main:watch": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.main.js --watch", diff --git a/apps/desktop/scripts/start.js b/apps/desktop/scripts/start.js index 19b11125061..388bf09405c 100644 --- a/apps/desktop/scripts/start.js +++ b/apps/desktop/scripts/start.js @@ -13,6 +13,11 @@ concurrently( command: "npm run build:main:watch", prefixColor: "yellow", }, + { + name: "Prel", + command: "npm run build:preload:watch", + prefixColor: "magenta", + }, { name: "Rend", command: "npm run build:renderer:watch", diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index 7ccf4aca770..a2a9e71a32b 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -21,7 +21,6 @@ import { DialogService } from "@bitwarden/components"; import { flagEnabled } from "../../platform/flags"; import { ElectronStateService } from "../../platform/services/electron-state.service.abstraction"; -import { isWindowsStore } from "../../utils"; import { SetPinComponent } from "../components/set-pin.component"; @Component({ selector: "app-settings", @@ -589,7 +588,7 @@ export class SettingsComponent implements OnInit { this.form.controls.enableBrowserIntegration.setValue(false); return; - } else if (isWindowsStore()) { + } else if (ipc.platform.isWindowsStore) { await this.dialogService.openSimpleDialog({ title: { key: "browserIntegrationUnsupportedTitle" }, content: { key: "browserIntegrationWindowsStoreDesc" }, diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 34262c3a309..65ac83b59fd 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -10,7 +10,6 @@ import { } from "@angular/core"; import { DomSanitizer } from "@angular/platform-browser"; import { Router } from "@angular/router"; -import { ipcRenderer } from "electron"; import { IndividualConfig, ToastrService } from "ngx-toastr"; import { firstValueFrom, Subject, takeUntil } from "rxjs"; @@ -227,7 +226,7 @@ export class AppComponent implements OnInit, OnDestroy { this.systemService.cancelProcessReload(); break; case "reloadProcess": - ipcRenderer.send("reload-process"); + ipc.platform.reloadProcess(); break; case "syncStarted": break; diff --git a/apps/desktop/src/app/main.ts b/apps/desktop/src/app/main.ts index 7d99e48ea22..c22d4eb9e10 100644 --- a/apps/desktop/src/app/main.ts +++ b/apps/desktop/src/app/main.ts @@ -1,8 +1,12 @@ import { enableProdMode } from "@angular/core"; import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; +import { ipc } from "../preload"; import { isDev } from "../utils"; +// Temporary polyfill for preload script +(window as any).ipc = ipc; + require("../scss/styles.scss"); require("../scss/tailwind.css"); diff --git a/apps/desktop/src/global.d.ts b/apps/desktop/src/global.d.ts index 1b85bb1b6b1..4d103b2cdef 100644 --- a/apps/desktop/src/global.d.ts +++ b/apps/desktop/src/global.d.ts @@ -1 +1,2 @@ declare module "forcefocus"; +declare const ipc: typeof import("./preload").ipc; diff --git a/apps/desktop/src/main/window.main.ts b/apps/desktop/src/main/window.main.ts index 4ea28c74c5f..e326b9e9e1d 100644 --- a/apps/desktop/src/main/window.main.ts +++ b/apps/desktop/src/main/window.main.ts @@ -143,6 +143,7 @@ export class WindowMain { backgroundColor: await this.getBackgroundColor(), alwaysOnTop: this.enableAlwaysOnTop, webPreferences: { + // preload: path.join(__dirname, "preload.js"), spellcheck: false, nodeIntegration: true, backgroundThrottling: false, diff --git a/apps/desktop/src/platform/preload.ts b/apps/desktop/src/platform/preload.ts new file mode 100644 index 00000000000..b8aed8f65d1 --- /dev/null +++ b/apps/desktop/src/platform/preload.ts @@ -0,0 +1,26 @@ +import { ipcRenderer } from "electron"; + +import { DeviceType } from "@bitwarden/common/enums/device-type.enum"; + +import { isDev, isWindowsStore } from "../utils"; + +export default { + versions: { + app: (): Promise => ipcRenderer.invoke("appVersion"), + }, + deviceType: deviceType(), + isDev: isDev(), + isWindowsStore: isWindowsStore(), + reloadProcess: () => ipcRenderer.send("reload-process"), +}; + +function deviceType(): DeviceType { + switch (process.platform) { + case "win32": + return DeviceType.WindowsDesktop; + case "darwin": + return DeviceType.MacOsDesktop; + default: + return DeviceType.LinuxDesktop; + } +} diff --git a/apps/desktop/src/platform/services/electron-platform-utils.service.ts b/apps/desktop/src/platform/services/electron-platform-utils.service.ts index dbc35de9311..6c99507b12b 100644 --- a/apps/desktop/src/platform/services/electron-platform-utils.service.ts +++ b/apps/desktop/src/platform/services/electron-platform-utils.service.ts @@ -9,31 +9,14 @@ import { } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { BiometricMessage, BiometricStorageAction } from "../../types/biometric-message"; -import { isDev, isMacAppStore } from "../../utils"; +import { isMacAppStore } from "../../utils"; import { ClipboardWriteMessage } from "../types/clipboard"; export class ElectronPlatformUtilsService implements PlatformUtilsService { - private deviceCache: DeviceType = null; - constructor(protected i18nService: I18nService, private messagingService: MessagingService) {} getDevice(): DeviceType { - if (!this.deviceCache) { - switch (process.platform) { - case "win32": - this.deviceCache = DeviceType.WindowsDesktop; - break; - case "darwin": - this.deviceCache = DeviceType.MacOsDesktop; - break; - case "linux": - default: - this.deviceCache = DeviceType.LinuxDesktop; - break; - } - } - - return this.deviceCache; + return ipc.platform.deviceType; } getDeviceString(): string { @@ -82,7 +65,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService { } getApplicationVersion(): Promise { - return ipcRenderer.invoke("appVersion"); + return ipc.platform.versions.app(); } async getApplicationVersionNumber(): Promise { @@ -92,7 +75,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService { // Temporarily restricted to only Windows until https://github.com/electron/electron/pull/28349 // has been merged and an updated electron build is available. supportsWebAuthn(win: Window): boolean { - return process.platform === "win32"; + return this.getDevice() === DeviceType.WindowsDesktop; } supportsDuo(): boolean { @@ -114,7 +97,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService { } isDev(): boolean { - return isDev(); + return ipc.platform.isDev; } isSelfHost(): boolean { diff --git a/apps/desktop/src/preload.ts b/apps/desktop/src/preload.ts new file mode 100644 index 00000000000..a6ddfdefca5 --- /dev/null +++ b/apps/desktop/src/preload.ts @@ -0,0 +1,19 @@ +// import { contextBridge } from "electron"; +import platform from "./platform/preload"; + +/** + * Bitwarden Preload script. + * + * This file contains the "glue" between the main process and the renderer process. Please ensure + * that you have read through the following articles before modifying any preload script. + * + * https://www.electronjs.org/docs/latest/tutorial/tutorial-preload + * https://www.electronjs.org/docs/latest/api/context-bridge + */ + +// Each team owns a subspace of the `ipc` global variable in the renderer. +export const ipc = { + platform, +}; + +// contextBridge.exposeInMainWorld("ipc", ipc); diff --git a/apps/desktop/webpack.main.js b/apps/desktop/webpack.main.js index efd1de20d13..59e043fa12e 100644 --- a/apps/desktop/webpack.main.js +++ b/apps/desktop/webpack.main.js @@ -67,7 +67,6 @@ const main = { ], }, plugins: [ - new CleanWebpackPlugin(), new CopyWebpackPlugin({ patterns: [ "./src/package.json", diff --git a/apps/desktop/webpack.preload.js b/apps/desktop/webpack.preload.js new file mode 100644 index 00000000000..721d0567ca4 --- /dev/null +++ b/apps/desktop/webpack.preload.js @@ -0,0 +1,63 @@ +const path = require("path"); +const { merge } = require("webpack-merge"); +const CopyWebpackPlugin = require("copy-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); +const configurator = require("./config/config"); +const { EnvironmentPlugin } = require("webpack"); + +const NODE_ENV = process.env.NODE_ENV == null ? "development" : process.env.NODE_ENV; + +console.log("Preload process config"); +const envConfig = configurator.load(NODE_ENV); +configurator.log(envConfig); + +const common = { + module: { + rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules\/(?!(@bitwarden)\/).*/, + }, + ], + }, + plugins: [], + resolve: { + extensions: [".tsx", ".ts", ".js"], + plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })], + }, +}; + +const prod = { + output: { + filename: "[name].js", + path: path.resolve(__dirname, "build"), + }, +}; + +const dev = { + output: { + filename: "[name].js", + path: path.resolve(__dirname, "build"), + devtoolModuleFilenameTemplate: "[absolute-resource-path]", + }, + devtool: "cheap-source-map", +}; + +const main = { + mode: NODE_ENV, + target: "electron-preload", + node: { + __dirname: false, + __filename: false, + }, + entry: { + preload: "./src/preload.ts", + }, + optimization: { + minimize: false, + }, +}; + +module.exports = merge(common, NODE_ENV === "development" ? dev : prod, main); diff --git a/apps/desktop/webpack.renderer.js b/apps/desktop/webpack.renderer.js index 64eef5729f6..ea1c350c389 100644 --- a/apps/desktop/webpack.renderer.js +++ b/apps/desktop/webpack.renderer.js @@ -62,6 +62,8 @@ const common = { const renderer = { mode: NODE_ENV, devtool: "source-map", + // TODO: Replace this with web. + // target: "web", target: "electron-renderer", node: { __dirname: false,