mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-29 07:09:48 +03:00
Revert "Restore spam prevention"
This commit is contained in:
parent
7ce22416c6
commit
5c1a7a7349
@ -245,15 +245,7 @@ errors = {
|
||||
}
|
||||
errors.renderErrorPage(err.status || 500, err, req, res, next);
|
||||
} else {
|
||||
// generate a valid JSON response
|
||||
var statusCode = 500,
|
||||
errorContent = {};
|
||||
|
||||
statusCode = err.code || 500;
|
||||
|
||||
errorContent.message = _.isString(err) ? err : (_.isObject(err) ? err.message : 'Unknown Error');
|
||||
errorContent.type = err.type || 'InternalServerError';
|
||||
res.json(statusCode, errorContent);
|
||||
res.send(err.status || 500, err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -9,13 +9,11 @@ var _ = require('lodash'),
|
||||
path = require('path'),
|
||||
api = require('../api'),
|
||||
passport = require('passport'),
|
||||
errors = require('../errors'),
|
||||
|
||||
expressServer,
|
||||
oauthServer,
|
||||
ONE_HOUR_MS = 60 * 60 * 1000,
|
||||
ONE_YEAR_MS = 365 * 24 * ONE_HOUR_MS,
|
||||
loginSecurity = [];
|
||||
ONE_YEAR_MS = 365 * 24 * ONE_HOUR_MS;
|
||||
|
||||
function isBlackListedFileType(file) {
|
||||
var blackListedFileTypes = ['.hbs', '.md', '.json'],
|
||||
@ -151,31 +149,6 @@ var middleware = {
|
||||
});
|
||||
},
|
||||
|
||||
// ### Spam prevention Middleware
|
||||
// limit signin requests to one every two seconds
|
||||
spamPrevention: function (req, res, next) {
|
||||
var currentTime = process.hrtime()[0],
|
||||
remoteAddress = req.connection.remoteAddress,
|
||||
denied = '';
|
||||
|
||||
// filter for IPs that tried to login in the last 2 sec
|
||||
loginSecurity = _.filter(loginSecurity, function (logTime) {
|
||||
return (logTime.time + 2 > currentTime);
|
||||
});
|
||||
|
||||
// check if IP tried to login in the last 2 sec
|
||||
denied = _.find(loginSecurity, function (logTime) {
|
||||
return (logTime.ip === remoteAddress);
|
||||
});
|
||||
|
||||
if (!denied) {
|
||||
loginSecurity.push({ip: remoteAddress, time: currentTime});
|
||||
next();
|
||||
} else {
|
||||
return next(new errors.UnauthorizedError('Slow down, there are way too many login attempts!'));
|
||||
}
|
||||
},
|
||||
|
||||
// work around to handle missing client_secret
|
||||
// oauth2orize needs it, but untrusted clients don't have it
|
||||
addClientSecret: function (req, res, next) {
|
||||
@ -184,15 +157,9 @@ var middleware = {
|
||||
}
|
||||
next();
|
||||
},
|
||||
|
||||
// ### Authenticate Client Middleware
|
||||
// authenticate client that is asking for an access token
|
||||
authenticateClient: function (req, res, next) {
|
||||
return passport.authenticate(['oauth2-client-password'], { session: false })(req, res, next);
|
||||
},
|
||||
|
||||
// ### Generate access token Middleware
|
||||
// register the oauth2orize middleware for password and refresh token grants
|
||||
generateAccessToken: function (req, res, next) {
|
||||
return oauthServer.token()(req, res, next);
|
||||
},
|
||||
|
@ -43,8 +43,8 @@ oauth = {
|
||||
}).catch(function () {
|
||||
return done(null, false);
|
||||
});
|
||||
}).catch(function (error) {
|
||||
return done(error);
|
||||
}).catch(function () {
|
||||
return done(null, false);
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
@ -270,16 +270,15 @@ User = ghostBookshelf.Model.extend({
|
||||
var self = this,
|
||||
s;
|
||||
return this.getByEmail(object.email).then(function (user) {
|
||||
if (!user || user.get('status') === 'invited' || user.get('status') === 'invited-pending'
|
||||
|| user.get('status') === 'inactive') {
|
||||
return when.reject(new errors.NotFoundError('NotFound'));
|
||||
if (!user || user.get('status') === 'invited' || user.get('status') === 'inactive') {
|
||||
return when.reject(new Error('NotFound'));
|
||||
}
|
||||
if (user.get('status') !== 'locked') {
|
||||
return nodefn.call(bcrypt.compare, object.password, user.get('password')).then(function (matched) {
|
||||
if (!matched) {
|
||||
return when(self.setWarning(user)).then(function (remaining) {
|
||||
s = (remaining > 1) ? 's' : '';
|
||||
return when.reject(new errors.UnauthorizedError('Your password is incorrect.<br>' +
|
||||
return when.reject(new Error('Your password is incorrect.<br>' +
|
||||
remaining + ' attempt' + s + ' remaining!'));
|
||||
});
|
||||
}
|
||||
@ -289,7 +288,7 @@ User = ghostBookshelf.Model.extend({
|
||||
});
|
||||
}, errors.logAndThrowError);
|
||||
}
|
||||
return when.reject(new errors.NoPermissionError('Your account is locked due to too many ' +
|
||||
return when.reject(new Error('Your account is locked due to too many ' +
|
||||
'login attempts. Please reset your password to log in again by clicking ' +
|
||||
'the "Forgotten password?" link!'));
|
||||
|
||||
|
@ -73,7 +73,6 @@ apiRoutes = function (middleware) {
|
||||
router.post('/authentication/setup', api.http(api.authentication.setup));
|
||||
router.get('/authentication/setup', api.http(api.authentication.isSetup));
|
||||
router.post('/authentication/token',
|
||||
middleware.spamPrevention,
|
||||
middleware.addClientSecret,
|
||||
middleware.authenticateClient,
|
||||
middleware.generateAccessToken
|
||||
|
@ -4,35 +4,35 @@
|
||||
/*globals CasperTest, casper, url, newUser, user, falseUser */
|
||||
|
||||
// TODO fix signup vs setup testing
|
||||
CasperTest.begin('Ensure a User is Registered', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('setup', function checkUrl() {
|
||||
test.assertUrlMatch(/ghost\/setup\/$/, 'Landed on the correct URL');
|
||||
});
|
||||
|
||||
casper.waitForOpaque('.setup-box',
|
||||
function then() {
|
||||
this.fillAndAdd('#setup', newSetup);
|
||||
},
|
||||
function onTimeout() {
|
||||
test.fail('Set up form didn\'t fade in.');
|
||||
});
|
||||
|
||||
casper.captureScreenshot('login_register_test.png');
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'already registered');
|
||||
// If the previous assert succeeds, then we should skip the next check and just pass.
|
||||
casper.echoConcise('Already registered!');
|
||||
casper.captureScreenshot('already_registered.png');
|
||||
}, function onTimeout() {
|
||||
test.assertUrlMatch(/ghost\/\d+\/$/, 'If we\'re not already registered, we should be logged in.');
|
||||
casper.echoConcise('Successfully registered.');
|
||||
}, 2000);
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('signout', function then() {
|
||||
test.assertUrlMatch(/ghost\/signin/, 'We got redirected to signin page.');
|
||||
});
|
||||
}, true);
|
||||
//CasperTest.begin('Ensure a User is Registered', 3, function suite(test) {
|
||||
// casper.thenOpenAndWaitForPageLoad('signup', function checkUrl() {
|
||||
// test.assertUrlMatch(/ghost\/signup\/$/, 'Landed on the correct URL');
|
||||
// });
|
||||
//
|
||||
// casper.waitForOpaque('.signup-box',
|
||||
// function then() {
|
||||
// this.fillAndSave('#signup', newUser);
|
||||
// },
|
||||
// function onTimeout() {
|
||||
// test.fail('Sign up form didn\'t fade in.');
|
||||
// });
|
||||
//
|
||||
// casper.captureScreenshot('login_register_test.png');
|
||||
//
|
||||
// casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
// test.assertSelectorHasText('.notification-error', 'already registered');
|
||||
// // If the previous assert succeeds, then we should skip the next check and just pass.
|
||||
// casper.echoConcise('Already registered!');
|
||||
// casper.captureScreenshot('already_registered.png');
|
||||
// }, function onTimeout() {
|
||||
// test.assertUrlMatch(/ghost\/\d+\/$/, 'If we\'re not already registered, we should be logged in.');
|
||||
// casper.echoConcise('Successfully registered.');
|
||||
// }, 2000);
|
||||
//
|
||||
// casper.thenOpenAndWaitForPageLoad('signout', function then() {
|
||||
// test.assertUrlMatch(/ghost\/signin/, 'We got redirected to signin page.');
|
||||
// });
|
||||
//}, true);
|
||||
|
||||
CasperTest.begin('Ghost admin will load login page', 3, function suite(test) {
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
@ -59,84 +59,73 @@ CasperTest.begin('Redirects login to signin', 2, function suite(test) {
|
||||
});
|
||||
}, true);
|
||||
|
||||
// TODO: please uncomment when the spam prevention bug is fixed (https://github.com/TryGhost/Ghost/issues/3128)
|
||||
// CasperTest.begin('Can\'t spam it', 4, function suite(test) {
|
||||
// casper.thenOpenAndWaitForPageLoad('signin', function testTitle() {
|
||||
// test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
// test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
// });
|
||||
|
||||
CasperTest.begin('Can\'t spam it', 4, function suite(test) {
|
||||
// init user to prevent redirect to setup
|
||||
CasperTest.Routines.setup.run(test);
|
||||
CasperTest.Routines.signout.run(test);
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function testTitle() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
});
|
||||
|
||||
casper.waitForOpaque('.login-box',
|
||||
function then() {
|
||||
this.fillAndSave('#login', falseUser);
|
||||
},
|
||||
function onTimeout() {
|
||||
test.fail('Sign in form didn\'t fade in.');
|
||||
});
|
||||
// casper.waitForOpaque('.login-box',
|
||||
// function then() {
|
||||
// this.fillAndSave('#login', falseUser);
|
||||
// },
|
||||
// function onTimeout() {
|
||||
// test.fail('Sign in form didn\'t fade in.');
|
||||
// });
|
||||
|
||||
|
||||
casper.captureScreenshot('login_spam_test.png');
|
||||
// casper.captureScreenshot('login_spam_test.png');
|
||||
|
||||
casper.waitForText('attempts remaining!', function then() {
|
||||
this.fillAndSave('#login', falseUser);
|
||||
});
|
||||
// casper.waitForText('attempts remaining!', function then() {
|
||||
// this.fillAndSave('#login', falseUser);
|
||||
// });
|
||||
|
||||
casper.captureScreenshot('login_spam_test2.png');
|
||||
// casper.captureScreenshot('login_spam_test2.png');
|
||||
|
||||
casper.waitForText('Slow down, there are way too many login attempts!', function onSuccess() {
|
||||
test.assert(true, 'Spamming the login did result in an error notification');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'Spamming the login did not result in an error notification');
|
||||
});
|
||||
// casper.waitForText('Slow down, there are way too many login attempts!', function onSuccess() {
|
||||
// test.assert(true, 'Spamming the login did result in an error notification');
|
||||
// test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
// }, function onTimeout() {
|
||||
// test.assert(false, 'Spamming the login did not result in an error notification');
|
||||
// });
|
||||
|
||||
// This test causes the spam notification
|
||||
// add a wait to ensure future tests don't get tripped up by this.
|
||||
casper.wait(2000);
|
||||
}, true);
|
||||
// // This test causes the spam notification
|
||||
// // add a wait to ensure future tests don't get tripped up by this.
|
||||
// casper.wait(2000);
|
||||
// }, true);
|
||||
|
||||
CasperTest.begin('Login limit is in place', 4, function suite(test) {
|
||||
// init user to prevent redirect to setup
|
||||
CasperTest.Routines.setup.run(test);
|
||||
CasperTest.Routines.signout.run(test);
|
||||
// TODO: please uncomment when the spam prevention bug is fixed (https://github.com/TryGhost/Ghost/issues/3128)
|
||||
// CasperTest.begin('Login limit is in place', 4, function suite(test) {
|
||||
// casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
// test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
// test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
// });
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
});
|
||||
// casper.waitForOpaque('.login-box',
|
||||
// function then() {
|
||||
// this.fillAndSave('#login', falseUser);
|
||||
// },
|
||||
// function onTimeout() {
|
||||
// test.fail('Sign in form didn\'t fade in.');
|
||||
// });
|
||||
|
||||
casper.waitForOpaque('.login-box',
|
||||
function then() {
|
||||
this.fillAndSave('#login', falseUser);
|
||||
},
|
||||
function onTimeout() {
|
||||
test.fail('Sign in form didn\'t fade in.');
|
||||
});
|
||||
// casper.wait(2100, function doneWait() {
|
||||
// this.fillAndSave('#login', falseUser);
|
||||
// });
|
||||
|
||||
casper.wait(2100, function doneWait() {
|
||||
this.fillAndSave('#login', falseUser);
|
||||
});
|
||||
|
||||
casper.waitForText('remaining', function onSuccess() {
|
||||
test.assert(true, 'The login limit is in place.');
|
||||
test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
}, function onTimeout() {
|
||||
test.assert(false, 'We did not trip the login limit.');
|
||||
});
|
||||
// This test used login, add a wait to
|
||||
// ensure future tests don't get tripped up by this.
|
||||
casper.wait(2000);
|
||||
}, true);
|
||||
// casper.waitForText('remaining', function onSuccess() {
|
||||
// test.assert(true, 'The login limit is in place.');
|
||||
// test.assertSelectorDoesntHaveText('.notification-error', '[object Object]');
|
||||
// }, function onTimeout() {
|
||||
// test.assert(false, 'We did not trip the login limit.');
|
||||
// });
|
||||
// // This test used login, add a wait to
|
||||
// // ensure future tests don't get tripped up by this.
|
||||
// casper.wait(2000);
|
||||
// }, true);
|
||||
|
||||
CasperTest.begin('Can login to Ghost', 5, function suite(test) {
|
||||
// init user
|
||||
CasperTest.Routines.setup.run(test);
|
||||
CasperTest.Routines.signout.run(test);
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
@ -158,10 +147,6 @@ CasperTest.begin('Can login to Ghost', 5, function suite(test) {
|
||||
}, true);
|
||||
|
||||
CasperTest.begin('Authenticated user is redirected', 8, function suite(test) {
|
||||
// init user
|
||||
CasperTest.Routines.setup.run(test);
|
||||
CasperTest.Routines.signout.run(test);
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
@ -190,31 +175,27 @@ CasperTest.begin('Authenticated user is redirected', 8, function suite(test) {
|
||||
});
|
||||
}, true);
|
||||
|
||||
// TODO: please uncomment when the validation problem is fixed (https://github.com/TryGhost/Ghost/issues/3120)
|
||||
// CasperTest.begin('Ensure email field form validation', 3, function suite(test) {
|
||||
// casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
// test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
// test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
// });
|
||||
|
||||
CasperTest.begin('Ensure email field form validation', 3, function suite(test) {
|
||||
// init user to prevent redirect to setup
|
||||
CasperTest.Routines.setup.run(test);
|
||||
CasperTest.Routines.signout.run(test);
|
||||
// casper.waitForOpaque('.js-login-box',
|
||||
// function then() {
|
||||
// this.fillAndSave('form.login-form', {
|
||||
// 'email': 'notanemail'
|
||||
// });
|
||||
// },
|
||||
// function onTimeout() {
|
||||
// test.fail('Login form didn\'t fade in.');
|
||||
// });
|
||||
|
||||
casper.thenOpenAndWaitForPageLoad('signin', function testTitleAndUrl() {
|
||||
test.assertTitle('Ghost Admin', 'Ghost admin has no title');
|
||||
test.assertUrlMatch(/ghost\/signin\/$/, 'Landed on the correct URL');
|
||||
});
|
||||
// casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
// test.assertSelectorHasText('.notification-error', 'Invalid Email');
|
||||
// }, function onTimeout() {
|
||||
// test.fail('Email validation error did not appear');
|
||||
// }, 2000);
|
||||
|
||||
casper.waitForOpaque('.js-login-box',
|
||||
function then() {
|
||||
this.fillAndSave('form.login-form', {
|
||||
'identification': 'notanemail'
|
||||
});
|
||||
},
|
||||
function onTimeout() {
|
||||
test.fail('Login form didn\'t fade in.');
|
||||
});
|
||||
|
||||
casper.waitForSelectorTextChange('.notification-error', function onSuccess() {
|
||||
test.assertSelectorHasText('.notification-error', 'Invalid Email');
|
||||
}, function onTimeout() {
|
||||
test.fail('Email validation error did not appear');
|
||||
}, 2000);
|
||||
|
||||
}, true);
|
||||
// }, true);
|
||||
|
Loading…
Reference in New Issue
Block a user