UNPKG

sails

Version:

API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)

444 lines (367 loc) 14 kB
/** * Module dependencies */ var assert = require('assert'); var fs = require('fs'); var path = require('path'); var _ = require('@sailshq/lodash'); var tmp = require('tmp'); var Sails = require('../../lib').constructor; var httpHelper = require('./helpers/httpHelper.js'); var appHelper = require('./helpers/appHelper'); describe('CSRF ::', function() { describe('Basic CSRF config ::', function() { var sailsConfig = {}; var sailsApp; beforeEach(function(done) { var _config = _.merge({ hooks: {grunt: false, views: false, blueprints: false, policies: false, i18n: false}, log: {level: 'error'}, routes: { '/csrfToken': {action: 'security/grant-csrf-token'}, 'ALL /viewtest/csrf': function(req, res) { var template = _.template('csrf=\'<%-_csrf%>\''); res.send(template(res.locals)); }, 'GET /user': function(req, res) { return res.sendStatus(200); }, 'POST /user': function(req, res) { return res.status(201).send(); }, 'POST /user/:id': function(req, res) { return res.sendStatus(200); } } }, sailsConfig); (new Sails()).load(_config, function(err, _sails) { sailsApp = _sails; return done(err); } ); }); afterEach(function(done) { sailsApp.lower(done); }); describe('with CSRF set to `false`', function() { before(function() { sailsConfig = {}; }); it('a blank CSRF token should be present in view locals', function(done) { sailsApp.request({url: '/viewtest/csrf', method: 'get'}, function(err, response) { if (err) { return done(err); } assert(response.body.indexOf('csrf=\'\'') !== -1, response.body); done(); }); }); }); describe('with CSRF set to `true`', function() { before(function() { sailsConfig = { security: { csrf: true } }; }); it('a HEAD request to a route with the CSRF used as a view local should not result in an error', function(done) { sailsApp.request({url: '/viewtest/csrf', method: 'head'}, function(err, response) { if (err) { return done(err); } done(); }); }); it('an OPTIONS request to a route with the CSRF used as a view local should not result in an error', function(done) { sailsApp.request({url: '/viewtest/csrf', method: 'options'}, function(err, response) { if (err) { return done(err); } done(); }); }); it('a CSRF token should be present in view locals', function(done) { sailsApp.request({url: '/viewtest/csrf', method: 'get'}, function(err, response) { if (err) { return done(err); } assert(response.body.match(/csrf='.{36}'/), response.body); done(); }); }); it('a request to /csrfToken should respond with a _csrf token', function(done) { sailsApp.request({url: '/csrftoken', method: 'get'}, function(err, response) { if (err) { return done(err); } assert(response.body._csrf, response.body); return done(); }); }); it('a POST request without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/user', method: 'post'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); it('a POST request with a valid CSRF token should result in a 201 response', function(done) { sailsApp.request({url: '/csrftoken', method: 'get'}, function(err, response) { if (err) { return done(err); } try { var body = response.body; var sid = response.headers['set-cookie'][0].split(';')[0].substr(10); sailsApp.request({ method: 'post', url: '/user', headers: { 'Content-type': 'application/json', 'cookie': 'sails.sid=' + sid }, data: {_csrf: body._csrf} }, function(err, response) { if (err) { return done(err); } assert.equal(response.statusCode, 201); done(); }); } catch (e) { done(e); } }); }); }); describe('with CSRF set to true, blacklisting \'POST /foo/:id, POST /bar/:id?, /user\'}', function() { before(function() { sailsConfig = { security: { csrf: true }, routes: { // Note -- since we don't actually define a target for these, requests that pass CSRF should return a 404. 'POST /foo/:id': {csrf: false}, '/bar/:id?': {csrf: false}, '/user': {csrf: false} } }; }); it('a POST request on /user without a CSRF token should result in a 201 response', function(done) { sailsApp.request({ method: 'post', url: '/user' }, function(err, response) { if (err) { return done(err); } assert.equal(response.statusCode, 201); done(); }); }); it('a POST request on /foo/12 without a CSRF token should result in a 404 response', function(done) { sailsApp.request({url: '/foo/12', method: 'post'}, function(err, response) { if (err && err.status === 404) { return done(); } done(new Error('Expected a 404 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /foo/12?abc=123 without a CSRF token should result in a 404 response', function(done) { sailsApp.request({url: '/foo/12?abc=123', method: 'post'}, function(err, response) { if (err && err.status === 404) { return done(); } done(new Error('Expected a 404 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /bar/12 without a CSRF token should result in a 404 response', function(done) { sailsApp.request({url: '/bar/12', method: 'post'}, function(err, response) { if (err && err.status === 404) { return done(); } done(new Error('Expected a 404 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /bar/12?abc=123 without a CSRF token should result in a 404 response', function(done) { sailsApp.request({url: '/bar/12?abc=123', method: 'post'}, function(err, response) { if (err && err.status === 404) { return done(); } done(new Error('Expected a 404 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /bar without a CSRF token should result in a 404 response', function(done) { sailsApp.request({url: '/bar', method: 'post'}, function(err, response) { if (err && err.status === 404) { return done(); } done(new Error('Expected a 404 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /bar?abc=123 without a CSRF token should result in a 404 response', function(done) { sailsApp.request({url: '/bar?abc=123', method: 'post'}, function(err, response) { if (err && err.status === 404) { return done(); } done(new Error('Expected a 404 error, instead got: ' + (err || response.body))); }); }); it('a PUT request on /foo/12 without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/foo/12', method: 'put'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /test without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/test', method: 'post'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /foo without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/foo', method: 'post'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); }); describe('with CSRF set to true, blacklisting \'POST /user\\/\\d+/\'', function() { before(function() { sailsConfig = { security: { csrf: true }, routes: { 'POST r|user/\\d+|': {csrf: false} } }; }); it('a POST request on /user/1 without a CSRF token should result in a 200 response', function(done) { sailsApp.request({url: '/user/1', method: 'post'}, function(err, response) { if (err) { return done(err); } assert.equal(response.statusCode, 200); done(); }); }); it('a PUT request on /user/1 without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/user/1', method: 'put'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /user/a without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/user/a', method: 'post'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /user without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/user', method: 'post'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); }); describe('with CSRF set to false, whitelisting \'/user\\/\\d+/\'', function() { before(function() { sailsConfig = { security: { csrf: false }, routes: { 'r|user/\\d+|': {csrf: true} } }; }); it('a POST request on /user/1 without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/user/1', method: 'post'}, function(err, response) { if (err && err.status === 403) { return done(); } done(new Error('Expected a 403 error, instead got: ' + (err || response.body))); }); }); it('a POST request on /user/a without a CSRF token should result in a 200 response', function(done) { sailsApp.request({url: '/user/a', method: 'post'}, function(err, response) { if (err) { return done(err); } assert.equal(response.statusCode, 200); done(); }); }); it('a POST request on /user without a CSRF token should result in a 201 response', function(done) { sailsApp.request({url: '/user', method: 'post'}, function(err, response) { if (err) { return done(err); } assert.equal(response.statusCode, 201); done(); }); }); }); describe('with CSRF set to true and sessions disabled', function() { before(function() { sailsConfig = { security: { csrf: false }, hooks: {session: false}, routes: { 'GET /user': {csrf: true, target: function(req, res) { return res.sendStatus(200); }}, 'POST /user': {csrf: true, target: function(req, res) { return res.status(201).send(); }} } }; }); it('a GET request on /user should result in a 200 response', function(done) { sailsApp.request({url: '/user', method: 'get'}, function(err, response) { if (err) { return done(err); } assert.equal(response.statusCode, 200); done(); }); }); it('a POST request on /user without a CSRF token should result in a 403 response', function(done) { sailsApp.request({url: '/user', method: 'post'}, function(err, response) { assert(err); assert.equal(err.status, 403); done(); }); }); }); }); //</describe('CSRF config ::')> describe('With CSRF set to `true` globally and the session hook disabled :: ', function() { it('should fail to lift', function(done) { (new Sails()).load({security: {csrf: true}, hooks: {session: false}}, function(err, _sails) { if (err) { return done(); } _sails.lower(function() { return done(new Error('Sails lifted successfully, but it should have failed!')); }); } ); }); }); });