2015-05-26 22:04:27 +03:00
|
|
|
/*globals describe, beforeEach, afterEach, it*/
|
|
|
|
var should = require('should'),
|
|
|
|
sinon = require('sinon'),
|
|
|
|
middleware = require('../../../server/middleware').middleware;
|
2016-02-08 00:27:01 +03:00
|
|
|
require('should-sinon');
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2016-02-08 00:27:01 +03:00
|
|
|
next.calledOnce.should.be.true();
|
2015-05-26 22:04:27 +03:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
|
|
|
|
it ('creates a BadRequestError when there\'s no username', function (done) {
|
|
|
|
req.body = {};
|
|
|
|
|
|
|
|
middleware.spamPrevention.signin(req, null, spyNext);
|
|
|
|
|
|
|
|
should.exist(error);
|
2016-02-08 00:27:01 +03:00
|
|
|
error.errorType.should.eql('BadRequestError');
|
2015-05-26 22:04:27 +03:00
|
|
|
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);
|
2016-02-08 00:27:01 +03:00
|
|
|
error.errorType.should.eql('TooManyRequestsError');
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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);
|
2016-02-08 00:27:01 +03:00
|
|
|
error.errorType.should.eql('TooManyRequestsError');
|
2015-05-26 22:04:27 +03:00
|
|
|
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);
|
2016-02-15 01:48:20 +03:00
|
|
|
spyNext.should.be.called();
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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);
|
2016-02-08 00:27:01 +03:00
|
|
|
error.errorType.should.eql('BadRequestError');
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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);
|
2016-02-08 00:27:01 +03:00
|
|
|
error.errorType.should.eql('TooManyRequestsError');
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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);
|
2016-02-08 00:27:01 +03:00
|
|
|
error.errorType.should.eql('TooManyRequestsError');
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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');
|
2016-02-08 00:27:01 +03:00
|
|
|
spyNext.should.be.calledOnce();
|
2015-05-26 22:04:27 +03:00
|
|
|
|
|
|
|
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();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|