New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

fi-aegis

Package Overview
Dependencies
Maintainers
2
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fi-aegis - npm Package Compare versions

Comparing version 1.1.0 to 2.0.0

.eslintrc

7

CHANGELOG.md

@@ -0,1 +1,8 @@

#### v1.1.0
* Added CSRF `safeVerbs` option.
* Multiple code improvements.
* Improved code docs.
#### v1.0.2

@@ -2,0 +9,0 @@

74

index.js

@@ -1,73 +0,1 @@

'use strict';
/**
* Fi Aegis.
*
* @module fi-aegis
*
* @see module:fi-aegis
*/
/**
* Configures the module.
*
* @param {Object} options The options object.
* @param {Object} options.csp The options for the `csp` module.
* @param {Object} options.csrf The options for the `csrf` module.
* @param {Object} options.hsts The options for the `hsts` module.
* @param {Boolean} options.nosniff Whether to activate the `nosniff` module.
* @param {String} options.p3p The header value for the `p3p` module.
* @param {String} options.xframes The header value for the `xframe` module.
* @param {Object} options.xssprotection The options for the `xssprotection`
* module.
*
* @returns {Function} The Express middleware.
*/
var aegis = module.exports = options => {
const components = [];
if (options) {
Object.keys(aegis).forEach(key => {
let config = options[key];
if (config) {
components.push(aegis[key](config));
}
});
}
/**
* Fi Aegis middleware.
*
* @param {Object} req Express request object.
* @param {Object} res Express response object.
* @param {Function} next Express next middleware callback.
*/
function middleware(req, res, next) {
var chain = next;
components.forEach(component => {
chain = (next => err => {
if (err) {
return next(err);
}
component(req, res, next);
})(chain);
});
chain();
}
return middleware;
};
aegis.csrf = require('./lib/csrf');
aegis.csp = require('./lib/csp');
aegis.hsts = require('./lib/hsts');
aegis.p3p = require('./lib/p3p');
aegis.xframe = require('./lib/xframes');
aegis.xssProtection = require('./lib/xssprotection');
aegis.nosniff = require('./lib/nosniff');
module.exports = require('./lib');

@@ -10,8 +10,6 @@ /**

'use strict';
const { CSP_INVALID_POLICY } = require('./errors');
const ERR = require('./errors');
let header, value;
var value, name;
/**

@@ -24,5 +22,4 @@ * CSP middleware.

*/
function middleware(req, res, next) {
res.header(name, value);
function middleware (req, res, next) {
res.header(header, value);
next();

@@ -32,2 +29,33 @@ }

/**
* Creates a CSP policy string.
*
* @param {Array|Object|String} policy The policy object to parse.
*
* @returns {String} The CSP policy string.
*/
function createPolicyString (policy) {
if (typeof policy === 'string') {
return policy;
}
if (Array.isArray(policy)) {
return policy.map(csp.createPolicyString).join('; ');
}
if (typeof policy === 'object' && policy !== null) {
let entries = Object.keys(policy).map(directive => {
if (policy[String(directive)] === 0 || policy[String(directive)]) {
directive += ` ${policy[String(directive)]}`;
}
return directive;
});
return csp.createPolicyString(entries);
}
throw new Error(CSP_INVALID_POLICY);
}
/**
* Configures the CSP module.

@@ -42,7 +70,6 @@ *

*/
function csp(options) {
var reportUri, policyRules;
function csp (options) {
let reportUri, policyRules;
let isReportOnly = false;
var isReportOnly = false;
if (options) {

@@ -54,6 +81,6 @@ isReportOnly = options.reportOnly;

name = 'content-security-policy';
header = 'Content-Security-Policy';
if (isReportOnly) {
name += '-report-only';
header += '-Report-Only';
}

@@ -70,3 +97,3 @@

value += 'report-uri ' + reportUri;
value += `report-uri ${reportUri}`;
}

@@ -77,37 +104,4 @@

/**
* Creates a CSP policy string.
*
* @param {Array|Object|String} policy The policy object to parse.
*
* @returns {String} The CSP policy string.
*/
function createPolicyString(policy) {
var entries;
if (typeof policy === 'string') {
return policy;
}
if (Array.isArray(policy)) {
return policy.map(csp.createPolicyString).join('; ');
}
if (typeof policy === 'object' && policy !== null) {
entries = Object.keys(policy).map(directive => {
if (policy[directive] === 0 || policy[directive]) {
directive += ' ' + policy[directive];
}
return directive;
});
return csp.createPolicyString(entries);
}
throw new Error(ERR.CSP_INVALID_POLICY);
}
csp.createPolicyString = createPolicyString;
module.exports = csp;
module.exports = csp;

@@ -10,9 +10,6 @@ /**

'use strict';
const { CSRF_TOKEN_MISSING, CSRF_TOKEN_MISMATCH } = require('./errors');
const token = require('./token');
const ERR = require('./errors');
const CONFIG = {
const config = {
safeVerbs: null,

@@ -34,6 +31,6 @@ cookie: null,

*/
function getCsrf(req, secret) {
var csrf = CONFIG.impl.create(req, secret);
var validate = CONFIG.impl.validate || csrf.validate;
var token = csrf.token || csrf;
function getCsrf (req, secret) {
const csrf = config.impl.create(req, secret);
const validate = config.impl.validate || csrf.validate;
const token = csrf.token || csrf;

@@ -55,7 +52,7 @@ secret = csrf.secret;

*/
function setToken(res, token) {
res.locals[CONFIG.key] = token;
function setToken (res, token) {
res.locals[config.key] = token;
if (CONFIG.cookie && CONFIG.cookie.name) {
res.cookie(CONFIG.cookie.name, token, CONFIG.cookie.options);
if (config.cookie && config.cookie.name) {
res.cookie(config.cookie.name, token, config.cookie.options);
}

@@ -73,7 +70,6 @@ }

*/
function middleware(req, res, next) {
var csrf = getCsrf(req, CONFIG.secret);
function middleware (req, res, next) {
let csrf = getCsrf(req, config.secret);
let token;
var token;
setToken(res, csrf.token);

@@ -87,3 +83,3 @@

req.csrfToken = () => {
var newCsrf = getCsrf(req, CONFIG.secret);
let newCsrf = getCsrf(req, config.secret);

@@ -102,10 +98,15 @@ if (csrf.secret && newCsrf.secret && csrf.secret === newCsrf.secret) {

/* Move along for safe verbs */
if (CONFIG.safeVerbs.indexOf(req.method) >= 0) {
if (config.safeVerbs.indexOf(req.method) >= 0) {
return next();
}
/* Validate token */
token = (req.body && req.body[CONFIG.key]) ||
req.headers[CONFIG.header];
token = (req.body && req.body[String(config.key)]) ||
req.headers[String(config.header)];
if (!token) {
console.info(req.headers);
}
if (csrf.validate(req, token)) {

@@ -115,11 +116,9 @@ return next();

console.log(req.body, req.headers[CONFIG.header]);
res.status(403);
next(new Error(!token ? ERR.CSRF_TOKEN_MISSING : ERR.CSRF_TOKEN_MISMATCH));
next(new Error(!token ? CSRF_TOKEN_MISSING : CSRF_TOKEN_MISMATCH));
}
/**
* Confures the CSRF module.
* Configures the CSRF module.
*

@@ -141,13 +140,10 @@ * @param {Object} options The options object.

*/
module.exports = options => {
options = options || {};
module.exports = (options = {}) => {
/* Initialize defaults */
CONFIG.header = (options.header || 'csrf-token').toLowerCase(); // https://stackoverflow.com/a/5259004/1970170
CONFIG.safeVerbs = options.safeVerbs || ['OPTIONS', 'HEAD', 'GET'];
CONFIG.secret = options.secret || '_csrfSecret';
CONFIG.impl = options.impl || token;
CONFIG.key = options.key || '_csrf';
CONFIG.cookie = {
config.header = (options.header || 'csrf-token').toLowerCase();
config.safeVerbs = options.safeVerbs || ['OPTIONS', 'HEAD', 'GET'];
config.secret = options.secret || '_csrfSecret';
config.impl = options.impl || token;
config.key = options.key || '_csrf';
config.cookie = {
options: options.cookie && options.cookie.options,

@@ -159,12 +155,11 @@ name: 'CSRF-TOKEN'

if (options.angular) {
CONFIG.cookie.name = 'XSRF-TOKEN';
CONFIG.header = 'x-xsrf-token';
config.cookie.name = 'XSRF-TOKEN';
config.header = 'x-xsrf-token';
} else if (typeof options.cookie === 'string') {
CONFIG.cookie.name = options.cookie;
config.cookie.name = options.cookie;
} else if (options.cookie && typeof options.cookie.name === 'string') {
CONFIG.cookie.name = options.cookie.name;
config.cookie.name = options.cookie.name;
}
return middleware;
};
};

@@ -1,3 +0,1 @@

'use strict';
/**

@@ -10,15 +8,11 @@ * Prefixes error string for easier debugging.

*/
function msg(message) {
return `Fi Aegis: ${ message }`;
function msg (message) {
return `Fi Aegis: ${message}`;
}
module.exports = {
SESSION_INVALID: msg('A valid session must be available in order to maintain state!'),
CSP_INVALID_POLICY: msg('Invalid CSP policy! Must be Array, String, or Object.'),
CSRF_TOKEN_MISMATCH: msg('CSRF token mismatch!'),
CSRF_TOKEN_MISSING: msg('CSRF token missing!')
};
};

@@ -10,8 +10,4 @@ /**

'use strict';
let value;
const HEADER = 'strict-transport-security';
var value;
/**

@@ -24,5 +20,5 @@ * HSTS Middleware.

*/
function middleware(req, res, next) {
function middleware (req, res, next) {
if (value) {
res.header(HEADER, value);
res.header('Strict-Transport-Security', value);
}

@@ -44,6 +40,3 @@

*/
module.exports = options => {
options = options || {};
module.exports = (options = {}) => {
if (typeof options.maxAge !== undefined) {

@@ -54,3 +47,3 @@ options.maxAge = Math.max(0, parseInt(options.maxAge));

if (options.maxAge > -1) {
value = 'max-age=' + options.maxAge;
value = `max-age=${options.maxAge}`;

@@ -67,3 +60,2 @@ if (options.includeSubDomains) {

return middleware;
};
};

@@ -10,7 +10,2 @@ /**

'use strict';
const HEADER = 'x-content-type-options';
const VALUE = 'nosniff';
/**

@@ -23,5 +18,4 @@ * Nosniff Middleware.

*/
function middleware(req, res, next) {
res.header(HEADER, VALUE);
function middleware (req, res, next) {
res.header('X-Content-Type-Options', 'nosniff');
next();

@@ -31,6 +25,6 @@ }

/**
* Configures the Nosniff module.
* Configures the NoSniff module.
*
* @returns {Function} The Express middleware.
*/
module.exports = () => middleware;
module.exports = () => middleware;

@@ -1,6 +0,4 @@

'use strict';
const crypto = require('crypto');
const ERR = require('./errors');
const { SESSION_INVALID } = require('./errors');

@@ -17,4 +15,8 @@ const LENGTH = 10;

*/
function tokenize(salt, secret) {
return salt + crypto.createHash('sha1').update(salt + secret).digest('base64');
function tokenize (salt, secret) {
const hash = crypto.createHash('sha1')
.update(`${salt}${secret}`)
.digest('base64');
return `${salt}${hash}`;
}

@@ -25,15 +27,19 @@

*
* @param {Number} len The salt's length.
* @param {Number} length The salt's length.
*
* @returns {String} The generated salt.
*/
function salt(len) {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var str = '';
function salt (length) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const randomBytes = crypto.randomBytes(length);
const result = new Array(length);
for (var i = 0; i < len; i++) {
str += chars[Math.floor(Math.random() * chars.length)];
let cursor = 0;
for (let i = 0; i < length; i++) {
cursor += randomBytes[parseInt(i)];
result[parseInt(i)] = chars[parseInt(cursor % chars.length)];
}
return str;
return result.join('');
}

@@ -50,3 +56,3 @@

*/
function validate(secretKey, req, token) {
function validate (secretKey, req, token) {
if (typeof token !== 'string') {

@@ -56,3 +62,6 @@ return false;

return token === tokenize(token.slice(0, LENGTH), req.session[secretKey]);
const key = req.session[String(secretKey)];
const slice = token.slice(0, LENGTH);
return token === tokenize(slice, key);
}

@@ -68,15 +77,15 @@

*/
function create(req, secretKey) {
var session = req.session;
function create (req, secretKey) {
const { session } = req;
if (session === undefined) {
throw new Error(ERR.SESSION_INVALID);
if (!session) {
throw new Error(SESSION_INVALID);
}
/* Save the secret for validation */
var secret = session[secretKey];
let secret = session[String(secretKey)];
if (!secret) {
session[secretKey] = crypto.pseudoRandomBytes(LENGTH).toString('base64');
secret = session[secretKey];
session[String(secretKey)] = crypto.randomBytes(LENGTH).toString('base64');
secret = session[String(secretKey)];
}

@@ -91,4 +100,2 @@

module.exports = {
create: create
};
module.exports = { create };

@@ -10,8 +10,4 @@ /**

'use strict';
let value;
const HEADER = 'x-frame-options';
var value;
/**

@@ -24,5 +20,5 @@ * X-Frame-Options middleware.

*/
function middleware(req, res, next) {
function middleware (req, res, next) {
if (value) {
res.header(HEADER, value);
res.header('X-Frame-Options', value);
}

@@ -41,7 +37,5 @@

module.exports = val => {
value = val;
return middleware;
};
};

@@ -10,8 +10,4 @@ /**

'use strict';
let value;
const HEADER = 'x-xss-protection';
var value;
/**

@@ -24,5 +20,5 @@ * X-Frame-Options middleware.

*/
function middleware(req, res, next) {
function middleware (req, res, next) {
if (value) {
res.header(HEADER, value);
res.header('X-XSS-Protection', value);
}

@@ -44,6 +40,3 @@

*/
module.exports = options => {
options = options || {};
module.exports = (options = {}) => {
/* IMPORTANT: `enabled` should be either `1` or `0` */

@@ -60,3 +53,3 @@ if (typeof options === 'boolean') {

var mode = 'block';
let mode = 'block';

@@ -67,6 +60,5 @@ if (options && options.mode && typeof options.mode === 'string') {

value += '; mode=' + mode;
value += `; mode=${mode}`;
return middleware;
};
};
{
"name": "fi-aegis",
"version": "1.1.0",
"version": "2.0.0",
"description": "Web Application Security Middleware.",
"author": "Jeff Harrell <jeharrell@paypal.com>",
"homepage": "https://github.com/finaldevstudio/fi-aegis",
"author": "Santiago G. Marín <santiago.marin@dotstudio.io>",
"homepage": "https://github.com/dotstudio-io/fi-aegis",
"main": "index",
"license": "MIT",
"scripts": {
"test": "node_modules/.bin/mocha"
"test": "nyc mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/finaldevstudio/fi-aegis.git"
"url": "git+https://github.com/dotstudio-io/fi-aegis.git"
},
"contributors": [
"Santiago G. Marín <santiago@finaldevstudio.com>"
"Santiago G. Marín <santiago.marin@dotstudio.io>"
],
"engines": {
"node": ">=4.0.0",
"npm": ">=3.0.0"
"node": "12",
"npm": ">=6"
},
"dependencies": {},
"devDependencies": {
"body-parser": "^1.6.3",
"chance": "^1.0.10",
"cookie-parser": "^1.3.2",
"cookie-session": "^1.0.2",
"data-driven": "^1.0.0",
"errorhandler": "^1.1.1",
"express": "^4.3.8",
"express-session": "^1.7.5",
"mocha": "^3.4.2",
"supertest": "^3.0.0"
"body-parser": "^1.19.0",
"chance": "^1.1.4",
"cookie-parser": "^1.4.4",
"cookie-session": "^1.3.3",
"data-driven": "^1.4.0",
"errorhandler": "^1.5.1",
"eslint-plugin-mocha": "^6.2.2",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-security": "^1.4.0",
"express": "^4.17.1",
"express-session": "^1.17.0",
"mocha": "^6.2.2",
"nyc": "^15.0.0",
"supertest": "^4.0.2"
},
"bugs": {
"url": "https://github.com/finaldevstudio/fi-aegis/issues",
"email": "security@finaldevstudio.com"
"url": "https://github.com/dotstudio-io/fi-aegis/issues",
"email": "security@dotstudio.io"
},

@@ -40,0 +44,0 @@ "directories": {

@@ -44,15 +44,14 @@ # Fi Aegis

app.use(aegis({
csrf: true,
csp: {
xframe: 'SAMEORIGIN',
xssProtection: true,
nosniff: true,
csrf: {
angular: true
},
xframe: 'SAMEORIGIN',
p3p: 'ABCDEF', /*[DEPRECATED]*/
csp: ,
hsts: {
includeSubDomains: true,
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
xssProtection: true,
nosniff: true
}
}));

@@ -105,5 +104,5 @@ ```

| `angular` | `Boolean` | No | `false` | Shorthand setting to set **Fi Aegis** up to use the default settings for CSRF validation according to the [AngularJS docs](https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection). |
| `cookie` | `String` or `Object` | No | `Object` | If set, a cookie with the name you provide will be set with the CSRF token. |
| `cookie` | `String` or `Object` | No | `Object` | A cookie with the name you provide will be set with the CSRF token. |
| `cookie.name` | `String` | No | `CSRF-TOKEN` | The name you provide will be set as the cookie with the CSRF token. |
| `cookie.options` | `Object` | No | `{}` | A valid Express cookie options object. See [Express' res.cookie](http://expressjs.com/en/4x/api.html#res.cookie) API docs for more information. |
| `cookie.options` | `Object` | No | `{}` | A valid Express cookie options object. See [Express res.cookie](http://expressjs.com/en/4x/api.html#res.cookie) API docs for more information. |
| `header` | `String` | No | `csrf-token` | If set, the header name you provide will be expected to have the CSRF token. |

@@ -293,2 +292,2 @@ | `safeVerbs` | `[String]` | No | `['OPTIONS', 'HEAD', 'GET']` | A list of HTTP verbs cosidered `safe` that will skip CSRF token validation.

|-------|------|----------|---------|-------------|
| `value` | `String` | Yes | None | The compact privacy policy. |
| `value` | `String` | Yes | None | The compact privacy policy. |
# Security Policy
Security is a very important part of our applications and therefore must be treated seriously and professionaly.
Security is a very important part of our applications and therefore must be treated seriously and professionally.

@@ -8,5 +8,5 @@

If you think you may have found a bug or flaw please [open an issue](https://github.com/FinalDevStudio/fi-aegis/issues/new) so everyone can help solve it as quickly as possible.
If you think you may have found a bug or flaw please[open an issue](https://github.com/dotstudio-io/fi-aegis/issues/new) so everyone can help solve it as quickly as possible.
If the issue is too risky to be put out in the open, please send us an email with the details to [security@finaldevstudio.com](mailto:security@finaldevstudio.com).
If the issue is too risky to be put out in the open, please send us an email with the details to [santiago.marin@dotstudio.io](mailto:santiago.marin@dotstudio.io).

@@ -18,7 +18,4 @@

If you feel we're not responding back in time, please send an email directly to [santiago@finaldevstudio.com](mailto:santiago@finaldevstudio.com) with a link to the issue or indicating that a previous message was sent.
## History
No reported issues.
No reported issues.
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