├── renovate.json
├── example
├── static
│ └── js.png
├── pages
│ └── index.vue
└── nuxt.config.js
├── .eslintignore
├── commitlint.config.js
├── .gitignore
├── .github
├── FUNDING.yml
└── dependabot.yml
├── .releaserc
├── .huskyrc.js
├── babel.config.js
├── .eslintrc.js
├── test
├── fixture
│ ├── defaults.js
│ ├── nuxt.config.defaults.js
│ ├── nuxt.config.params.js
│ └── nuxt.config.helmet.js
├── helmet.test.js
├── helpers.js
├── params.test.js
└── defaults.test.js
├── .editorconfig
├── jest.config.js
├── lib
└── module.js
├── LICENSE
├── .circleci
└── config.yml
├── package.json
└── README.md
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "@nuxtjs"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/example/static/js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/victor-perez/nuxt-helmet/HEAD/example/static/js.png
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # Common
2 | node_modules
3 | dist
4 | .nuxt
5 | coverage
6 |
7 | # Plugin
8 | lib/plugin.js
9 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | '@commitlint/config-conventional'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.iml
3 | .idea
4 | *.log*
5 | .nuxt
6 | .vscode
7 | .DS_Store
8 | coverage
9 | dist
10 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | #github: [victor-perez]
4 | custom: ['https://www.buymeacoffee.com/victoraperez']
5 |
--------------------------------------------------------------------------------
/.releaserc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "@semantic-release/commit-analyzer",
4 | "@semantic-release/release-notes-generator",
5 | "@semantic-release/npm",
6 | ]
7 | }
--------------------------------------------------------------------------------
/.huskyrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | hooks: {
3 | 'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS',
4 | 'pre-commit': 'yarn lint',
5 | 'pre-push': 'yarn lint'
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/example/pages/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Helmet for Nuxt
4 |

5 |
6 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | '@babel/preset-env', {
5 | targets: {
6 | esmodules: true
7 | }
8 | }
9 | ]
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | parser: '@babel/eslint-parser',
5 | sourceType: 'module'
6 | },
7 | extends: [
8 | '@nuxtjs'
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/test/fixture/defaults.js:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 |
3 | export default {
4 | rootDir: resolve(__dirname, '../../'),
5 | srcDir: __dirname,
6 | render: {
7 | resourceHints: false
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_size = 2
6 | indent_style = space
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/test/fixture/nuxt.config.defaults.js:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 | import libModule from '../../lib/module'
3 | import defaultConfig from './defaults'
4 |
5 | export default {
6 | ...defaultConfig,
7 | buildDir: resolve(__dirname, '../../.nuxt/test/defaults'),
8 | modules: [libModule]
9 | }
10 |
--------------------------------------------------------------------------------
/example/nuxt.config.js:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 |
3 | export default {
4 | rootDir: resolve(__dirname, '..'),
5 | buildDir: resolve(__dirname, '.nuxt'),
6 | srcDir: __dirname,
7 | render: {
8 | resourceHints: false
9 | },
10 | modules: [['~~', {
11 | referrerPolicy: true
12 | }]]
13 | }
14 |
--------------------------------------------------------------------------------
/test/fixture/nuxt.config.params.js:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 | import libModule from '../../lib/module'
3 | import defaultConfig from './defaults'
4 |
5 | export default {
6 | ...defaultConfig,
7 | buildDir: resolve(__dirname, '../../.nuxt/test/params'),
8 | modules: [[libModule, {
9 | referrerPolicy: 'no-referrer',
10 | frameguard: false
11 | }]]
12 | }
13 |
--------------------------------------------------------------------------------
/test/fixture/nuxt.config.helmet.js:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path'
2 | import libModule from '../../lib/module'
3 | import defaultConfig from './defaults'
4 |
5 | export default {
6 | ...defaultConfig,
7 | buildDir: resolve(__dirname, '../../.nuxt/test/params'),
8 | modules: [libModule],
9 | helmet: {
10 | referrerPolicy: 'no-referrer',
11 | frameguard: false
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: 'node',
3 | collectCoverage: true,
4 | collectCoverageFrom: [
5 | 'lib/**/*.js'
6 | ],
7 | moduleNameMapper: {
8 | '^~/(.*)$': '/lib/$1',
9 | '^~~$': '',
10 | '^@@$': '',
11 | '^@/(.*)$': '/lib/$1'
12 | },
13 | transform: {
14 | '^.+\\.js$': 'babel-jest'
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/module.js:
--------------------------------------------------------------------------------
1 | import helmet from 'helmet'
2 | import consola from 'consola'
3 |
4 | const logger = consola.withScope('nuxt:helmet')
5 |
6 | export default function (moduleOptions = {}) {
7 | const options = {
8 | permittedCrossDomainPolicies: 'none',
9 | contentSecurityPolicy: false,
10 | ...this.options.helmet || {},
11 | ...moduleOptions
12 | }
13 |
14 | this.nuxt.hook('render:setupMiddleware', (app) => {
15 | app.use(helmet(options))
16 | if (!options.silence) {
17 | logger.success('Nuxt `Helmet` middleware added')
18 | }
19 | })
20 | }
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 | assignees:
13 | - "victor-perez"
14 |
15 |
--------------------------------------------------------------------------------
/test/helmet.test.js:
--------------------------------------------------------------------------------
1 | import config from './fixture/nuxt.config.helmet'
2 | import { startNuxt, stopNuxt, get } from './helpers'
3 |
4 | jest.setTimeout(60000)
5 |
6 | describe('enable/disable helmet modules via helmet', () => {
7 | beforeAll(startNuxt(config))
8 |
9 | afterAll(stopNuxt)
10 |
11 | test('enabled module referrer-Policy', async () => {
12 | const { headers } = await get('/')
13 | expect(headers).toHaveProperty('referrer-policy', 'no-referrer')
14 | })
15 |
16 | test('disabled module referrer-Policy', async () => {
17 | const { headers } = await get('/')
18 | expect(headers).not.toHaveProperty('x-frame-options')
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/test/helpers.js:
--------------------------------------------------------------------------------
1 | import { Nuxt, Builder } from 'nuxt'
2 | import got from 'got'
3 | import getPort from 'get-port'
4 | let nuxt, port
5 |
6 | export const url = path => `http://localhost:${port}${path}`
7 | export const get = path => got(url(path))
8 |
9 | export const stopNuxt = async () => {
10 | if (nuxt) {
11 | await nuxt.close()
12 | }
13 | nuxt = undefined
14 | }
15 |
16 | export const startNuxt = (config) => {
17 | return async () => {
18 | if (nuxt) {
19 | await stopNuxt()
20 | }
21 | nuxt = new Nuxt(config)
22 | port = await getPort()
23 | await new Builder(nuxt).build()
24 | await nuxt.listen(port)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/params.test.js:
--------------------------------------------------------------------------------
1 | import config from './fixture/nuxt.config.params'
2 | import { startNuxt, stopNuxt, get } from './helpers'
3 |
4 | jest.setTimeout(60000)
5 |
6 | describe('enable/disable helmet modules via params', () => {
7 | beforeAll(startNuxt(config))
8 |
9 | afterAll(stopNuxt)
10 |
11 | test('enabled module referrer-Policy', async () => {
12 | const { headers } = await get('/')
13 | expect(headers).toHaveProperty('referrer-policy', 'no-referrer')
14 | })
15 |
16 | test('disabled module referrer-Policy', async () => {
17 | const { headers } = await get('/')
18 | expect(headers).not.toHaveProperty('x-frame-options')
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Victor Perez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/defaults.test.js:
--------------------------------------------------------------------------------
1 | import config from './fixture/nuxt.config.defaults'
2 | import { startNuxt, stopNuxt, get } from './helpers'
3 |
4 | jest.setTimeout(60000)
5 |
6 | const HEADERS = expect.objectContaining({
7 | 'x-content-type-options': 'nosniff',
8 | 'x-dns-prefetch-control': 'off',
9 | 'x-download-options': 'noopen',
10 | 'x-frame-options': 'SAMEORIGIN',
11 | 'x-permitted-cross-domain-policies': 'none',
12 | 'expect-ct': 'max-age=0',
13 | 'referrer-policy': 'no-referrer',
14 | 'x-xss-protection': '0',
15 | 'strict-transport-security': 'max-age=15552000; includeSubDomains'
16 | })
17 |
18 | describe('Default headers', () => {
19 | beforeAll(startNuxt(config))
20 |
21 | afterAll(stopNuxt)
22 |
23 | test('Default config', async () => {
24 | const { headers } = await get('/')
25 | expect(headers).toEqual(HEADERS)
26 | })
27 |
28 | test('Static content headers', async () => {
29 | const { body } = await get('/')
30 |
31 | const requests = body.match(/src="([^"]+)"/g)
32 | .map(src => /src="([^"]+)"/.exec(src)[1])
33 | .map(file => get(file))
34 | .map(p => p.then(({ headers }) => expect(headers).toEqual(HEADERS)))
35 |
36 | return Promise.all(requests)
37 | })
38 | })
39 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | defaults: &defaults
4 | working_directory: ~/repo
5 | docker:
6 | - image: circleci/node
7 |
8 | jobs:
9 | test:
10 | <<: *defaults
11 | steps:
12 | # Checkout repository
13 | - checkout
14 |
15 | # Restore cache
16 | - restore_cache:
17 | key: yarn-cache-{{ checksum "yarn.lock" }}
18 |
19 | # Install dependencies
20 | - run:
21 | name: Install Dependencies
22 | command: NODE_ENV=dev yarn
23 |
24 | # Keep cache
25 | - save_cache:
26 | key: yarn-cache-{{ checksum "yarn.lock" }}
27 | paths:
28 | - "node_modules"
29 |
30 | # Lint
31 | - run:
32 | name: Lint
33 | command: yarn lint
34 |
35 | # Tests
36 | - run:
37 | name: Tests
38 | command: yarn jest
39 |
40 | # Coverage
41 | - run:
42 | name: Coverage
43 | command: yarn codecov
44 |
45 | - persist_to_workspace:
46 | root: ~/repo
47 | paths: .
48 |
49 | release:
50 | <<: *defaults
51 | steps:
52 | - attach_workspace:
53 | at: ~/repo
54 | - run:
55 | name: Avoid hosts unknown for github
56 | command: mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config
57 | - run:
58 | name: Publish package
59 | command: yarn release
60 |
61 | workflows:
62 | version: 2
63 | test-deploy:
64 | jobs:
65 | - test
66 | - hold:
67 | type: approval
68 | requires:
69 | - test
70 | filters:
71 | branches:
72 | only:
73 | - master
74 | - release:
75 | requires:
76 | - hold
77 | filters:
78 | branches:
79 | only:
80 | - master
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nuxt-helmet",
3 | "version": "2.1.0",
4 | "description": "Helmet for nuxt",
5 | "license": "MIT",
6 | "contributors": [
7 | {
8 | "name": "Victor Perez "
9 | }
10 | ],
11 | "main": "lib/module.js",
12 | "publishConfig": {
13 | "access": "public"
14 | },
15 | "keywords": [
16 | "security",
17 | "headers",
18 | "helmet",
19 | "helmet.js",
20 | "nuxt",
21 | "nuxtjs",
22 | "nuxt.js",
23 | "x-frame-options",
24 | "csp",
25 | "hsts",
26 | "clickjack"
27 | ],
28 | "scripts": {
29 | "dev": "nuxt example",
30 | "lint": "eslint lib test",
31 | "test": "yarn lint && rimraf ./.nuxt && jest",
32 | "release": "semantic-release",
33 | "commit": "npx git-cz"
34 | },
35 | "files": [
36 | "lib"
37 | ],
38 | "dependencies": {
39 | "consola": "^2.11.3",
40 | "helmet": "^5.0.1"
41 | },
42 | "devDependencies": {
43 | "@babel/core": "^7.16.7",
44 | "@babel/eslint-parser": "^7.16.5",
45 | "@babel/preset-env": "^7.16.8",
46 | "@commitlint/cli": "^16.0.2",
47 | "@commitlint/config-conventional": "^16.0.0",
48 | "@nuxtjs/eslint-config": "^8.0.0",
49 | "babel-jest": "^27.4.6",
50 | "codecov": "^3.6.5",
51 | "cz-conventional-changelog": "^3.3.0",
52 | "eslint": "^8.6.0",
53 | "eslint-config-standard": "^16.0.3",
54 | "eslint-plugin-import": "^2.20.1",
55 | "eslint-plugin-jest": "^25.3.4",
56 | "eslint-plugin-node": "^11.0.0",
57 | "eslint-plugin-promise": "^6.0.0",
58 | "eslint-plugin-standard": "^5.0.0",
59 | "eslint-plugin-vue": "^8.3.0",
60 | "get-port": "5.x",
61 | "got": "11.x",
62 | "husky": "^4.2.3",
63 | "jest": "^27.4.7",
64 | "nuxt": "^2.12.0",
65 | "rimraf": "^3.0.2",
66 | "semantic-release": "^19.0.2"
67 | },
68 | "config": {
69 | "commitizen": {
70 | "path": "./node_modules/cz-conventional-changelog"
71 | }
72 | },
73 | "repository": {
74 | "type": "git",
75 | "url": "https://github.com/victor-perez/nuxt-helmet.git"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Helmet for nuxt
2 |
3 | [![npm version][npm-version-src]][npm-version-href]
4 | [![npm downloads][npm-downloads-src]][npm-downloads-href]
5 | [![Circle CI][circle-ci-src]][circle-ci-href]
6 | [![Codecov][codecov-src]][codecov-href]
7 | [![Dependencies][david-dm-src]][david-dm-href]
8 | [![Standard JS][standard-js-src]][standard-js-href]
9 | [![Buy Me A Coffee][bmc-shield-src]][bmc-href]
10 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fvictor-perez%2Fnuxt-helmet?ref=badge_shield)
11 |
12 | > Easy [Helmet](https://helmetjs.github.io/) integration with Nuxt.js
13 |
14 | > [Helmet](https://helmetjs.github.io/) helps you secure your Nuxt apps by setting various HTTP headers. By default [Helmet](https://helmetjs.github.io/) will set the
15 | `X-DNS-Prefetch-Control`, `X-Frame-Options`, `Strict-Transport-Security`, `X-Download-Options`, `Expect-Ct`, `Referrer-Policy` and `X-Content-Type-Options` headers. Beside that this module will also set by default the `X-Permitted-Cross-Domain-Policies` header.
16 |
17 | [📖 **Release Notes**](https://github.com/victor-perez/nuxt-helmet/releases) | [📖 **Helmet Docs**](https://helmetjs.github.io/docs/)
18 |
19 | ## Setup
20 |
21 | 1. Add `nuxt-helmet` dependency with `yarn` or `npm` into your project
22 | 2. Add `nuxt-helmet` at the beginning of the `modules` section of `nuxt.config.js`
23 | 3. Configure it:
24 |
25 | ```js
26 | {
27 | modules: [
28 | 'nuxt-helmet'
29 | //...other modules
30 | ],
31 | // helmet options
32 | // @see https://helmetjs.github.io/docs/
33 | helmet: {
34 | /*
35 | frameguard: false,
36 | ...
37 | */
38 | }
39 | }
40 | ```
41 |
42 | ## Note
43 | Use `csp` property provided by Nuxt.js v2.11.0 for Content Security Policy (CSP) | [📖 **Nuxt Docs**](https://nuxtjs.org/api/configuration-render/#csp)
44 |
45 | ## Development
46 |
47 | 1. Clone this repository
48 | 2. Install dependencies using `yarn install` or `npm install`
49 | 3. Start development server using `npm run dev`
50 |
51 | ## Sponsor
52 |
53 | [![Buy Me A Coffee][bmc-src]][bmc-href]
54 |
55 | ## License
56 |
57 | [MIT License](./LICENSE)
58 |
59 | Copyright (c) Victor Perez
60 |
61 |
62 | [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-helmet.svg?style=flat-square
63 | [npm-downloads-href]: https://npmjs.com/package/nuxt-helmet
64 |
65 | [npm-version-src]: https://img.shields.io/npm/v/nuxt-helmet/latest.svg?style=flat-square
66 | [npm-version-href]: https://npmjs.com/package/nuxt-helmet
67 |
68 | [circle-ci-src]: https://img.shields.io/circleci/project/github/victor-perez/nuxt-helmet.svg?style=flat-square
69 | [circle-ci-href]: https://circleci.com/gh/victor-perez/nuxt-helmet
70 |
71 | [codecov-src]: https://img.shields.io/codecov/c/github/victor-perez/nuxt-helmet.svg?style=flat-square
72 | [codecov-href]: https://codecov.io/gh/victor-perez/nuxt-helmet
73 |
74 | [david-dm-src]: https://david-dm.org/victor-perez/nuxt-helmet/status.svg?style=flat-square
75 | [david-dm-href]: https://david-dm.org/victor-perez/nuxt-helmet
76 |
77 | [standard-js-src]: https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square
78 | [standard-js-href]: https://standardjs.com
79 | [bmc-src]: https://bmc-cdn.nyc3.digitaloceanspaces.com/BMC-button-images/custom_images/orange_img.png
80 | [bmc-href]: https://www.buymeacoffee.com/victoraperez
81 | [bmc-shield-src]: https://img.shields.io/static/v1?message=Buy%20me%20a%20coffee&logo=buy-me-a-coffee&style=flat-square&label=Sponsor&logoColor=white&color=ff813f
82 |
83 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fvictor-perez%2Fnuxt-helmet?ref=badge_large)
84 |
--------------------------------------------------------------------------------