2019-07-01 23:00:17 +00:00
|
|
|
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
|
const electron_1 = require("electron");
|
|
|
|
const ipc_renderer_internal_utils_1 = require("@electron/internal/renderer/ipc-renderer-internal-utils");
|
|
|
|
let shouldLog = null;
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* This method checks if a security message should be logged.
|
|
|
|
* It does so by determining whether we're running as Electron,
|
|
|
|
* which indicates that a developer is currently looking at the
|
|
|
|
* app.
|
|
|
|
*
|
|
|
|
* @returns {boolean} - Should we log?
|
|
|
|
*/
|
|
|
|
const shouldLogSecurityWarnings = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (shouldLog !== null) {
|
|
|
|
return shouldLog;
|
|
|
|
}
|
|
|
|
const { platform, execPath, env } = process;
|
|
|
|
switch (platform) {
|
|
|
|
case 'darwin':
|
|
|
|
shouldLog = execPath.endsWith('MacOS/Electron') ||
|
|
|
|
execPath.includes('Electron.app/Contents/Frameworks/');
|
|
|
|
break;
|
|
|
|
case 'freebsd':
|
|
|
|
case 'linux':
|
|
|
|
shouldLog = execPath.endsWith('/electron');
|
|
|
|
break;
|
|
|
|
case 'win32':
|
|
|
|
shouldLog = execPath.endsWith('\\electron.exe');
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
shouldLog = false;
|
|
|
|
}
|
|
|
|
if ((env && env.ELECTRON_DISABLE_SECURITY_WARNINGS) ||
|
|
|
|
(window && window.ELECTRON_DISABLE_SECURITY_WARNINGS)) {
|
|
|
|
shouldLog = false;
|
|
|
|
}
|
|
|
|
if ((env && env.ELECTRON_ENABLE_SECURITY_WARNINGS) ||
|
|
|
|
(window && window.ELECTRON_ENABLE_SECURITY_WARNINGS)) {
|
|
|
|
shouldLog = true;
|
|
|
|
}
|
|
|
|
return shouldLog;
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* Checks if the current window is remote.
|
|
|
|
*
|
|
|
|
* @returns {boolean} - Is this a remote protocol?
|
|
|
|
*/
|
|
|
|
const getIsRemoteProtocol = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (window && window.location && window.location.protocol) {
|
|
|
|
return /^(http|ftp)s?/gi.test(window.location.protocol);
|
|
|
|
}
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* Tries to determine whether a CSP without `unsafe-eval` is set.
|
|
|
|
*
|
|
|
|
* @returns {boolean} Is a CSP with `unsafe-eval` set?
|
|
|
|
*/
|
|
|
|
const isUnsafeEvalEnabled = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
return electron_1.webFrame.executeJavaScript(`(${(() => {
|
|
|
|
try {
|
|
|
|
new Function(''); // eslint-disable-line no-new,no-new-func
|
|
|
|
}
|
|
|
|
catch (_a) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}).toString()})()`, false);
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
const moreInformation = `\nFor more information and help, consult
|
|
|
|
https://electronjs.org/docs/tutorial/security.\n This warning will not show up
|
2019-07-01 23:00:17 +00:00
|
|
|
once the app is packaged.`;
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #1 Only load secure content
|
|
|
|
*
|
|
|
|
* Checks the loaded resources on the current page and logs a
|
|
|
|
* message about all resources loaded over HTTP or FTP.
|
|
|
|
*/
|
|
|
|
const warnAboutInsecureResources = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (!window || !window.performance || !window.performance.getEntriesByType) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const resources = window.performance
|
|
|
|
.getEntriesByType('resource')
|
|
|
|
.filter(({ name }) => /^(http|ftp):/gi.test(name || ''))
|
|
|
|
.map(({ name }) => `- ${name}`)
|
|
|
|
.join('\n');
|
|
|
|
if (!resources || resources.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const warning = `This renderer process loads resources using insecure
|
2019-06-16 20:19:06 +00:00
|
|
|
protocols.This exposes users of this app to unnecessary security risks.
|
|
|
|
Consider loading the following resources over HTTPS or FTPS. \n ${resources}
|
2019-07-01 23:00:17 +00:00
|
|
|
\n ${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (Insecure Resources)', 'font-weight: bold;', warning);
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #2 on the checklist: Disable the Node.js integration in all renderers that
|
|
|
|
* display remote content
|
|
|
|
*
|
|
|
|
* Logs a warning message about Node integration.
|
|
|
|
*/
|
|
|
|
const warnAboutNodeWithRemoteContent = function (nodeIntegration) {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (!nodeIntegration)
|
|
|
|
return;
|
|
|
|
if (getIsRemoteProtocol()) {
|
|
|
|
const warning = `This renderer process has Node.js integration enabled
|
2019-06-16 20:19:06 +00:00
|
|
|
and attempted to load remote content from '${window.location}'. This
|
2019-07-01 23:00:17 +00:00
|
|
|
exposes users of this app to severe security risks.\n ${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (Node.js Integration with Remote Content)', 'font-weight: bold;', warning);
|
|
|
|
}
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
// Currently missing since it has ramifications and is still experimental:
|
|
|
|
// #3 Enable context isolation in all renderers that display remote content
|
|
|
|
//
|
|
|
|
// Currently missing since we can't easily programmatically check for those cases:
|
|
|
|
// #4 Use ses.setPermissionRequestHandler() in all sessions that load remote content
|
|
|
|
/**
|
|
|
|
* #5 on the checklist: Do not disable websecurity
|
|
|
|
*
|
|
|
|
* Logs a warning message about disabled webSecurity.
|
|
|
|
*/
|
|
|
|
const warnAboutDisabledWebSecurity = function (webPreferences) {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (!webPreferences || webPreferences.webSecurity !== false)
|
|
|
|
return;
|
|
|
|
const warning = `This renderer process has "webSecurity" disabled. This
|
|
|
|
exposes users of this app to severe security risks.\n ${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (Disabled webSecurity)', 'font-weight: bold;', warning);
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #6 on the checklist: Define a Content-Security-Policy and use restrictive
|
|
|
|
* rules (i.e. script-src 'self')
|
|
|
|
*
|
|
|
|
* #7 on the checklist: Disable eval
|
|
|
|
*
|
|
|
|
* Logs a warning message about unset or insecure CSP
|
|
|
|
*/
|
|
|
|
const warnAboutInsecureCSP = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
isUnsafeEvalEnabled().then((enabled) => {
|
|
|
|
if (!enabled)
|
|
|
|
return;
|
|
|
|
const warning = `This renderer process has either no Content Security
|
2019-06-16 20:19:06 +00:00
|
|
|
Policy set or a policy with "unsafe-eval" enabled. This exposes users of
|
2019-07-01 23:00:17 +00:00
|
|
|
this app to unnecessary security risks.\n ${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (Insecure Content-Security-Policy)', 'font-weight: bold;', warning);
|
|
|
|
});
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #8 on the checklist: Do not set allowRunningInsecureContent to true
|
|
|
|
*
|
|
|
|
* Logs a warning message about disabled webSecurity.
|
|
|
|
*/
|
|
|
|
const warnAboutInsecureContentAllowed = function (webPreferences) {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (!webPreferences || !webPreferences.allowRunningInsecureContent)
|
|
|
|
return;
|
|
|
|
const warning = `This renderer process has "allowRunningInsecureContent"
|
2019-06-16 20:19:06 +00:00
|
|
|
enabled. This exposes users of this app to severe security risks.\n
|
2019-07-01 23:00:17 +00:00
|
|
|
${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (allowRunningInsecureContent)', 'font-weight: bold;', warning);
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #9 on the checklist: Do not enable experimental features
|
|
|
|
*
|
|
|
|
* Logs a warning message about experimental features.
|
|
|
|
*/
|
|
|
|
const warnAboutExperimentalFeatures = function (webPreferences) {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (!webPreferences || (!webPreferences.experimentalFeatures)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const warning = `This renderer process has "experimentalFeatures" enabled.
|
2019-06-16 20:19:06 +00:00
|
|
|
This exposes users of this app to some security risk. If you do not need
|
2019-07-01 23:00:17 +00:00
|
|
|
this feature, you should disable it.\n ${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (experimentalFeatures)', 'font-weight: bold;', warning);
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #10 on the checklist: Do not use enableBlinkFeatures
|
|
|
|
*
|
|
|
|
* Logs a warning message about enableBlinkFeatures
|
|
|
|
*/
|
|
|
|
const warnAboutEnableBlinkFeatures = function (webPreferences) {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (!webPreferences ||
|
|
|
|
!webPreferences.hasOwnProperty('enableBlinkFeatures') ||
|
|
|
|
(webPreferences.enableBlinkFeatures && webPreferences.enableBlinkFeatures.length === 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const warning = `This renderer process has additional "enableBlinkFeatures"
|
2019-06-16 20:19:06 +00:00
|
|
|
enabled. This exposes users of this app to some security risk. If you do not
|
2019-07-01 23:00:17 +00:00
|
|
|
need this feature, you should disable it.\n ${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (enableBlinkFeatures)', 'font-weight: bold;', warning);
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
/**
|
|
|
|
* #11 on the checklist: Do Not Use allowpopups
|
|
|
|
*
|
|
|
|
* Logs a warning message about allowed popups
|
|
|
|
*/
|
|
|
|
const warnAboutAllowedPopups = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
if (document && document.querySelectorAll) {
|
|
|
|
const domElements = document.querySelectorAll('[allowpopups]');
|
|
|
|
if (!domElements || domElements.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const warning = `A <webview> has "allowpopups" set to true. This exposes
|
2019-06-16 20:19:06 +00:00
|
|
|
users of this app to some security risk, since popups are just
|
|
|
|
BrowserWindows. If you do not need this feature, you should disable it.\n
|
2019-07-01 23:00:17 +00:00
|
|
|
${moreInformation}`;
|
|
|
|
console.warn('%cElectron Security Warning (allowpopups)', 'font-weight: bold;', warning);
|
|
|
|
}
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
// Currently missing since we can't easily programmatically check for it:
|
|
|
|
// #12WebViews: Verify the options and params of all `<webview>` tags
|
|
|
|
const logSecurityWarnings = function (webPreferences, nodeIntegration) {
|
2019-07-01 23:00:17 +00:00
|
|
|
warnAboutNodeWithRemoteContent(nodeIntegration);
|
|
|
|
warnAboutDisabledWebSecurity(webPreferences);
|
|
|
|
warnAboutInsecureResources();
|
|
|
|
warnAboutInsecureContentAllowed(webPreferences);
|
|
|
|
warnAboutExperimentalFeatures(webPreferences);
|
|
|
|
warnAboutEnableBlinkFeatures(webPreferences);
|
|
|
|
warnAboutInsecureCSP();
|
|
|
|
warnAboutAllowedPopups();
|
|
|
|
};
|
2019-06-16 20:19:06 +00:00
|
|
|
const getWebPreferences = function () {
|
2019-07-01 23:00:17 +00:00
|
|
|
try {
|
|
|
|
return ipc_renderer_internal_utils_1.invokeSync('ELECTRON_BROWSER_GET_LAST_WEB_PREFERENCES');
|
2019-06-16 20:19:06 +00:00
|
|
|
}
|
2019-07-01 23:00:17 +00:00
|
|
|
catch (error) {
|
|
|
|
console.warn(`getLastWebPreferences() failed: ${error}`);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function securityWarnings(nodeIntegration) {
|
|
|
|
const loadHandler = function () {
|
|
|
|
if (shouldLogSecurityWarnings()) {
|
|
|
|
const webPreferences = getWebPreferences();
|
|
|
|
logSecurityWarnings(webPreferences, nodeIntegration);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
window.addEventListener('load', loadHandler, { once: true });
|
|
|
|
}
|
|
|
|
exports.securityWarnings = securityWarnings;
|
|
|
|
//# sourceMappingURL=security-warnings.js.map
|