Browse Source

Merge pull request #456 from mrfelton/fix/better-csp-for-production

Implement a more restrictive Content Security Policy for production builds
renovate/lint-staged-8.x
Ben Woosley 7 years ago
committed by GitHub
parent
commit
096cdedb1b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      app/api/index.js
  2. 43
      app/app.html
  3. 7
      app/main.dev.js
  4. 3
      package.json
  5. 59
      webpack.config.renderer.dev.js
  6. 33
      webpack.config.renderer.prod.js
  7. 50
      yarn.lock

18
app/api/index.js

@ -1,7 +1,19 @@
import axios from 'axios'
// When running in development/hot mode we load the renderer js code via webpack dev server, and it is from there that
// we ultimately initate requests to these remote resources. The end result is that the electron browser window makes a
// request to localhost (to webpack dev server), which in turn makes a request to the remote resource. If the remote
// resource in question has a restrictive `Access-Control-Allow-Origin` header, this may cause the electron browser
// window to not allow loading the remote content.
//
// See https://enable-cors.org/
//
// In order to mitigate the CORS issue, we instead access these remote resources through a local proxy that we have
// defined on the webpack dev server.
const scheme = process.env.HOT ? '/proxy/' : 'https://'
export function requestTicker(id) {
const BASE_URL = `https://api.coinmarketcap.com/v1/ticker/${id}/`
const BASE_URL = `${scheme}api.coinmarketcap.com/v1/ticker/${id}`
return axios({
method: 'get',
url: BASE_URL
@ -17,7 +29,7 @@ export function requestTickers(ids) {
}
export function requestBlockHeight() {
const BASE_URL = 'https://testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1'
const BASE_URL = `${scheme}testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1`
return axios({
method: 'get',
url: BASE_URL
@ -25,7 +37,7 @@ export function requestBlockHeight() {
}
export function requestSuggestedNodes() {
const BASE_URL = 'https://zap.jackmallers.com/suggested-peers'
const BASE_URL = `${scheme}zap.jackmallers.com/suggested-peers`
return axios({
method: 'get',
url: BASE_URL

43
app/app.html

@ -2,55 +2,14 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
connect-src 'self' http://localhost:* ws://localhost:* https://api.coinmarketcap.com https://zap.jackmallers.com https://testnet-api.smartbit.com.au;
script-src 'self' http://localhost:* 'unsafe-eval' 'unsafe-inline';
font-src 'self' data: http://localhost:* https://fonts.googleapis.com https://s3.amazonaws.com https://fonts.gstatic.com;
style-src 'self' blob: https://fonts.googleapis.com https://s3.amazonaws.com https://fonts.gstatic.com 'unsafe-inline';">
<meta http-equiv="Content-Security-Policy" content="">
<title>Zap</title>
<link rel="stylesheet" href="https://s3.amazonaws.com/fonts.typotheque.com/WF-018717-007225.css" type="text/css" />
<link href='https://fonts.googleapis.com/css?family=Raleway:700' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Orbitron' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Noto+Sans:400,700|Roboto:300' rel='stylesheet' type='text/css'>
<script>
(function() {
if (!process.env.HOT) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './dist/style.css';
// HACK: Writing the script path should be done with webpack
document.getElementsByTagName('head')[0].appendChild(link);
}
}());
</script>
</head>
<body>
<div id="root"></div>
<script>
{
const scripts = [];
// Dynamically insert the DLL script in development env in the
// renderer process
if (process.env.NODE_ENV === 'development') {
scripts.push('../dll/renderer.dev.dll.js');
}
// Dynamically insert the bundled app script in the renderer process
const port = process.env.PORT || 1212;
scripts.push(
(process.env.HOT)
? 'http://localhost:' + port + '/dist/renderer.dev.js'
: './dist/renderer.prod.js'
);
document.write(
scripts
.map(script => '<script defer src="' + script + '"><\/script>')
.join('')
);
}
</script>
</body>
</html>

7
app/main.dev.js

@ -258,7 +258,12 @@ app.on('ready', async () => {
minHeight: 425
})
mainWindow.loadURL(`file://${__dirname}/app.html`)
if (process.env.HOT) {
const port = process.env.PORT || 1212
mainWindow.loadURL(`http://localhost:${port}/dist/index.html`)
} else {
mainWindow.loadURL(`file://${__dirname}/dist/index.html`)
}
// @TODO: Use 'ready-to-show' event
// https://github.com/electron/electron/blob/master/docs/api/browser-window.md#using-ready-to-show-event

3
package.json

@ -52,7 +52,6 @@
"files": [
"dist/",
"node_modules/",
"app.html",
"main.prod.js",
"main.prod.js.map",
"package.json"
@ -144,6 +143,7 @@
"devDependencies": {
"@commitlint/cli": "^7.0.0",
"@commitlint/config-conventional": "^7.0.1",
"add-asset-html-webpack-plugin": "^2.1.3",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-jest": "^23.0.1",
@ -165,6 +165,7 @@
"concurrently": "^3.5.1",
"cross-env": "^5.2.0",
"cross-spawn": "^6.0.5",
"csp-html-webpack-plugin": "^2.3.0",
"css-loader": "^0.28.11",
"electron-builder": "^20.15.3",
"electron-devtools-installer": "^2.2.4",

59
webpack.config.renderer.dev.js

@ -13,6 +13,9 @@ import webpack from 'webpack'
import merge from 'webpack-merge'
import { spawn, execSync } from 'child_process'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import AddAssetHtmlPlugin from 'add-asset-html-webpack-plugin'
import CspHtmlWebpackPlugin from 'csp-html-webpack-plugin'
import baseConfig from './webpack.config.base'
import { mainLog } from './app/utils/log'
@ -217,6 +220,45 @@ export default merge.smart(baseConfig, {
new ExtractTextPlugin({
filename: '[name].css'
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'app', 'app.html')
}),
new AddAssetHtmlPlugin({
filepath: path.join(__dirname, 'dll', 'renderer.dev.dll.js'),
includeSourcemap: false
}),
new CspHtmlWebpackPlugin({
'default-src': "'self'",
'object-src': "'none'",
'connect-src': [
"'self'",
'http://localhost:*',
'ws://localhost:*',
'https://api.coinmarketcap.com',
'https://zap.jackmallers.com',
'https://testnet-api.smartbit.com.au'
],
'script-src': ["'self'", 'http://localhost:*', "'unsafe-eval'"],
'font-src': [
"'self'",
'data:',
'http://localhost:*',
'https://fonts.googleapis.com',
'https://s3.amazonaws.com',
'https://fonts.gstatic.com'
],
'style-src': [
"'self'",
'blob:',
'https://fonts.googleapis.com',
'https://s3.amazonaws.com',
'https://fonts.gstatic.com',
"'unsafe-inline'"
]
})
],
@ -241,6 +283,23 @@ export default merge.smart(baseConfig, {
ignored: /node_modules/,
poll: 100
},
proxy: {
'/proxy/zap.jackmallers.com': {
target: 'https://zap.jackmallers.com',
pathRewrite: { '^/proxy/zap.jackmallers.com': '' },
changeOrigin: true
},
'/proxy/api.coinmarketcap.com': {
target: 'https://api.coinmarketcap.com',
pathRewrite: { '^/proxy/api.coinmarketcap.com': '' },
changeOrigin: true
},
'/proxy/testnet-api.smartbit.com.au': {
target: 'https://testnet-api.smartbit.com.au',
pathRewrite: { '^/proxy/testnet-api.smartbit.com.au': '' },
changeOrigin: true
}
},
historyApiFallback: {
verbose: true,
disableDotRule: false

33
webpack.config.renderer.prod.js

@ -4,6 +4,8 @@
import path from 'path'
import ExtractTextPlugin from 'extract-text-webpack-plugin'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import CspHtmlWebpackPlugin from 'csp-html-webpack-plugin'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
import merge from 'webpack-merge'
import baseConfig from './webpack.config.base'
@ -144,6 +146,37 @@ export default merge.smart(baseConfig, {
new BundleAnalyzerPlugin({
analyzerMode: process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true'
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'app', 'app.html')
}),
new CspHtmlWebpackPlugin({
'default-src': "'self'",
'object-src': "'none'",
'connect-src': [
"'self'",
'https://api.coinmarketcap.com',
'https://zap.jackmallers.com',
'https://testnet-api.smartbit.com.au'
],
'script-src': ["'self'"],
'font-src': [
"'self'",
'data:',
'https://fonts.googleapis.com',
'https://s3.amazonaws.com',
'https://fonts.gstatic.com'
],
'style-src': [
"'self'",
'blob:',
'https://fonts.googleapis.com',
'https://s3.amazonaws.com',
'https://fonts.gstatic.com',
"'unsafe-inline'"
]
})
]
})

50
yarn.lock

@ -247,6 +247,10 @@
dependencies:
any-observable "^0.3.0"
"@types/node@*":
version "10.3.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.4.tgz#c74e8aec19e555df44609b8057311052a2c84d9e"
"@types/node@^6.0.46":
version "6.0.78"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.78.tgz#5d4a3f579c1524e01ee21bf474e6fba09198f470"
@ -472,6 +476,14 @@ acorn@^5.5.0, acorn@^5.6.2:
version "5.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
add-asset-html-webpack-plugin@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/add-asset-html-webpack-plugin/-/add-asset-html-webpack-plugin-2.1.3.tgz#1bb8cd9cf9bd612833a502397bb75da66b77ba32"
dependencies:
globby "^8.0.0"
micromatch "^3.1.3"
p-each-series "^1.0.0"
ajv-keywords@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@ -2577,6 +2589,17 @@ cheerio@^0.22.0:
lodash.reject "^4.4.0"
lodash.some "^4.4.0"
cheerio@^1.0.0-rc.2:
version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
dependencies:
css-select "~1.2.0"
dom-serializer "~0.1.0"
entities "~1.1.1"
htmlparser2 "^3.9.1"
lodash "^4.15.0"
parse5 "^3.0.1"
chokidar@^2.0.0, chokidar@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176"
@ -3203,6 +3226,13 @@ crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
csp-html-webpack-plugin@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/csp-html-webpack-plugin/-/csp-html-webpack-plugin-2.3.0.tgz#33f8d9fe4dcd61e1c4a8a9e936ec54adddecfaeb"
dependencies:
cheerio "^1.0.0-rc.2"
lodash "^4.17.10"
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@ -7632,7 +7662,7 @@ lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, l
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
lodash@^4.17.10, lodash@^4.17.5, lodash@^4.5.1:
lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.5, lodash@^4.5.1:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
@ -7897,7 +7927,7 @@ micromatch@^2.3.11:
parse-glob "^3.0.4"
regex-cache "^0.4.2"
micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9:
micromatch@^3.1.10, micromatch@^3.1.3, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
dependencies:
@ -8644,6 +8674,12 @@ p-cancelable@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
p-each-series@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71"
dependencies:
p-reduce "^1.0.0"
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@ -8664,6 +8700,10 @@ p-map@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.1.1.tgz#05f5e4ae97a068371bc2a5cc86bfbdbc19c4ae7a"
p-reduce@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa"
p-timeout@^1.1.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
@ -8769,6 +8809,12 @@ parse5@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
dependencies:
"@types/node" "*"
parse5@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510"

Loading…
Cancel
Save