mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Electron: Fixed security issue by enabling contextIsolation and proxying IPC messages via preload script
This commit is contained in:
parent
0a2b83998c
commit
72af564382
@ -1404,6 +1404,7 @@ class NoteTextComponent extends React.Component {
|
||||
style={viewerStyle}
|
||||
preload="gui/note-viewer/preload.js"
|
||||
src="gui/note-viewer/index.html"
|
||||
webpreferences="contextIsolation"
|
||||
ref={(elem) => { this.webview_ref(elem); } }
|
||||
/>
|
||||
|
||||
|
@ -36,6 +36,22 @@
|
||||
<script>
|
||||
const contentElement = document.getElementById('content');
|
||||
|
||||
const ipc = {};
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
// Here we only deal with messages that are sent from the main Electro process to the webview.
|
||||
if (!event.data || event.data.target !== 'webview') return;
|
||||
|
||||
const callName = event.data.name;
|
||||
const callData = event.data.data;
|
||||
|
||||
if (!ipc[callName]) {
|
||||
console.warn('Missing IPC function:', event.data);
|
||||
} else {
|
||||
ipc[callName](callData);
|
||||
}
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Handle dynamically loading HLJS when a code element is present
|
||||
// ----------------------------------------------------------------------
|
||||
@ -119,7 +135,9 @@
|
||||
setPercentScroll(percentScroll_);
|
||||
}
|
||||
|
||||
ipcRenderer.on('setHtml', (event, html) => {
|
||||
ipc.setHtml = (event) => {
|
||||
const html = event.html;
|
||||
|
||||
updateBodyHeight();
|
||||
|
||||
contentElement.innerHTML = html;
|
||||
@ -158,10 +176,12 @@
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let ignoreNextScrollEvent = false;
|
||||
ipcRenderer.on('setPercentScroll', (event, percent) => {
|
||||
ipc.setPercentScroll = (event) => {
|
||||
const percent = event.percent;
|
||||
|
||||
if (checkScrollIID_) {
|
||||
clearInterval(checkScrollIID_);
|
||||
checkScrollIID_ = null;
|
||||
@ -169,7 +189,7 @@
|
||||
|
||||
ignoreNextScrollEvent = true;
|
||||
setPercentScroll(percent);
|
||||
});
|
||||
}
|
||||
|
||||
let mark_ = null;
|
||||
function setMarkers(keywords) {
|
||||
@ -184,7 +204,9 @@
|
||||
}
|
||||
|
||||
let markLoaded_ = false;
|
||||
ipcRenderer.on('setMarkers', (event, keywords) => {
|
||||
ipc.setMarkers = (event) => {
|
||||
const keywords = event.keywords;
|
||||
|
||||
if (!keywords.length && !markLoaded_) return;
|
||||
|
||||
if (!markLoaded_) {
|
||||
@ -199,7 +221,7 @@
|
||||
} else {
|
||||
setMarkers(keywords);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function maxScrollTop() {
|
||||
return Math.max(0, contentElement.scrollHeight - contentElement.clientHeight);
|
||||
@ -210,6 +232,10 @@
|
||||
document.getElementById('body').style.height = window.innerHeight + 'px';
|
||||
}
|
||||
|
||||
const ipcProxySendToHost = (methodName, arg) => {
|
||||
window.postMessage({ target: 'main', name: methodName, args: [ arg ] }, '*');
|
||||
}
|
||||
|
||||
contentElement.addEventListener('scroll', function(e) {
|
||||
if (ignoreNextScrollEvent) {
|
||||
ignoreNextScrollEvent = false;
|
||||
@ -218,7 +244,8 @@
|
||||
const m = maxScrollTop();
|
||||
const percent = m ? contentElement.scrollTop / m : 0;
|
||||
setPercentScroll(percent);
|
||||
ipcRenderer.sendToHost('percentScroll', percent);
|
||||
|
||||
ipcProxySendToHost('percentScroll', percent);
|
||||
});
|
||||
|
||||
document.addEventListener('contextmenu', function(event) {
|
||||
@ -228,7 +255,7 @@
|
||||
if (element && !element.getAttribute('data-resource-id')) element = element.parentElement;
|
||||
|
||||
if (element && element.getAttribute('data-resource-id')) {
|
||||
ipcRenderer.sendToHost('contextMenu', {
|
||||
ipcProxySendToHost('contextMenu', {
|
||||
type: element.getAttribute('src') ? 'image' : 'resource',
|
||||
resourceId: element.getAttribute('data-resource-id'),
|
||||
});
|
||||
@ -236,12 +263,12 @@
|
||||
const selectedText = window.getSelection().toString();
|
||||
|
||||
if (selectedText) {
|
||||
ipcRenderer.sendToHost('contextMenu', {
|
||||
ipcProxySendToHost('contextMenu', {
|
||||
type: 'text',
|
||||
textToCopy: selectedText,
|
||||
});
|
||||
} else if (event.target.getAttribute('href')) {
|
||||
ipcRenderer.sendToHost('contextMenu', {
|
||||
ipcProxySendToHost('contextMenu', {
|
||||
type: 'link',
|
||||
textToCopy: event.target.getAttribute('href'),
|
||||
});
|
||||
|
@ -1,4 +1,36 @@
|
||||
// Define here Electron objects that need to be accessed from the WebView
|
||||
// https://github.com/electron/electron/blob/master/docs/tutorial/security.md#2-disable-nodejs-integration-for-remote-content
|
||||
// In order to give access to the webview to certain functions of the main process, we need
|
||||
// this bridge which listens from the main process and sends to the webview and the other
|
||||
// way around. This is necessary after having enabled the "contextIsolation" option, which
|
||||
// prevents the webview from accessing low-level methods in the main process.
|
||||
|
||||
window.ipcRenderer = require('electron').ipcRenderer;
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
|
||||
ipcRenderer.on('setHtml', (event, html) => {
|
||||
window.postMessage({ target: 'webview', name: 'setHtml', data: { html: html } }, '*');
|
||||
});
|
||||
|
||||
ipcRenderer.on('setPercentScroll', (event, percent) => {
|
||||
window.postMessage({ target: 'webview', name: 'setPercentScroll', data: { percent: percent } }, '*');
|
||||
});
|
||||
|
||||
ipcRenderer.on('setMarkers', (event, keywords) => {
|
||||
window.postMessage({ target: 'webview', name: 'setMarkers', data: { keywords: keywords } }, '*');
|
||||
});
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
// Here we only deal with messages that are sent from the webview to the main Electron process
|
||||
if (!event.data || event.data.target !== 'main') return;
|
||||
|
||||
const callName = event.data.name;
|
||||
const args = event.data.args;
|
||||
|
||||
if (args.length === 0) {
|
||||
ipcRenderer.sendToHost(callName);
|
||||
} else if (args.length === 1) {
|
||||
ipcRenderer.sendToHost(callName, args[0]);
|
||||
} else if (args.length === 2) {
|
||||
ipcRenderer.sendToHost(callName, args[1]);
|
||||
} else {
|
||||
throw new Error('Unsupported number of args');
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue
Block a user