2021-02-15 03:42:51 -05:00
const config = require ( './config' )
2021-02-16 16:21:13 -05:00
const { v4 : uuidv4 } = require ( 'uuid' )
2017-10-21 19:22:48 -04:00
2021-02-15 03:42:51 -05:00
const CspStrategy = { }
2017-10-21 19:22:48 -04:00
2021-02-15 03:42:51 -05:00
const defaultDirectives = {
2021-07-06 15:17:56 -04:00
defaultSrc : [ '\'none\'' ] ,
baseUri : [ '\'self\'' ] ,
connectSrc : [ '\'self\'' ] ,
fontSrc : [ '\'self\'' ] ,
2021-08-06 06:11:53 -04:00
manifestSrc : [ '\'self\'' ] ,
2021-08-06 06:11:08 -04:00
frameSrc : [ '\'self\'' , 'https://player.vimeo.com' , 'https://www.slideshare.net/slideshow/embed_code/key/' , 'https://www.youtube.com' ] ,
2021-07-06 15:17:56 -04: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 06:09:20 -04: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 19:22:48 -04:00
objectSrc : [ '*' ] , // Chrome PDF viewer treats PDFs as objects :/
2021-08-14 18:35:57 -04:00
formAction : [ '\'self\'' ] ,
mediaSrc : [ '*' ]
2017-10-21 19:22:48 -04:00
}
2021-02-15 03:42:51 -05:00
const disqusDirectives = {
2018-12-05 07:14:34 -05:00
scriptSrc : [ 'https://disqus.com' , 'https://*.disqus.com' , 'https://*.disquscdn.com' ] ,
2018-03-30 10:33:32 -04:00
styleSrc : [ 'https://*.disquscdn.com' ] ,
fontSrc : [ 'https://*.disquscdn.com' ]
}
2021-02-15 03:42:51 -05:00
const googleAnalyticsDirectives = {
2018-03-30 10:33:32 -04:00
scriptSrc : [ 'https://www.google-analytics.com' ]
}
2021-02-15 03:42:51 -05:00
const dropboxDirectives = {
2020-08-22 19:29:53 -04:00
scriptSrc : [ 'https://www.dropbox.com' , '\'unsafe-inline\'' ]
2020-08-22 19:11:31 -04:00
}
2021-07-18 03:59:14 -04:00
const disallowFramingDirectives = {
frameAncestors : [ '\'self\'' ]
}
2021-08-06 06:58:22 -04:00
const allowPDFEmbedDirectives = {
objectSrc : [ '*' ] , // Chrome and Firefox treat PDFs as objects
frameSrc : [ '*' ] // Chrome also checks PDFs against frame-src
}
2017-10-21 19:22:48 -04:00
CspStrategy . computeDirectives = function ( ) {
2021-02-15 03:42:51 -05:00
const directives = { }
2017-10-21 19:22:48 -04:00
mergeDirectives ( directives , config . csp . directives )
mergeDirectivesIf ( config . csp . addDefaults , directives , defaultDirectives )
2018-03-30 10:33:32 -04:00
mergeDirectivesIf ( config . csp . addDisqus , directives , disqusDirectives )
mergeDirectivesIf ( config . csp . addGoogleAnalytics , directives , googleAnalyticsDirectives )
2020-08-22 19:11:31 -04:00
mergeDirectivesIf ( config . dropbox . appKey , directives , dropboxDirectives )
2021-07-18 03:59:14 -04:00
mergeDirectivesIf ( ! config . csp . allowFraming , directives , disallowFramingDirectives )
2021-08-06 06:58:22 -04:00
mergeDirectivesIf ( config . csp . allowPDFEmbed , directives , allowPDFEmbedDirectives )
2021-07-06 15:17:56 -04:00
addInlineScriptExceptions ( directives )
2017-10-21 19:22:48 -04:00
addUpgradeUnsafeRequestsOptionTo ( directives )
2018-03-10 08:34:14 -05:00
addReportURI ( directives )
2017-10-21 19:22:48 -04:00
return directives
}
function mergeDirectives ( existingDirectives , newDirectives ) {
2021-02-15 03:42:51 -05:00
for ( const propertyName in newDirectives ) {
const newDirective = newDirectives [ propertyName ]
2017-10-21 19:22:48 -04:00
if ( newDirective ) {
2021-02-15 03:42:51 -05:00
const existingDirective = existingDirectives [ propertyName ] || [ ]
2017-10-21 19:22:48 -04: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 06:50:07 -05:00
directives . scriptSrc . push ( '\'sha256-81acLZNZISnyGYZrSuoYhpzwDTTxi7vC1YM4uNxqWaM=\'' )
2017-10-21 19:22:48 -04:00
}
function getCspNonce ( req , res ) {
2021-08-05 17:06:28 -04:00
return '\'nonce-' + res . locals . nonce + '\''
2017-10-21 19:22:48 -04:00
}
function addUpgradeUnsafeRequestsOptionTo ( directives ) {
2021-07-18 03:59:14 -04:00
if ( config . csp . upgradeInsecureRequests === 'auto' && ( config . useSSL || config . protocolUseSSL ) ) {
2021-05-04 05:10:53 -04:00
directives . upgradeInsecureRequests = [ ]
2017-10-21 19:22:48 -04:00
} else if ( config . csp . upgradeInsecureRequests === true ) {
2021-05-04 05:10:53 -04:00
directives . upgradeInsecureRequests = [ ]
2017-10-21 19:22:48 -04:00
}
}
2018-03-10 08:34:14 -05:00
function addReportURI ( directives ) {
if ( config . csp . reportURI ) {
directives . reportUri = config . csp . reportURI
}
}
2017-10-21 19:22:48 -04:00
CspStrategy . addNonceToLocals = function ( req , res , next ) {
2021-02-16 16:21:13 -05:00
res . locals . nonce = uuidv4 ( )
2017-10-21 19:22:48 -04:00
next ( )
}
module . exports = CspStrategy