Skip to content

Commit

Permalink
🐛 subscriber: sanitize email vol. 2 (#8280)
Browse files Browse the repository at this point in the history
no issue


🐛  subscriber: sanitize email vol. 2
- ensure email get's sanitized for every error case

🐛  validator.isEmptyOrURL doesn't accept non strings
- otherwise it shows a weird error message in the client

✨  new tests for subscriber app
- routing tests

* change tests for Ghost 1.0
* it took me 15min to find this 😡
  • Loading branch information
kirrg001 authored and ErisDS committed Apr 5, 2017
1 parent 64d2a94 commit 38fe4d2
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 24 deletions.
11 changes: 8 additions & 3 deletions core/server/apps/subscribers/lib/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,16 @@ function controller(req, res) {
return res.render(templates.pickTemplate(templateName, defaultTemplate), data);
}

/**
* Takes care of sanitizing the email input.
* XSS prevention.
* For success cases, we don't have to worry, because then the input contained a valid email address.
*/
function errorHandler(error, req, res, next) {
/*jshint unused:false */

req.body.email = '';

if (error.statusCode !== 404) {
res.locals.error = error;
return controller(req, res);
Expand All @@ -44,7 +51,7 @@ function honeyPot(req, res, next) {
}

function santizeUrl(url) {
return validator.isEmptyOrURL(url) ? url : '';
return validator.isEmptyOrURL(url || '') ? url : '';
}

function handleSource(req, res, next) {
Expand Down Expand Up @@ -76,8 +83,6 @@ function storeSubscriber(req, res, next) {
if (_.isEmpty(req.body.email)) {
return next(new errors.ValidationError({message: 'Email cannot be blank.'}));
} else if (!validator.isEmail(req.body.email)) {
// sanitize email
req.body.email = '';
return next(new errors.ValidationError({message: 'Invalid email.'}));
}

Expand Down
18 changes: 0 additions & 18 deletions core/server/apps/subscribers/tests/router_spec.js

This file was deleted.

122 changes: 122 additions & 0 deletions core/server/apps/subscribers/tests/routing_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
var supertest = require('supertest'),
should = require('should'),
sinon = require('sinon'),
testUtils = require('../../../../test/utils'),
labs = require('../../../utils/labs'),
config = require('../../../config'),
ghost = testUtils.startGhost,
sandbox = sinon.sandbox.create();

describe('Subscriber: Routing', function () {
var ghostServer, request;

before(function (done) {
ghost().then(function (_ghostServer) {
ghostServer = _ghostServer;
return ghostServer.start();
}).then(function () {
request = supertest.agent(config.get('url'));
done();
}).catch(function (e) {
console.log('Ghost Error: ', e);
console.log(e.stack);
done(e);
});
});

after(function () {
return ghostServer.stop();
});

before(function () {
sandbox.stub(labs, 'isSet', function (key) {
if (key === 'subscribers') {
return true;
}
});
});

after(function () {
sandbox.restore();
});

describe('GET', function () {
it('[success]', function (done) {
request.get('/subscribe/')
.expect(200)
.end(function (err) {
should.not.exist(err);
done();
});
});
});

describe('POST', function () {
it('[success]', function (done) {
request.post('/subscribe/')
.set('Content-type', 'application/x-www-form-urlencoded')
.send({
email: 'test@ghost.org',
location: 'http://localhost:2368',
confirm: ''
})
.expect(200)
.end(function (err, res) {
should.not.exist(err);
res.text.should.containEql('Subscribed!');
res.text.should.containEql('test@ghost.org');
done();
});
});

it('[error] email is invalid', function (done) {
request.post('/subscribe/')
.set('Content-type', 'application/x-www-form-urlencoded')
.send({
email: 'alphabetazeta',
location: 'http://localhost:2368',
confirm: ''
})
.expect(200)
.end(function (err, res) {
should.not.exist(err);
res.text.should.containEql('http://localhost:2368');
res.text.should.not.containEql('Subscribed!');
res.text.should.not.containEql('alphabetazeta');
done();
});
});

it('[error] location is not defined', function (done) {
request.post('/subscribe/')
.set('Content-type', 'application/x-www-form-urlencoded')
.send({
email: 'test@ghost.org',
confirm: ''
})
.expect(200)
.end(function (err, res) {
should.not.exist(err);
res.text.should.not.containEql('Subscribed!');
res.text.should.not.containEql('test@ghost.org');
done();
});
});

it('[error] confirm is not defined', function (done) {
request.post('/subscribe/')
.set('Content-type', 'application/x-www-form-urlencoded')
.send({
email: 'test@ghost.org',
location: 'http://localhost:2368'
})
.expect(200)
.end(function (err, res) {
should.not.exist(err);
res.text.should.not.containEql('Subscribed!');
res.text.should.not.containEql('test@ghost.org');
done();
});
});
});
});
2 changes: 1 addition & 1 deletion core/test/unit/auth/validation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('UNIT: auth validation', function () {
models.init();
});

beforeEach(function () {
afterEach(function () {
sandbox.restore();
});

Expand Down
4 changes: 2 additions & 2 deletions core/test/unit/scheduling/post-scheduling/index_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ describe('Scheduling: Post Scheduling', function () {

sandbox.stub(schedulingUtils, 'createAdapter').returns(Promise.resolve(scope.adapter));

models.Client.findOne = function () {
sandbox.stub(models.Client, 'findOne', function () {
return Promise.resolve(scope.client);
};
});

sandbox.spy(scope.adapter, 'schedule');
sandbox.spy(scope.adapter, 'reschedule');
Expand Down

0 comments on commit 38fe4d2

Please sign in to comment.