Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

csp-header

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

csp-header - npm Package Compare versions

Comparing version 0.0.4 to 1.0.0

test/fixtures/presets/csp-preset-test.js

107

index.js

@@ -1,2 +0,2 @@

var allowedPolicies = [
const allowedPolicies = [
'base-uri',

@@ -34,19 +34,17 @@ 'block-all-mixed-content',

function buildCSPString(policies, reportUri){
var cspString = Object.keys(policies).map(function(policyName){
let cspString = Object.keys(policies).map(policyName => {
if(policies[policyName] === true || policies[policyName].length === 0){
return policyName;
}
return policyName + ' ' + policies[policyName].join(' ');
}).join('; ') + ';';
return `${policyName} ${policies[policyName].join(' ')}`;
}).join('; ');
if(typeof reportUri === 'string'){
cspString += ' report-uri ' + reportUri + ';';
cspString += `; report-uri ${reportUri}`;
}
return cspString;
return `${cspString};`;
}
function csp(params){
var policies;
// params should be an object

@@ -57,9 +55,12 @@ if(typeof params !== 'object'){

// property policies is required
if(typeof params.policies !== 'object'){
return;
if (!params.policies) {
if (params.presets || params.extend) {
params.policies = {};
} else {
return;
}
}
// filter disallowed policies
policies = Object.keys(params.policies).reduce(function(policies, policyName){
let policies = Object.keys(params.policies).reduce((policies, policyName) => {
if(allowedPolicies.indexOf(policyName) > -1){

@@ -73,2 +74,20 @@ if(params.policies[policyName] !== false){

if (params.presets) {
params.presets.forEach(preset => {
let presetPolicies;
if (typeof preset === 'string') {
presetPolicies = requirePreset(preset);
} else {
presetPolicies = preset;
}
policies = extendPolicies(policies, presetPolicies);
});
}
if (params.extend) {
policies = extendPolicies(policies, params.extend);
}
return buildCSPString(policies, params['report-uri']);

@@ -78,2 +97,54 @@ }

/**
* Resolves require string
* @param {string} presetName Relative/absolute path or full/short module name
* @returns {string}
*/
function resolvePreset(presetName) {
const isFullModuleName = presetName.indexOf('csp-preset') === 0;
if (isFullModuleName) {
return presetName;
} else {
return `csp-preset-${presetName}`;
}
}
function requirePreset(presetName) {
try {
return require(resolvePreset(presetName));
} catch(err) {
throw new Error(`CSP preset ${presetName} is not found`);
}
}
/**
* Extends policies object
* @param {Object} original Original policies
* @param {Object} extension Additional policies
* @returns {Object} Extended policies
*/
function extendPolicies(original, extension){
const extended = Object.assign(original);
Object.keys(extension).forEach(policyName => {
const extPolicy = extension[policyName];
const origPolicy = original[policyName];
if (origPolicy === undefined) {
extended[policyName] = extPolicy;
} else if(Array.isArray(extPolicy) && extPolicy.length > 0 && Array.isArray(origPolicy)){
extPolicy.forEach(rule => {
if(typeof rule === 'string' && origPolicy.indexOf(rule) === -1){
extended[policyName].push(rule);
}
});
} else {
extended[policyName] = extPolicy[policyName];
}
});
return extended;
}
/**
* Build nonce param

@@ -84,10 +155,12 @@ * @param nonceId {string} Nonce param id

csp.nonce = function(nonceId){
return '\'nonce-' + nonceId + '\'';
return `'nonce-${nonceId}'`;
};
csp.NONE = '\'none\'';
csp.SELF = '\'self\'';
csp.INLINE = '\'unsafe-inline\'';
csp.EVAL = '\'unsafe-eval\'';
csp.resolvePreset = resolvePreset;
csp.NONE = "'none'";
csp.SELF = "'self'";
csp.INLINE = "'unsafe-inline'";
csp.EVAL = "'unsafe-eval'";
module.exports = csp;

10

package.json
{
"name": "csp-header",
"version": "0.0.4",
"version": "1.0.0",
"description": "Content-Security-Policy header generator",
"main": "index.js",
"scripts": {
"test": "mocha test"
"test": "ava"
},

@@ -17,5 +17,7 @@ "keywords": [

"license": "WTFPL",
"engines": {
"node": ">=4"
},
"devDependencies": {
"mocha": "^2.4.5",
"should": "^8.3.0"
"ava": "^0.18.2"
},

@@ -22,0 +24,0 @@ "directories": {

@@ -6,3 +6,3 @@ # csp-header

```js
var csp = require('csp-header');
const csp = require('csp-header');
csp({

@@ -21,3 +21,3 @@ policies: {

]
},
}
'report-uri': 'https://cspreport.com/send'

@@ -28,1 +28,37 @@ });

```
## Extending
If you want to extend your config by some rules:
```js
const myCSPPolicies = require('./my-csp-rules');
csp({
policies: myCSPPolicies,
extend: {
'connect-src': ['test.com']
}
});
```
## Presets
You can use csp presets prefixed by 'csp-preset'. If you have a web-service it would be great if you write preset with rules for your service users.
E.g. your service is called ``my-super-service.com``. You publish preset ``csp-preset-my-super-service`` containing following code:
```js
modules.exports = {
'script-src': ['api.my-super-service.com'],
'img-src': ['images.my-super-service.com']
};
```
Then someone wants to configure its CSP to work with your service. And now it's so easy:
```js
const myCSPPolicies = require('./my-csp-rules');
csp({
policies: myCSPPolicies,
presets: ['my-super-service']
});
```
And you will get a lot of thanks ;)

@@ -1,77 +0,130 @@

var should = require('should');
var csp = require('../index');
import test from 'ava';
import csp from '../index';
describe('Input params', function(){
it('should returns undefined if params was not specified', function(){
should(csp()).be.type('undefined');
test('Empty args', t => {
t.is(csp(), undefined);
});
test('Empty policies', t => {
const actual = csp({
nonce: true,
foo: 'bar'
});
t.is(actual, undefined);
});
it('should returns undefined if policies property was not specified', function(){
should(csp({
nonce: true,
foo: 'bar'
})).be.type('undefined');
test('Disallowed policies', t => {
const actual = csp({
policies: {
'script-src': [ 'test.com', csp.SELF ],
'foo-bar-src': [ 'foo', 'bar' ]
}
});
const expected = "script-src test.com 'self';";
t.is(actual, expected);
});
it('should ignore disallowed policies', function(){
csp({
policies: {
'script-src': [ 'test.com', csp.SELF ],
'foo-bar-src': [ 'foo', 'bar' ]
}
}).should.be.equal('script-src test.com \'self\';');
test('report-uri', t => {
const actual = csp({
policies: {
'script-src': [ csp.SELF ]
},
'report-uri': 'https://test.com/cspreport'
})
const expected = "script-src 'self'; report-uri https://test.com/cspreport;";
t.is(actual, expected);
});
test('Valueless directives', t => {
const actualTrue = csp({
policies: {
'script-src': ['test.com'],
'block-all-mixed-content': true
}
});
it('should add report-uri param', function(){
csp({
policies: {
'script-src': [ csp.SELF ]
},
'report-uri': 'https://test.com/cspreport'
}).should.be.equal('script-src \'self\'; report-uri https://test.com/cspreport;');
const actualEmptyArray = csp({
policies: {
'script-src': ['test.com'],
'block-all-mixed-content': []
}
});
it('should support valueless directives', function(){
csp({
policies: {
'script-src': [ 'test.com' ],
'block-all-mixed-content': true
}
}).should.be.equal('script-src test.com; block-all-mixed-content;');
const actualEmptyString = csp({
policies: {
'script-src': ['test.com'],
'block-all-mixed-content': ''
}
});
csp({
policies: {
'script-src': [ 'test.com' ],
'block-all-mixed-content': []
}
}).should.be.equal('script-src test.com; block-all-mixed-content;');
const expected = 'script-src test.com; block-all-mixed-content;';
csp({
policies: {
'script-src': [ 'test.com' ],
'block-all-mixed-content': ''
}
}).should.be.equal('script-src test.com; block-all-mixed-content;');
t.is(actualTrue, expected);
t.is(actualEmptyArray, expected);
t.is(actualEmptyString, expected);
});
test('Presets | extend', t => {
const actual = csp({
presets: [require('./fixtures/presets/csp-preset-test')]
});
t.is(actual, 'script-src test.com; style-src test.com;');
});
describe('Utils', function(){
it('should build nonce param', function(){
csp.nonce('vg3eer#E4gEbw34gwq3fgqGQWBWQh').should.be.equal('\'nonce-vg3eer#E4gEbw34gwq3fgqGQWBWQh\'');
test('Presets | resolve', t => {
t.is(csp.resolvePreset('csp-preset-test'), 'csp-preset-test');
t.is(csp.resolvePreset('test'), 'csp-preset-test');
});
test('Extend | new rule', t => {
const actual = csp({
policies: {
'script-src': [ 'myhost.com' ]
},
extend: {
'script-src': [ 'additional.host.com' ]
}
});
describe('Constants', function(){
it('should contains \'self\'', function(){
csp.SELF.should.be.equal('\'self\'');
});
it('should contains \'unsafe-inline\'', function(){
csp.INLINE.should.be.equal('\'unsafe-inline\'');
});
it('should contains \'unsafe-eval\'', function(){
csp.EVAL.should.be.equal('\'unsafe-eval\'');
});
it('should contains \'none\'', function(){
csp.NONE.should.be.equal('\'none\'');
});
t.is(actual, 'script-src myhost.com additional.host.com;');
});
test('Extend | duplicating', t => {
const actual = csp({
policies: {
'script-src': [ 'myhost.com' ]
},
extend: {
'script-src': [ 'myhost.com' ]
}
});
t.is(actual, 'script-src myhost.com;');
});
test('Extend | new policy', t => {
const actual = csp({
policies: {
'script-src': [ 'myhost.com' ]
},
extend: {
'style-src': [ 'newhost.com' ]
}
});
t.is(actual, 'script-src myhost.com; style-src newhost.com;');
});
test('Nonce', t => {
const actual = csp.nonce('vg3eer#E4gEbw34gwq3fgqGQWBWQh');
const expected = "'nonce-vg3eer#E4gEbw34gwq3fgqGQWBWQh'"
t.is(actual, expected);
});
test('Constants', t => {
t.is(csp.SELF, "'self'");
t.is(csp.INLINE, "'unsafe-inline'");
t.is(csp.EVAL, "'unsafe-eval'");
t.is(csp.NONE, "'none'");
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc