mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-13 22:41:32 -05:00
e4a1797085
no issue - removes should-sinon dependency from package.json - rewrites all usages of should-sinon to use normal should assertions Unfortunately, should-sinon has very minimal documentation and therefore it is hard to discern what is considered a correctly-written assertion: - in some cases, refactoring to use should-sinon causes false positives - in other cases, assertions that work written in the normal way fail when written using should-sinon (e.g. getters, combos with rewire) The additional overhead created by these issues outweigh any benefit from the easier-to-read assertions
220 lines
6.3 KiB
JavaScript
220 lines
6.3 KiB
JavaScript
/*globals describe, beforeEach, afterEach, it*/
|
|
var should = require('should'),
|
|
sinon = require('sinon'),
|
|
middleware = require('../../../server/middleware').middleware;
|
|
|
|
describe('Middleware: spamPrevention', function () {
|
|
var sandbox,
|
|
req,
|
|
next,
|
|
error,
|
|
spyNext;
|
|
|
|
beforeEach(function () {
|
|
sandbox = sinon.sandbox.create();
|
|
error = null;
|
|
|
|
next = sinon.spy();
|
|
|
|
spyNext = sinon.spy(function (param) {
|
|
error = param;
|
|
});
|
|
});
|
|
|
|
afterEach(function () {
|
|
sandbox.restore();
|
|
});
|
|
|
|
describe('signin', function () {
|
|
beforeEach(function () {
|
|
req = {
|
|
connection: {
|
|
remoteAddress: '10.0.0.0'
|
|
},
|
|
body: {
|
|
username: 'tester',
|
|
grant_type: 'password'
|
|
}
|
|
};
|
|
});
|
|
|
|
it('calls next if refreshing the token', function (done) {
|
|
req.body.grant_type = 'refresh_token';
|
|
middleware.spamPrevention.signin(req, null, next);
|
|
|
|
next.calledOnce.should.be.true();
|
|
done();
|
|
});
|
|
|
|
it ('creates a BadRequestError when there\'s no username', function (done) {
|
|
req.body = {};
|
|
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
|
|
should.exist(error);
|
|
error.errorType.should.eql('BadRequestError');
|
|
done();
|
|
});
|
|
|
|
it ('rate limits after 10 attempts', function (done) {
|
|
for (var ndx = 0; ndx < 10; ndx = ndx + 1) {
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
}
|
|
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
should.exist(error);
|
|
error.errorType.should.eql('TooManyRequestsError');
|
|
|
|
done();
|
|
});
|
|
|
|
it ('allows more attempts after an hour', function (done) {
|
|
var ndx,
|
|
stub = sinon.stub(process, 'hrtime', function () {
|
|
return [10, 10];
|
|
});
|
|
|
|
for (ndx = 0; ndx < 10; ndx = ndx + 1) {
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
}
|
|
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
error.errorType.should.eql('TooManyRequestsError');
|
|
error = null;
|
|
|
|
// fast forward 1 hour
|
|
process.hrtime.restore();
|
|
stub = sinon.stub(process, 'hrtime', function () {
|
|
return [3700000, 10];
|
|
});
|
|
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
should(error).equal(undefined);
|
|
spyNext.called.should.be.true();
|
|
|
|
process.hrtime.restore();
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe('forgotten', function () {
|
|
beforeEach(function () {
|
|
req = {
|
|
connection: {
|
|
remoteAddress: '10.0.0.0'
|
|
},
|
|
body: {
|
|
passwordreset: [
|
|
{email:'test@ghost.org'}
|
|
]
|
|
}
|
|
};
|
|
});
|
|
|
|
it ('send a bad request if no email is specified', function (done) {
|
|
req.body = {
|
|
passwordreset: [{}]
|
|
};
|
|
|
|
middleware.spamPrevention.forgotten(req, null, spyNext);
|
|
error.errorType.should.eql('BadRequestError');
|
|
|
|
done();
|
|
});
|
|
|
|
it ('creates an unauthorized error after 5 attempts with same email', function (done) {
|
|
for (var ndx = 0; ndx < 6; ndx = ndx + 1) {
|
|
middleware.spamPrevention.forgotten(req, null, spyNext);
|
|
}
|
|
|
|
middleware.spamPrevention.forgotten(req, null, spyNext);
|
|
error.errorType.should.eql('TooManyRequestsError');
|
|
|
|
done();
|
|
});
|
|
|
|
it ('creates an unauthorized error after 5 attempts from the same ip', function (done) {
|
|
var ndx, email;
|
|
|
|
for (ndx = 0; ndx < 6; ndx = ndx + 1) {
|
|
email = 'test' + String(ndx) + '@ghost.org';
|
|
req.body.passwordreset = [
|
|
{email: email}
|
|
];
|
|
|
|
middleware.spamPrevention.forgotten(req, null, spyNext);
|
|
}
|
|
|
|
middleware.spamPrevention.forgotten(req, null, spyNext);
|
|
error.errorType.should.eql('TooManyRequestsError');
|
|
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe('protected', function () {
|
|
var res;
|
|
|
|
beforeEach(function () {
|
|
res = sinon.spy();
|
|
req = {
|
|
connection: {
|
|
remoteAddress: '10.0.0.0'
|
|
},
|
|
body: {
|
|
password: 'password'
|
|
}
|
|
};
|
|
});
|
|
|
|
it ('sets an error when there is no password', function (done) {
|
|
req.body = {};
|
|
|
|
middleware.spamPrevention.protected(req, res, spyNext);
|
|
res.error.message.should.equal('No password entered');
|
|
spyNext.calledOnce.should.be.true();
|
|
|
|
done();
|
|
});
|
|
|
|
it ('sets and error message after 10 tries', function (done) {
|
|
var ndx;
|
|
|
|
for (ndx = 0; ndx < 10; ndx = ndx + 1) {
|
|
middleware.spamPrevention.protected(req, res, spyNext);
|
|
}
|
|
|
|
should.not.exist(res.error);
|
|
middleware.spamPrevention.protected(req, res, spyNext);
|
|
should.exist(res.error);
|
|
should.exist(res.error.message);
|
|
|
|
done();
|
|
});
|
|
|
|
it ('allows more tries after an hour', function (done) {
|
|
var ndx,
|
|
stub = sinon.stub(process, 'hrtime', function () {
|
|
return [10, 10];
|
|
});
|
|
|
|
for (ndx = 0; ndx < 11; ndx = ndx + 1) {
|
|
middleware.spamPrevention.protected(req, res, spyNext);
|
|
}
|
|
|
|
should.exist(res.error);
|
|
process.hrtime.restore();
|
|
stub = sinon.stub(process, 'hrtime', function () {
|
|
return [3610000, 10];
|
|
});
|
|
|
|
res = sinon.spy();
|
|
|
|
middleware.spamPrevention.protected(req, res, spyNext);
|
|
should.not.exist(res.error);
|
|
|
|
process.hrtime.restore();
|
|
done();
|
|
});
|
|
});
|
|
});
|