diff --git a/public/libs/preferences.js b/public/libs/preferences.js
index 420c3d89..3f20b36c 100755
--- a/public/libs/preferences.js
+++ b/public/libs/preferences.js
@@ -25,6 +25,7 @@ const getDefaultPauseNotificationsByScheduleTo = () => {
};
const defaultPreferences = {
+ allowNodeInJsCodeInjection: false,
allowPrerelease: Boolean(semver.prerelease(app.getVersion())),
askForDownloadPath: true,
attachToMenubar: false,
diff --git a/public/preload/view.js b/public/preload/view.js
index 744aaf50..0df9c26e 100644
--- a/public/preload/view.js
+++ b/public/preload/view.js
@@ -48,15 +48,32 @@ const handleLoaded = (event) => {
});
const jsCodeInjection = ipcRenderer.sendSync('get-preference', 'jsCodeInjection');
+ const allowNodeInJsCodeInjection = ipcRenderer.sendSync('get-preference', 'allowNodeInJsCodeInjection');
const cssCodeInjection = ipcRenderer.sendSync('get-preference', 'cssCodeInjection');
if (jsCodeInjection && jsCodeInjection.trim().length > 0) {
- try {
- const node = document.createElement('script');
- node.innerHTML = jsCodeInjection;
- document.body.appendChild(node);
- } catch (err) {
- console.log(err); // eslint-disable-line no-console
+ if (allowNodeInJsCodeInjection) {
+ try {
+ // eslint-disable-next-line no-new-func
+ Function(
+ 'require',
+ `"use strict";${jsCodeInjection}`,
+ )(require);
+ } catch (err) {
+ /* eslint-disable no-console */
+ console.log(err);
+ /* eslint-enable no-console */
+ }
+ } else {
+ try {
+ const node = document.createElement('script');
+ node.innerHTML = jsCodeInjection;
+ document.body.appendChild(node);
+ } catch (err) {
+ /* eslint-disable no-console */
+ console.log(err);
+ /* eslint-enable no-console */
+ }
}
}
diff --git a/src/components/dialog-code-injection/index.js b/src/components/dialog-code-injection/index.js
index d9bbc94f..c3bdb235 100644
--- a/src/components/dialog-code-injection/index.js
+++ b/src/components/dialog-code-injection/index.js
@@ -2,6 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Switch from '@material-ui/core/Switch';
import AceEditor from 'react-ace';
@@ -29,6 +31,10 @@ const styles = (theme) => ({
actions: {
borderTop: `1px solid ${theme.palette.divider}`,
padding: theme.spacing(2),
+ display: 'flex',
+ },
+ actionsLeft: {
+ flex: 1,
},
button: {
float: 'right',
@@ -36,44 +42,68 @@ const styles = (theme) => ({
},
});
-const getMode = () => {
- const codeInjectionType = window.require('electron').remote.getGlobal('codeInjectionType');
+const getMode = (codeInjectionType) => {
if (codeInjectionType === 'css') return 'css';
if (codeInjectionType === 'js') return 'javascript';
return '';
};
const CodeInjection = ({
+ allowNodeInJsCodeInjection,
classes,
code,
onSave,
onUpdateForm,
shouldUseDarkColors,
-}) => (
-
-
-
onUpdateForm({ code: value })}
- />
+}) => {
+ const codeInjectionType = window.require('electron').remote.getGlobal('codeInjectionType');
+ return (
+
+
+
onUpdateForm({ code: value })}
+ />
+
+
+
+ {codeInjectionType === 'js' && (
+ onUpdateForm({ allowNodeInJsCodeInjection: e.target.checked })}
+ color="primary"
+ />
+ )}
+ label="Allow access to Node.JS & Electron APIs"
+ />
+ )}
+
+
+
+
+
+
-
-
-
-
-
-);
+ );
+};
+
+CodeInjection.defaultProps = {
+ allowNodeInJsCodeInjection: false,
+};
CodeInjection.propTypes = {
+ allowNodeInJsCodeInjection: PropTypes.bool,
classes: PropTypes.object.isRequired,
code: PropTypes.string.isRequired,
onSave: PropTypes.func.isRequired,
@@ -83,6 +113,7 @@ CodeInjection.propTypes = {
const mapStateToProps = (state) => ({
code: state.dialogCodeInjection.form.code || '',
+ allowNodeInJsCodeInjection: state.dialogCodeInjection.form.allowNodeInJsCodeInjection,
shouldUseDarkColors: state.general.shouldUseDarkColors,
});
diff --git a/src/components/dialog-preferences/index.js b/src/components/dialog-preferences/index.js
index 28753391..d5b1272a 100644
--- a/src/components/dialog-preferences/index.js
+++ b/src/components/dialog-preferences/index.js
@@ -170,6 +170,7 @@ const getUpdaterDesc = (status, info) => {
};
const Preferences = ({
+ allowNodeInJsCodeInjection,
allowPrerelease,
askForDownloadPath,
attachToMenubar,
@@ -1018,7 +1019,7 @@ const Preferences = ({
requestShowCodeInjectionWindow('js')}>
-
+
@@ -1233,6 +1234,7 @@ Preferences.defaultProps = {
};
Preferences.propTypes = {
+ allowNodeInJsCodeInjection: PropTypes.bool.isRequired,
allowPrerelease: PropTypes.bool.isRequired,
askForDownloadPath: PropTypes.bool.isRequired,
attachToMenubar: PropTypes.bool.isRequired,
@@ -1275,6 +1277,7 @@ Preferences.propTypes = {
};
const mapStateToProps = (state) => ({
+ allowNodeInJsCodeInjection: state.preferences.allowNodeInJsCodeInjection,
allowPrerelease: state.preferences.allowPrerelease,
askForDownloadPath: state.preferences.askForDownloadPath,
attachToMenubar: state.preferences.attachToMenubar,
diff --git a/src/state/dialog-code-injection/actions.js b/src/state/dialog-code-injection/actions.js
index c35c819c..96277fee 100644
--- a/src/state/dialog-code-injection/actions.js
+++ b/src/state/dialog-code-injection/actions.js
@@ -16,7 +16,11 @@ export const save = () => (dispatch, getState) => {
const { remote } = window.require('electron');
const codeInjectionType = remote.getGlobal('codeInjectionType');
+
requestSetPreference(`${codeInjectionType}CodeInjection`, form.code);
+ if (codeInjectionType === 'js' && typeof form.allowNodeInJsCodeInjection === 'boolean') {
+ requestSetPreference('allowNodeInJsCodeInjection', form.allowNodeInJsCodeInjection);
+ }
requestShowRequireRestartDialog();
diff --git a/src/state/dialog-code-injection/reducers.js b/src/state/dialog-code-injection/reducers.js
index 55aac404..46e5d8a3 100644
--- a/src/state/dialog-code-injection/reducers.js
+++ b/src/state/dialog-code-injection/reducers.js
@@ -10,6 +10,8 @@ const form = (state = {}, action) => {
const codeInjectionType = window.require('electron').remote.getGlobal('codeInjectionType');
return {
code: getPreference(`${codeInjectionType}CodeInjection`),
+ // allowNodeInJsCodeInjection is only used for js injection
+ allowNodeInJsCodeInjection: codeInjectionType === 'js' ? getPreference('allowNodeInJsCodeInjection') : false,
};
}
case UPDATE_CODE_INJECTION_FORM: return { ...state, ...action.changes };