Skip to content

Commit

Permalink
fix(gatsby-plugin-netlify): security headers merging (#17538)
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinerousseau authored and GatsbyJS Bot committed Sep 10, 2019
1 parent 459f197 commit 8420626
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,83 @@ exports[`with caching headers 1`] = `
"
`;

exports[`with security headers 1`] = `
"## Created with gatsby-plugin-netlify
/*
X-Frame-Options: ALLOW-FROM https://app.storyblok.com/
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Content-Security-Policy: frame-ancestors 'self' https://*.storyblok.com/
/component---node-modules-gatsby-plugin-offline-app-shell-js-78f9e4dea04737fa062d.js
Cache-Control: public, max-age=31536000, immutable
/0-0180cd94ef2497ac7db8.js
Cache-Control: public, max-age=31536000, immutable
/component---src-templates-blog-post-js-517987eae96e75cddbe7.js
Cache-Control: public, max-age=31536000, immutable
/component---src-pages-404-js-53e6c51a5a7e73090f50.js
Cache-Control: public, max-age=31536000, immutable
/component---src-pages-index-js-0bdd01c77ee09ef0224c.js
Cache-Control: public, max-age=31536000, immutable
/pages-manifest-ab11f09e0ca7ecd3b43e.js
Cache-Control: public, max-age=31536000, immutable
/webpack-runtime-acaa8994f1f704475e21.js
Cache-Control: public, max-age=31536000, immutable
/styles.1025963f4f2ec7abbad4.css
Cache-Control: public, max-age=31536000, immutable
/styles-565f081c8374bbda155f.js
Cache-Control: public, max-age=31536000, immutable
/app-f33c13590352da20930f.js
Cache-Control: public, max-age=31536000, immutable
/static/*
Cache-Control: public, max-age=31536000, immutable
/sw.js
Cache-Control: no-cache
/offline-plugin-app-shell-fallback/
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </component---node-modules-gatsby-plugin-offline-app-shell-js-78f9e4dea04737fa062d.js>; rel=preload; as=script
/hi-folks/
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </0-0180cd94ef2497ac7db8.js>; rel=preload; as=script
Link: </component---src-templates-blog-post-js-517987eae96e75cddbe7.js>; rel=preload; as=script
/my-second-post/
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </0-0180cd94ef2497ac7db8.js>; rel=preload; as=script
Link: </component---src-templates-blog-post-js-517987eae96e75cddbe7.js>; rel=preload; as=script
/hello-world/
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </0-0180cd94ef2497ac7db8.js>; rel=preload; as=script
Link: </component---src-templates-blog-post-js-517987eae96e75cddbe7.js>; rel=preload; as=script
/404/
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </0-0180cd94ef2497ac7db8.js>; rel=preload; as=script
Link: </component---src-pages-404-js-53e6c51a5a7e73090f50.js>; rel=preload; as=script
/
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </0-0180cd94ef2497ac7db8.js>; rel=preload; as=script
Link: </component---src-pages-index-js-0bdd01c77ee09ef0224c.js>; rel=preload; as=script
/404.html
Link: </webpack-runtime-acaa8994f1f704475e21.js>; rel=preload; as=script
Link: </styles-565f081c8374bbda155f.js>; rel=preload; as=script
Link: </app-f33c13590352da20930f.js>; rel=preload; as=script
Link: </0-0180cd94ef2497ac7db8.js>; rel=preload; as=script
Link: </component---src-pages-404-js-53e6c51a5a7e73090f50.js>; rel=preload; as=script
"
`;

exports[`without caching headers 1`] = `
"## Created with gatsby-plugin-netlify
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,24 @@ test(`without caching headers`, async () => {
await fs.readFile(pluginData.publicFolder(`_headers`), `utf8`)
).toMatchSnapshot()
})

test(`with security headers`, async () => {
const pluginData = await createPluginData()

const pluginOptions = {
...DEFAULT_OPTIONS,
mergeSecurityHeaders: true,
headers: {
"/*": [
`Content-Security-Policy: frame-ancestors 'self' https://*.storyblok.com/`,
`X-Frame-Options: ALLOW-FROM https://app.storyblok.com/`,
],
},
}

await buildHeadersProgram(pluginData, pluginOptions)

expect(
await fs.readFile(pluginData.publicFolder(`_headers`), `utf8`)
).toMatchSnapshot()
})
31 changes: 29 additions & 2 deletions packages/gatsby-plugin-netlify/src/build-headers-program.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import {
NETLIFY_HEADERS_FILENAME,
} from "./constants"

function getHeaderName(header) {
const matches = header.match(/^([^:]+):/)
return matches && matches[1]
}

function validHeaders(headers) {
if (!headers || !_.isObject(headers)) {
return false
Expand All @@ -21,7 +26,10 @@ function validHeaders(headers) {
headers,
(headersList, path) =>
_.isArray(headersList) &&
_.every(headersList, header => _.isString(header))
_.every(
headersList,
header => _.isString(header) && getHeaderName(header)
)
)
}

Expand Down Expand Up @@ -97,6 +105,25 @@ function defaultMerge(...headers) {
return _.mergeWith({}, ...headers, unionMerge)
}

function headersMerge(userHeaders, defaultHeaders) {
const merged = {}
Object.keys(defaultHeaders).forEach(path => {
if (!userHeaders[path]) {
merged[path] = defaultHeaders[path]
return
}
const headersMap = {}
defaultHeaders[path].forEach(header => {
headersMap[getHeaderName(header)] = header
})
userHeaders[path].forEach(header => {
headersMap[getHeaderName(header)] = header // override if exists
})
merged[path] = Object.values(headersMap)
})
return merged
}

function transformLink(manifest, publicFolder, pathPrefix) {
return header =>
header.replace(LINK_REGEX, (__, prefix, file, suffix) => {
Expand Down Expand Up @@ -216,7 +243,7 @@ const applySecurityHeaders = ({ mergeSecurityHeaders }) => headers => {
return headers
}

return defaultMerge(headers, SECURITY_HEADERS)
return headersMerge(headers, SECURITY_HEADERS)
}

const applyCachingHeaders = (
Expand Down

0 comments on commit 8420626

Please sign in to comment.