summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json1
-rw-r--r--test/csp.js124
2 files changed, 125 insertions, 0 deletions
diff --git a/package.json b/package.json
index 30c4bf8d..f2811fe5 100644
--- a/package.json
+++ b/package.json
@@ -184,6 +184,7 @@
"less-loader": "^4.1.0",
"mini-css-extract-plugin": "^0.4.1",
"mocha": "^5.2.0",
+ "mock-require": "^3.0.3",
"optimize-css-assets-webpack-plugin": "^5.0.0",
"script-loader": "^0.7.2",
"string-loader": "^0.0.1",
diff --git a/test/csp.js b/test/csp.js
new file mode 100644
index 00000000..a6de68ab
--- /dev/null
+++ b/test/csp.js
@@ -0,0 +1,124 @@
+/* eslint-env node, mocha */
+'use strict'
+
+const assert = require('assert')
+const crypto = require('crypto')
+const fs = require('fs')
+const path = require('path')
+const mock = require('mock-require')
+
+describe('Content security policies', function () {
+ let defaultConfig, csp
+
+ before(function () {
+ csp = require('../lib/csp')
+ })
+
+ beforeEach(function () {
+ // Reset config to make sure we don't influence other tests
+ defaultConfig = {
+ csp: {
+ enable: true,
+ directives: {
+ },
+ addDefaults: true,
+ addDisqus: true,
+ addGoogleAnalytics: true,
+ upgradeInsecureRequests: 'auto',
+ reportURI: undefined
+ },
+ useCDN: true
+ }
+ })
+
+ afterEach(function () {
+ mock.stop('../lib/config')
+ csp = mock.reRequire('../lib/csp')
+ })
+
+ after(function () {
+ mock.stopAll()
+ csp = mock.reRequire('../lib/csp')
+ })
+
+ // beginnging Tests
+ it('Disable CDN', function () {
+ let testconfig = defaultConfig
+ testconfig.useCDN = false
+ mock('../lib/config', testconfig)
+ csp = mock.reRequire('../lib/csp')
+
+ assert(!csp.computeDirectives().scriptSrc.includes('https://cdnjs.cloudflare.com'))
+ assert(!csp.computeDirectives().scriptSrc.includes('https://cdn.mathjax.org'))
+ assert(!csp.computeDirectives().styleSrc.includes('https://cdnjs.cloudflare.com'))
+ assert(!csp.computeDirectives().styleSrc.includes('https://fonts.googleapis.com'))
+ assert(!csp.computeDirectives().fontSrc.includes('https://cdnjs.cloudflare.com'))
+ assert(!csp.computeDirectives().fontSrc.includes('https://fonts.gstatic.com'))
+ })
+
+ it('Disable Google Analytics', function () {
+ let testconfig = defaultConfig
+ testconfig.csp.addGoogleAnalytics = false
+ mock('../lib/config', testconfig)
+ csp = mock.reRequire('../lib/csp')
+
+ assert(!csp.computeDirectives().scriptSrc.includes('https://www.google-analytics.com'))
+ })
+
+ it('Disable Disqus', function () {
+ let testconfig = defaultConfig
+ testconfig.csp.addDisqus = false
+ mock('../lib/config', testconfig)
+ csp = mock.reRequire('../lib/csp')
+
+ assert(!csp.computeDirectives().scriptSrc.includes('https://disqus.com'))
+ assert(!csp.computeDirectives().scriptSrc.includes('https://*.disqus.com'))
+ assert(!csp.computeDirectives().scriptSrc.includes('https://*.disquscdn.com'))
+ assert(!csp.computeDirectives().styleSrc.includes('https://*.disquscdn.com'))
+ assert(!csp.computeDirectives().fontSrc.includes('https://*.disquscdn.com'))
+ })
+
+ it('Set ReportURI', function () {
+ let testconfig = defaultConfig
+ testconfig.csp.reportURI = 'https://example.com/reportURI'
+ mock('../lib/config', testconfig)
+ csp = mock.reRequire('../lib/csp')
+
+ assert.strictEqual(csp.computeDirectives().reportUri, 'https://example.com/reportURI')
+ })
+
+ it('Set own directives', function () {
+ let testconfig = defaultConfig
+ mock('../lib/config', defaultConfig)
+ csp = mock.reRequire('../lib/csp')
+ const unextendedCSP = csp.computeDirectives()
+ testconfig.csp.directives = {
+ defaultSrc: ['https://default.example.com'],
+ scriptSrc: ['https://script.example.com'],
+ imgSrc: ['https://img.example.com'],
+ styleSrc: ['https://style.example.com'],
+ fontSrc: ['https://font.example.com'],
+ objectSrc: ['https://object.example.com'],
+ mediaSrc: ['https://media.example.com'],
+ childSrc: ['https://child.example.com'],
+ connectSrc: ['https://connect.example.com']
+ }
+ mock('../lib/config', testconfig)
+ csp = mock.reRequire('../lib/csp')
+
+ const variations = ['default', 'script', 'img', 'style', 'font', 'object', 'media', 'child', 'connect']
+
+ for (let i = 0; i < variations.length; i++) {
+ assert.strictEqual(csp.computeDirectives()[variations[i] + 'Src'].toString(), ['https://' + variations[i] + '.example.com'].concat(unextendedCSP[variations[i] + 'Src']).toString())
+ }
+ })
+
+ /*
+ * This test reminds us to update the CSP hash for the speaker notes
+ */
+ it('Unchanged hash for reveal.js speaker notes plugin', function () {
+ const hash = crypto.createHash('sha1')
+ hash.update(fs.readFileSync(path.resolve(__dirname, '../node_modules/reveal.js/plugin/notes/notes.html'), 'utf8'), 'utf8')
+ assert.strictEqual(hash.digest('hex'), '471f3826880fac884a4a14faabc492bc854ae994')
+ })
+})