2021-02-15 08:42:51 +00:00
const config = require ( './config' )
2021-02-16 21:21:13 +00:00
const { v4 : uuidv4 } = require ( 'uuid' )
2021-09-14 19:09:32 +00:00
const { buildDomainOriginWithProtocol } = require ( './config/buildDomainOriginWithProtocol' )
2017-10-21 23:22:48 +00:00
2021-02-15 08:42:51 +00:00
const CspStrategy = { }
2017-10-21 23:22:48 +00:00
2021-02-15 08:42:51 +00:00
const defaultDirectives = {
2021-07-06 19:17:56 +00:00
defaultSrc : [ '\'none\'' ] ,
baseUri : [ '\'self\'' ] ,
2021-09-14 19:09:32 +00:00
connectSrc : [ '\'self\'' , buildDomainOriginWithProtocol ( config , 'ws' ) ] ,
2021-07-06 19:17:56 +00:00
fontSrc : [ '\'self\'' ] ,
2021-08-06 10:11:53 +00:00
manifestSrc : [ '\'self\'' ] ,
2021-08-06 10:11:08 +00:00
frameSrc : [ '\'self\'' , 'https://player.vimeo.com' , 'https://www.slideshare.net/slideshow/embed_code/key/' , 'https://www.youtube.com' ] ,
2021-07-06 19:17:56 +00:00
imgSrc : [ '*' ] , // we allow using arbitrary images
scriptSrc : [
config . serverURL + '/build/' ,
config . serverURL + '/js/' ,
config . serverURL + '/config' ,
'https://gist.github.com/' ,
'https://vimeo.com/api/oembed.json' ,
'https://www.slideshare.net/api/oembed/2' ,
'\'unsafe-inline\'' // this is ignored by browsers supporting nonces/hashes
] ,
2021-08-06 10:09:20 +00:00
styleSrc : [ config . serverURL + '/build/' , config . serverURL + '/css/' , '\'unsafe-inline\'' , 'https://github.githubassets.com' ] , // unsafe-inline is required for some libs, plus used in views
2017-10-21 23:22:48 +00:00
objectSrc : [ '*' ] , // Chrome PDF viewer treats PDFs as objects :/
2021-08-14 22:35:57 +00:00
formAction : [ '\'self\'' ] ,
mediaSrc : [ '*' ]
2017-10-21 23:22:48 +00:00
}
2021-02-15 08:42:51 +00:00
const disqusDirectives = {
2018-12-05 12:14:34 +00:00
scriptSrc : [ 'https://disqus.com' , 'https://*.disqus.com' , 'https://*.disquscdn.com' ] ,
2018-03-30 14:33:32 +00:00
styleSrc : [ 'https://*.disquscdn.com' ] ,
fontSrc : [ 'https://*.disquscdn.com' ]
}
2021-02-15 08:42:51 +00:00
const googleAnalyticsDirectives = {
2018-03-30 14:33:32 +00:00
scriptSrc : [ 'https://www.google-analytics.com' ]
}
2021-02-15 08:42:51 +00:00
const dropboxDirectives = {
2020-08-22 23:29:53 +00:00
scriptSrc : [ 'https://www.dropbox.com' , '\'unsafe-inline\'' ]
2020-08-22 23:11:31 +00:00
}
2021-07-18 07:59:14 +00:00
const disallowFramingDirectives = {
frameAncestors : [ '\'self\'' ]
}
2021-08-06 10:58:22 +00:00
const allowPDFEmbedDirectives = {
objectSrc : [ '*' ] , // Chrome and Firefox treat PDFs as objects
frameSrc : [ '*' ] // Chrome also checks PDFs against frame-src
}
2022-04-03 20:47:42 +00:00
const configuredGitLabInstanceDirectives = {
connectSrc : [ config . gitlab . baseURL ]
}
2017-10-21 23:22:48 +00:00
CspStrategy . computeDirectives = function ( ) {
2021-02-15 08:42:51 +00:00
const directives = { }
2017-10-21 23:22:48 +00:00
mergeDirectives ( directives , config . csp . directives )
mergeDirectivesIf ( config . csp . addDefaults , directives , defaultDirectives )
2018-03-30 14:33:32 +00:00
mergeDirectivesIf ( config . csp . addDisqus , directives , disqusDirectives )
mergeDirectivesIf ( config . csp . addGoogleAnalytics , directives , googleAnalyticsDirectives )
2020-08-22 23:11:31 +00:00
mergeDirectivesIf ( config . dropbox . appKey , directives , dropboxDirectives )
2021-07-18 07:59:14 +00:00
mergeDirectivesIf ( ! config . csp . allowFraming , directives , disallowFramingDirectives )
2021-08-06 10:58:22 +00:00
mergeDirectivesIf ( config . csp . allowPDFEmbed , directives , allowPDFEmbedDirectives )
2022-04-03 20:47:42 +00:00
mergeDirectivesIf ( config . isGitlabSnippetsEnable , directives , configuredGitLabInstanceDirectives )
2021-07-06 19:17:56 +00:00
addInlineScriptExceptions ( directives )
2017-10-21 23:22:48 +00:00
addUpgradeUnsafeRequestsOptionTo ( directives )
2018-03-10 13:34:14 +00:00
addReportURI ( directives )
2017-10-21 23:22:48 +00:00
return directives
}
function mergeDirectives ( existingDirectives , newDirectives ) {
2021-02-15 08:42:51 +00:00
for ( const propertyName in newDirectives ) {
const newDirective = newDirectives [ propertyName ]
2017-10-21 23:22:48 +00:00
if ( newDirective ) {
2021-02-15 08:42:51 +00:00
const existingDirective = existingDirectives [ propertyName ] || [ ]
2017-10-21 23:22:48 +00:00
existingDirectives [ propertyName ] = existingDirective . concat ( newDirective )
}
}
}
function mergeDirectivesIf ( condition , existingDirectives , newDirectives ) {
if ( condition ) {
mergeDirectives ( existingDirectives , newDirectives )
}
}
function addInlineScriptExceptions ( directives ) {
directives . scriptSrc . push ( getCspNonce )
// TODO: This is the SHA-256 hash of the inline script in build/reveal.js/plugins/notes/notes.html
// Any more clean solution appreciated.
2020-02-01 11:50:07 +00:00
directives . scriptSrc . push ( '\'sha256-81acLZNZISnyGYZrSuoYhpzwDTTxi7vC1YM4uNxqWaM=\'' )
2017-10-21 23:22:48 +00:00
}
function getCspNonce ( req , res ) {
2021-08-05 21:06:28 +00:00
return '\'nonce-' + res . locals . nonce + '\''
2017-10-21 23:22:48 +00:00
}
function addUpgradeUnsafeRequestsOptionTo ( directives ) {
2021-07-18 07:59:14 +00:00
if ( config . csp . upgradeInsecureRequests === 'auto' && ( config . useSSL || config . protocolUseSSL ) ) {
2021-05-04 09:10:53 +00:00
directives . upgradeInsecureRequests = [ ]
2017-10-21 23:22:48 +00:00
} else if ( config . csp . upgradeInsecureRequests === true ) {
2021-05-04 09:10:53 +00:00
directives . upgradeInsecureRequests = [ ]
2017-10-21 23:22:48 +00:00
}
}
2018-03-10 13:34:14 +00:00
function addReportURI ( directives ) {
if ( config . csp . reportURI ) {
directives . reportUri = config . csp . reportURI
}
}
2017-10-21 23:22:48 +00:00
CspStrategy . addNonceToLocals = function ( req , res , next ) {
2021-02-16 21:21:13 +00:00
res . locals . nonce = uuidv4 ( )
2017-10-21 23:22:48 +00:00
next ( )
}
module . exports = CspStrategy