1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- 'use strict';
- const extend = require('extend');
- const platform = require('platform');
- const utils = require('../utils');
- const HEADER = [
- 'x-content-security-policy',
- 'content-security-policy',
- ];
- const REPORT_ONLY_HEADER = [
- 'x-content-security-policy-report-only',
- 'content-security-policy-report-only',
- ];
- module.exports = options => {
- return async function csp(ctx, next) {
- await next();
- const opts = utils.merge(options, ctx.securityOptions.csp);
- if (utils.checkIfIgnore(opts, ctx)) return;
- let finalHeader;
- let value;
- const matchedOption = extend(true, {}, opts.policy);
- const isIE = platform.parse(ctx.header['user-agent']).name === 'IE';
- const bufArray = [];
- const headers = opts.reportOnly ? REPORT_ONLY_HEADER : HEADER;
- if (isIE && opts.supportIE) {
- finalHeader = headers[0];
- } else {
- finalHeader = headers[1];
- }
- for (const key in matchedOption) {
- value = matchedOption[key];
- value = Array.isArray(value) ? value : [ value ];
- // Other arrays are splitted into strings EXCEPT `sandbox`
- if (key === 'sandbox' && value[0] === true) {
- bufArray.push(key);
- } else {
- if (key === 'script-src') {
- const hasNonce = value.some(function(val) {
- return val.indexOf('nonce-') !== -1;
- });
- if (!hasNonce) {
- value.push('\'nonce-' + ctx.nonce + '\'');
- }
- }
- value = value.map(function(d) {
- if (d.startsWith('.')) {
- d = '*' + d;
- }
- return d;
- });
- bufArray.push(key + ' ' + value.join(' '));
- }
- }
- const headerString = bufArray.join(';');
- ctx.set(finalHeader, headerString);
- ctx.set('x-csp-nonce', ctx.nonce);
- };
- };
|