1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-06-25 10:25:36 +02:00

[PM-3996] Scaffolding for preload script (#6065)

This PR wires up a polyfill for window.ipc which allows us to progressively migrate the codebase to a format which supports context bridge. This avoids a big bang effort where every non sandboxed call has to be migrated before we can run the code.

Once all calls to node modules are removed from the renderer and only exists in preload.ts. We will turn on context isolation and use the context bridge for communication instead.
This commit is contained in:
Oscar Hinton 2023-10-12 11:50:17 +02:00 committed by GitHub
parent 77d7813742
commit 7cfa38e344
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 131 additions and 28 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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" },

View File

@ -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;

View File

@ -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");

View File

@ -1 +1,2 @@
declare module "forcefocus";
declare const ipc: typeof import("./preload").ipc;

View File

@ -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,

View File

@ -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<string> => 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;
}
}

View File

@ -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<string> {
return ipcRenderer.invoke("appVersion");
return ipc.platform.versions.app();
}
async getApplicationVersionNumber(): Promise<string> {
@ -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 {

View File

@ -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);

View File

@ -67,7 +67,6 @@ const main = {
],
},
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
"./src/package.json",

View File

@ -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);

View File

@ -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,