Skip to content
Snippets Groups Projects
Commit 41fe7f3b authored by julian.baeume's avatar julian.baeume :pick:
Browse files

configure CSP to allow script execution

this currently doesn't really work as expected, but can be used as a base
to properly implement CSP for the scripts we "know" about.
parent 2c3a21e5
No related branches found
No related tags found
No related merge requests found
......@@ -56,6 +56,7 @@ describe('File caching service', () => {
expect(response.statusCode).toBe(200)
expect(response.headers['content-type']).toBe('application/javascript; charset=utf-8')
expect(response.text).toBe('this is example')
expect(response.headers['content-security-policy']).toContain('sha256-NzZhMTE2Njc2YTgyNTZmZTdlZGVjZDU3YTNmYzRjNmM1OWZkMTI2NjRkYzZmMWM3YTkwMGU3ZTdhNDlhZmVlMwo=')
const response2 = await request(app).get('/test.txt')
expect(response2.statusCode).toBe(200)
expect(response2.headers['content-type']).toBe('text/plain; charset=utf-8')
......@@ -66,6 +67,7 @@ describe('File caching service', () => {
const response = await request(app).get('/main.css')
expect(response.statusCode).toBe(200)
expect(response.headers['content-type']).toBe('text/css; charset=utf-8')
expect(response.headers['content-security-policy']).toContain('sha256-YjRiYWRlYTVhYmM5ZTZkNjE2ZGM4YjcwZWRlNzUxMmU0YjgxY2UxMWExOTI2ZjM1NzM1M2Y2MWJjNmUwMmZjMwo=')
})
it('serves / as index.html', async () => {
......
......@@ -38,7 +38,19 @@ export function createApp () {
// Application-level middleware
app.use(httpLogger)
app.use(helmet())
app.use((req, res, next) => {
const { sha256Sum } = fileCache.get(req.path)
res.locals.sha256Sum = sha256Sum
next()
})
app.use(helmet({
contentSecurityPolicy: {
useDefaults: true,
directives: {
defaultSrc: ["'self'", (req, res) => res.locals.sha256Sum ? `'sha256-${res.locals.sha256Sum}'` : '']
}
}
}))
app.use('/healthy', health.LivenessEndpoint(healthCheck))
app.use('/ready', health.ReadinessEndpoint(healthCheck))
app.use(metricsMiddleware)
......
import fetch from 'node-fetch'
import crypto from 'crypto'
class FileCache {
constructor () {
this._cache = {}
}
async warmUp (manifests, deps) {
const cache = Object.fromEntries(await (async function () {
const files = Object.keys(deps)
......@@ -20,9 +25,12 @@ class FileCache {
}
const response = await fetch(new URL(file, manifest.meta.baseUrl))
if (!response.ok) return null
const content = await response.buffer()
const sha256Sum = crypto.createHash('sha256').update(content).digest('base64')
return [file, {
'content-type': response.headers.get('content-type'),
content: await response.buffer()
sha256Sum,
content
}]
} catch (e) { console.error(e) }
}))).filter(data => Array.isArray(data) && data.length === 2))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment