Skip to content

Instantly share code, notes, and snippets.

@george-thomas-hill
Last active October 22, 2022 18:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save george-thomas-hill/c3179e6eddeb1a2715201a20dbf95015 to your computer and use it in GitHub Desktop.
Save george-thomas-hill/c3179e6eddeb1a2715201a20dbf95015 to your computer and use it in GitHub Desktop.
Demonstrates that embedding PDFs using webviews and custom protocols crashes Electron.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-src 'self' customprotocolname: ;">
<link href="./styles.css" rel="stylesheet">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
<h1>See what happens if you load a local .png or a local .pdf into the iframe.</h1>
<button onclick="loadFileIntoIframe()">Load file into iFrame</button>
<br>
<br>
<iframe id="theIframe" src=""></iframe>
<p>For me, embedding these files works correctly. However &hellip;</p>
<h1>See what happens if you load a local .png or local .pdf using a custom protocol.</h1>
<button onclick="loadFileIntoIframeUsingCustomProtocol()">Load file into iFrame using a custom protocol</button>
<br>
<br>
<iframe id="theIframeForCustomProtocol" src=""></iframe>
<p>For me, .png files display correctly, but .pdf files only display as a gray box.</p>
<h1>See what happens if you load a local .png or local .pdf using a custom protocol into a webview.</h1>
<button onclick="loadFileIntoWebviewUsingCustomProtocol()">Load file into webview using a custom protocol</button>
<br>
<br>
<webview id="theWebview" src=""
webpreferences="sandbox=yes, javascript=no, autoplayPolicy=document-user-activation-required">
</webview>
<p>For me, .png files display correctly, but .pdf files crash Electron ("Electron exited with signal SIGTRAP.").</p>
<script src="./renderer.js"></script>
</body>
</html>
const { app, BrowserWindow, dialog, ipcMain, protocol } = require('electron');
const path = require('path');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 1200,
height: 700,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
webviewTag: true,
},
});
mainWindow.loadFile('index.html');
mainWindow.webContents.openDevTools()
}
app.whenReady().then(
() => {
createWindow();
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
}
);
app.on(
'window-all-closed',
function () {
if (process.platform !== 'darwin') app.quit();
}
);
ipcMain.handle("getFilePathFromDialog", handleGetFilePathFromDialog);
async function handleGetFilePathFromDialog(event, desiredOptions) {
const mainWindow = BrowserWindow.fromWebContents(event.sender);
const result = dialog.showOpenDialog(mainWindow, desiredOptions);
return result;
}
// https://github.com/electron/electron/issues/23393
const files = {};
app.whenReady().then(() => {
const protocolName = "customprotocolname";
protocol.registerFileProtocol(
protocolName,
(request, callback) => {
// console.log(`request: ${"v".repeat(60)}`);
// console.log(request);
// console.log(`request: ${"^".repeat(60)}`);
const theUrl = request.url;
const theUrlParts = theUrl.split("/");
const fileIdString = theUrlParts[theUrlParts.length - 1];
const fileId = parseInt(fileIdString, 10);
// console.log("fileId:", fileId);
if (files[fileId]) {
const resolvedPath = files[fileId];
// console.log(`\n\nServing:\n\n` + resolvedPath);
callback(resolvedPath);
} else {
callback(404);
}
});
});
ipcMain.handle(
"serveFile",
(event, filePath) => {
// console.log(event, args);
const id = Math.floor(Math.random() * 1000 * 1000 * 1000);
// console.log(`\n\nSetting id ${id} --> ${filePath}\n\n`);
files[id] = filePath;
return id;
}
);
{
"name": "electron-embed-pdfs",
"productName": "electron-embed-pdfs",
"description": "My Electron application description",
"keywords": [],
"main": "./main.js",
"version": "1.0.0",
"author": "george-thomas-hill",
"scripts": {
"start": "electron ."
},
"dependencies": {},
"devDependencies": {
"electron": "21.2.0"
}
}
window.addEventListener(
'DOMContentLoaded',
() => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector);
if (element) element.innerText = text;
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type]);
}
}
);
// import { ipcRenderer, contextBridge } from "electron";
const { ipcRenderer, contextBridge } = require("electron");
contextBridge.exposeInMainWorld(
"electron",
{
ipcApi: {
getFilePathFromDialog(parametersObject) {
const resultObject =
ipcRenderer.invoke("getFilePathFromDialog", parametersObject);
return resultObject;
},
askForFileToBeServed(desiredPath) {
const theId = ipcRenderer.invoke("serveFile", desiredPath);
return theId;
},
},
}
);
async function loadFileIntoIframe() {
const theResult =
await window.electron.ipcApi.getFilePathFromDialog({
title: "Choose a File to Embed",
buttonLabel: "Embed This File",
message: "Please select the file that you want to embed.",
properties: [
"showHiddenFiles",
],
});
console.log(theResult);
if (theResult.canceled === false) {
const theIframe = document.getElementById("theIframe");
theIframe.src = `file://${theResult.filePaths[0]}`;
}
}
async function loadFileIntoIframeUsingCustomProtocol() {
const theResult =
await window.electron.ipcApi.getFilePathFromDialog({
title: "Choose a File to Embed Using a Custom Protocol",
buttonLabel: "Embed This File",
message: "Please select the file that you want to embed using a custom protocol.",
properties: [
"showHiddenFiles",
],
});
console.log(theResult);
if (theResult.canceled === false) {
const thePromise = window.electron.ipcApi.askForFileToBeServed(theResult.filePaths[0]);
thePromise.then(processTheResult);
function processTheResult(result) {
console.log(result);
const theIframe = document.getElementById("theIframeForCustomProtocol");
theIframe.src = `customprotocolname://secretString/${result}`;
}
};
}
async function loadFileIntoWebviewUsingCustomProtocol() {
const theResult =
await window.electron.ipcApi.getFilePathFromDialog({
title: "Choose a File to Embed Using a Custom Protocol",
buttonLabel: "Embed This File",
message: "Please select the file that you want to embed using a custom protocol.",
properties: [
"showHiddenFiles",
],
});
console.log(theResult);
if (theResult.canceled === false) {
const thePromise = window.electron.ipcApi.askForFileToBeServed(theResult.filePaths[0]);
thePromise.then(processTheResult);
function processTheResult(result) {
console.log(result);
const theWebview = document.getElementById("theWebview");
theWebview.src = `customprotocolname://secretString/${result}`;
}
};
}
/* No styles! */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment