summaryrefslogtreecommitdiff
path: root/test/csp.js
blob: 7059815662675802993fface798cb85201f132f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* 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,
      dropbox: {
        appKey: undefined
      }
    }
  })

  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 () {
    const 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 () {
    const 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 () {
    const 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('Include dropbox if configured', function () {
    const testconfig = defaultConfig
    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\''))
  })

  it('Set ReportURI', function () {
    const 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 () {
    const 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'), 'd5d872ae49b5db27f638b152e6e528837204d380')
  })
})