2022-06-15 00:43:25 +03:00
import helmet from 'helmet'
import { cloneDeep } from 'lodash-es'
import isArchivedVersion from '../lib/is-archived-version.js'
import versionSatisfiesRange from '../lib/version-satisfies-range.js'
const isDev = process . env . NODE _ENV === 'development'
const AZURE _STORAGE _URL = 'githubdocs.azureedge.net'
const GITHUB _DOMAINS = [
"'self'" ,
'github.com' ,
'*.github.com' ,
'*.githubusercontent.com' ,
'*.githubassets.com' ,
]
const DEFAULT _OPTIONS = {
crossOriginResourcePolicy : true ,
crossOriginEmbedderPolicy : false , // doesn't work with youtube
referrerPolicy : {
2023-01-20 00:45:19 +03:00
policy : 'no-referrer-when-downgrade' , // See docs-engineering #2426
2022-06-15 00:43:25 +03:00
} ,
// This module defines a Content Security Policy (CSP) to disallow
// inline scripts and content from untrusted sources.
contentSecurityPolicy : {
directives : {
defaultSrc : [ "'none'" ] ,
prefetchSrc : [ "'self'" ] ,
// When doing local dev, especially in Safari, you need to add `ws:`
// which NextJS uses for the hot module reloading.
connectSrc : [ "'self'" , isDev && 'ws:' ] . filter ( Boolean ) ,
fontSrc : [ "'self'" , 'data:' , AZURE _STORAGE _URL ] ,
imgSrc : [ ... GITHUB _DOMAINS , 'data:' , AZURE _STORAGE _URL , 'placehold.it' ] ,
objectSrc : [ "'self'" ] ,
// For use during development only!
// `unsafe-eval` allows us to use a performant webpack devtool setting (eval)
// https://webpack.js.org/configuration/devtool/#devtool
2022-10-25 22:03:38 +03:00
scriptSrc : [ "'self'" , 'data:' , AZURE _STORAGE _URL , isDev && "'unsafe-eval'" ] . filter ( Boolean ) ,
2022-06-15 00:43:25 +03:00
frameSrc : [
... GITHUB _DOMAINS ,
isDev && 'http://localhost:3000' ,
2023-03-29 15:38:47 +03:00
// This URL is also set in ArticleContext.tsx. We don't rely on importing a constant as we may run into an import conflict where the env variable is not yet set.
process . env . NODE _ENV === 'production'
? 'https://support.github.com'
: // Assume that a developer is not testing the VA iframe locally if this env var is not set
process . env . SUPPORT _PORTAL _URL || '' ,
2022-06-15 00:43:25 +03:00
'https://www.youtube-nocookie.com' ,
] . filter ( Boolean ) ,
2023-01-24 22:43:25 +03:00
frameAncestors : isDev ? [ '*' ] : [ ... GITHUB _DOMAINS ] ,
2022-10-25 22:03:38 +03:00
styleSrc : [ "'self'" , "'unsafe-inline'" , 'data:' , AZURE _STORAGE _URL ] ,
2022-06-15 00:43:25 +03:00
childSrc : [ "'self'" ] , // exception for search in deprecated GHE versions
2023-05-31 15:05:37 +03:00
manifestSrc : [ "'self'" ] ,
2022-08-08 18:19:46 +03:00
upgradeInsecureRequests : isDev ? null : [ ] ,
2022-06-15 00:43:25 +03:00
} ,
} ,
}
const NODE _DEPRECATED _OPTIONS = cloneDeep ( DEFAULT _OPTIONS )
const { directives : ndDirs } = NODE _DEPRECATED _OPTIONS . contentSecurityPolicy
ndDirs . scriptSrc . push (
"'unsafe-eval'" ,
"'unsafe-inline'" ,
'http://www.google-analytics.com' ,
2023-07-11 14:44:52 +03:00
'https://ssl.google-analytics.com' ,
2022-06-15 00:43:25 +03:00
)
ndDirs . connectSrc . push ( 'https://www.google-analytics.com' )
ndDirs . imgSrc . push ( 'http://www.google-analytics.com' , 'https://ssl.google-analytics.com' )
const STATIC _DEPRECATED _OPTIONS = cloneDeep ( DEFAULT _OPTIONS )
STATIC _DEPRECATED _OPTIONS . contentSecurityPolicy . directives . scriptSrc . push ( "'unsafe-inline'" )
const defaultHelmet = helmet ( DEFAULT _OPTIONS )
const nodeDeprecatedHelmet = helmet ( NODE _DEPRECATED _OPTIONS )
const staticDeprecatedHelmet = helmet ( STATIC _DEPRECATED _OPTIONS )
export default function helmetMiddleware ( req , res , next ) {
// Enable CORS
if ( [ 'GET' , 'OPTIONS' ] . includes ( req . method ) ) {
res . set ( 'access-control-allow-origin' , '*' )
}
// Determine version for exceptions
const { requestedVersion } = isArchivedVersion ( req )
// Exception for deprecated Enterprise docs (Node.js era)
if (
versionSatisfiesRange ( requestedVersion , '<=2.19' ) &&
versionSatisfiesRange ( requestedVersion , '>2.12' )
) {
return nodeDeprecatedHelmet ( req , res , next )
}
// Exception for search in deprecated Enterprise docs <=2.12 (static site era)
if ( versionSatisfiesRange ( requestedVersion , '<=2.12' ) ) {
return staticDeprecatedHelmet ( req , res , next )
}
return defaultHelmet ( req , res , next )
}