2019-01-18 22:57:18 -05:00
|
|
|
/* 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
|
|
|
|
},
|
2020-08-22 19:35:45 -04:00
|
|
|
useCDN: true,
|
|
|
|
dropbox: {
|
|
|
|
appKey: undefined
|
|
|
|
}
|
2019-01-18 22:57:18 -05:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
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 () {
|
2021-02-15 03:42:51 -05:00
|
|
|
const testconfig = defaultConfig
|
2019-01-18 22:57:18 -05:00
|
|
|
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 () {
|
2021-02-15 03:42:51 -05:00
|
|
|
const testconfig = defaultConfig
|
2019-01-18 22:57:18 -05:00
|
|
|
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 () {
|
2021-02-15 03:42:51 -05:00
|
|
|
const testconfig = defaultConfig
|
2019-01-18 22:57:18 -05:00
|
|
|
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'))
|
|
|
|
})
|
|
|
|
|
2020-08-22 19:41:55 -04:00
|
|
|
it('Include dropbox if configured', function () {
|
2021-02-15 03:42:51 -05:00
|
|
|
const testconfig = defaultConfig
|
2020-08-22 19:41:55 -04:00
|
|
|
testconfig.dropbox.appKey = 'hedgedoc'
|
|
|
|
mock('../lib/config', testconfig)
|
|
|
|
csp = mock.reRequire('../lib/csp')
|
|
|
|
|
|
|
|
assert(csp.computeDirectives().scriptSrc.includes('https://www.dropbox.com'))
|
|
|
|
assert(csp.computeDirectives().scriptSrc.includes('\'unsafe-inline\''))
|
|
|
|
})
|
|
|
|
|
2019-01-18 22:57:18 -05:00
|
|
|
it('Set ReportURI', function () {
|
2021-02-15 03:42:51 -05:00
|
|
|
const testconfig = defaultConfig
|
2019-01-18 22:57:18 -05:00
|
|
|
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 () {
|
2021-02-15 03:42:51 -05:00
|
|
|
const testconfig = defaultConfig
|
2019-01-18 22:57:18 -05:00
|
|
|
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')
|
2020-02-01 06:50:07 -05:00
|
|
|
assert.strictEqual(hash.digest('hex'), 'd5d872ae49b5db27f638b152e6e528837204d380')
|
2019-01-18 22:57:18 -05:00
|
|
|
})
|
|
|
|
})
|