Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add csp hash for color script #94

Merged
merged 3 commits into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/module.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { resolve } from 'path'
import { promises as fsp } from 'fs'
import crypto from 'crypto'
import defu from 'defu'
import template from 'lodash.template'
import { addTemplates } from './utils'
Expand Down Expand Up @@ -42,6 +43,13 @@ export default async function (moduleOptions) {
head[serializeProp][options.hid] = ['innerHTML']
})

this.nuxt.hook('vue-renderer:ssr:csp', (cspScriptSrcHashes) => {
const { csp } = this.options.render
const hash = crypto.createHash(csp.hashAlgorithm)
hash.update(options.script)
cspScriptSrcHashes.push(`'${csp.hashAlgorithm}-${hash.digest('base64')}'`)
})

// Add all templates
const templatesDir = resolve(__dirname, 'templates')
await addTemplates.call(this, templatesDir, 'color-mode', options)
Expand Down
24 changes: 23 additions & 1 deletion test/ssr.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ describe('ssr: true, target: server, prod mode', () => {
})

test('render', async () => {
const { body } = await get('/')
const { body, headers } = await get('/')
expect(body).toContain('nuxt-color-mode-script')
expect(headers['content-security-policy']).toBeUndefined()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it expected that there is no CSP header when the target is server? Does vue-renderer set the CSP itself then? I'm using the server target and SSR and within development everything works fine, but when I deploy my project to production, the CSP hash seems to be missing from script-src again and the color-mode cannot be changed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is default scenario which build.csp is not enabled in nuxt.config.js

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I deploy my project to production, the CSP hash seems to be missing from script-src again and the color-mode cannot be changed.

CSP hash should work same in dev and production, can you double check the nuxt.config and http response header of your page ?

Copy link

@dargmuesli dargmuesli Aug 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, the header only includes the always changing hash for nuxt state on production (and development), but sha256-SzzThFtAnNrq8hsItwHFrLjbWhI0pfrqgYInXTrgWRI= is only added on development. Currently, you can see it here yourself: https://alpha.maev.si/ which is running version 0.93.1 of https://github.com/maevsi/maevsi/. In the footer there are links to change the color mode, but the console shows a CSP error. Not so when starting the project using yarn dev. During yarn build L57 is ran across, but when vue-renderer calls vue-renderer:ssr:csp L58-L61 is not run. Here you can see my projet's csp configuration: https://github.com/maevsi/maevsi/blob/1c19ad303f8ce275e67dbe204adcfd1bc0ab66c9/nuxt/nuxt.config.js#L373

Btw, why is this plugin not registered by using addPlugin like here? https://github.com/nuxt-community/ackee-module/blob/fa6ac7d45dddbca7be5fea47294b9e5cb2206568/src/module.ts#L33

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is because you’re using this module as buildModule which is only for dev and build instead of production running. @atinux Should we recommend using this module as a normal module?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point, and indeed that solved the issue!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed adding a note in the README when using CSP could be nice. PR welcome ❤️

})
})

Expand All @@ -61,3 +62,24 @@ describe('ssr: true, target: static, generated files', () => {
}
})
})

describe('ssr: true, csp hash on script', () => {
const rootDir = join(__dirname, '..', 'example')

setupTest({
server: true,
build: true,
rootDir,
config: {
ssr: true,
render: {
csp: true
}
}
})

test('csp hash on script', async () => {
const { headers } = await get('/')
expect(headers['content-security-policy']).toContain('sha256-')
})
})