diff --git a/public/src/app.js b/public/src/app.js index ccd324b68c..a45a99c5b3 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -35,7 +35,8 @@ app.cacheBuster = null; app.handleSearch(); } - $('body').on('click', '#new_topic', function () { + $('body').on('click', '#new_topic', function (e) { + e.preventDefault(); app.newTopic(); }); @@ -89,7 +90,8 @@ app.cacheBuster = null; }); }; - app.logout = function () { + app.logout = function (e) { + e.preventDefault(); $(window).trigger('action:app.logout'); /* diff --git a/public/src/client/login.js b/public/src/client/login.js index 0ee61e48f7..1a8f96861e 100644 --- a/public/src/client/login.js +++ b/public/src/client/login.js @@ -74,6 +74,7 @@ define('forum/login', [], function () { } else { $('#content #username').focus(); } + $('#content #noscript').val('false'); }; return Login; diff --git a/public/src/client/register.js b/public/src/client/register.js index 8070263906..4289c75d10 100644 --- a/public/src/client/register.js +++ b/public/src/client/register.js @@ -16,6 +16,7 @@ define('forum/register', ['translator', 'zxcvbn'], function (translator, zxcvbn) handleLanguageOverride(); $('#referrer').val(app.previousUrl); + $('#content #noscript').val('false'); email.on('blur', function () { if (email.val().length) { diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 90b845538e..23e0954969 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -85,7 +85,8 @@ define('forum/topic/postTools', [ onReplyClicked($(this), tid); }); - $('.topic').on('click', '[component="topic/reply"]', function () { + $('.topic').on('click', '[component="topic/reply"]', function (e) { + e.preventDefault(); onReplyClicked($(this), tid); }); diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 5309bdc380..8ca33cdc62 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -14,6 +14,7 @@ var plugins = require('../plugins'); var utils = require('../utils'); var Password = require('../password'); var translator = require('../translator'); +var helpers = require('./helpers'); var sockets = require('../socket.io'); @@ -49,6 +50,10 @@ authenticationController.register = function (req, res) { return next(new Error('[[error:username-too-long]]')); } + if (userData.password !== userData['password-confirm']) { + return next(new Error('[[user:change_password_error_match]]')); + } + user.isPasswordValid(userData.password, next); }, function (next) { @@ -67,7 +72,7 @@ authenticationController.register = function (req, res) { }, ], function (err, data) { if (err) { - return res.status(400).send(err.message); + return helpers.noScriptErrors(req, res, err.message, 400); } if (data.uid && req.body.userLang) { @@ -96,6 +101,10 @@ function registerAndLoginUser(req, res, userData, callback) { } userData.register = true; req.session.registration = userData; + + if (req.body.noscript === 'true') { + return res.redirect(nconf.get('relative_path') + '/register/complete'); + } return res.json({ referrer: nconf.get('relative_path') + '/register/complete' }); }, function (next) { @@ -200,22 +209,22 @@ authenticationController.login = function (req, res, next) { } else if (loginWith.indexOf('username') !== -1 && !validator.isEmail(req.body.username)) { continueLogin(req, res, next); } else { - res.status(500).send('[[error:wrong-login-type-' + loginWith + ']]'); + var err = '[[error:wrong-login-type-' + loginWith + ']]'; + helpers.noScriptErrors(req, res, err, 500); } }; function continueLogin(req, res, next) { passport.authenticate('local', function (err, userData, info) { if (err) { - return res.status(403).send(err.message); + return helpers.noScriptErrors(req, res, err.message, 403); } if (!userData) { if (typeof info === 'object') { info = '[[error:invalid-username-or-password]]'; } - - return res.status(403).send(info); + return helpers.noScriptErrors(req, res, info, 403); } var passwordExpiry = userData.passwordExpiry !== undefined ? parseInt(userData.passwordExpiry, 10) : null; @@ -235,7 +244,7 @@ function continueLogin(req, res, next) { req.session.passwordExpired = true; user.reset.generate(userData.uid, function (err, code) { if (err) { - return res.status(403).send(err.message); + return helpers.noScriptErrors(req, res, err.message, 403); } res.status(200).send(nconf.get('relative_path') + '/reset/' + code); @@ -243,16 +252,21 @@ function continueLogin(req, res, next) { } else { authenticationController.doLogin(req, userData.uid, function (err) { if (err) { - return res.status(403).send(err.message); + return helpers.noScriptErrors(req, res, err.message, 403); } + var destination; if (!req.session.returnTo) { - res.status(200).send(nconf.get('relative_path') + '/'); + destination = nconf.get('relative_path') + '/'; } else { - var next = req.session.returnTo; + destination = req.session.returnTo; delete req.session.returnTo; + } - res.status(200).send(next); + if (req.body.noscript === 'true') { + res.redirect(destination + '?loggedin'); + } else { + res.status(200).send(destination); } }); } @@ -404,7 +418,11 @@ authenticationController.logout = function (req, res, next) { function () { // Force session check for all connected socket.io clients with the same session id sockets.in('sess_' + req.sessionID).emit('checkSession', 0); - res.status(200).send(''); + if (req.body.noscript === 'true') { + res.redirect(nconf.get('relative_path') + '/'); + } else { + res.status(200).send(''); + } }, ], next); }; diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index 732652aa38..ee0ba75482 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -14,6 +14,24 @@ var middleware = require('../middleware'); var helpers = module.exports; +helpers.noScriptErrors = function (req, res, error, httpStatus) { + if (req.body.noscript !== 'true') { + return res.status(httpStatus).send(error); + } + + var middleware = require('../middleware'); + var httpStatusString = httpStatus.toString(); + middleware.buildHeader(req, res, function () { + res.status(httpStatus).render(httpStatusString, { + path: req.path, + loggedIn: true, + error: error, + returnLink: true, + title: '[[global:' + httpStatusString + '.title]]', + }); + }); +}; + helpers.notAllowed = function (req, res, error) { plugins.fireHook('filter:helpers.notAllowed', { req: req, diff --git a/src/controllers/index.js b/src/controllers/index.js index 84c20ade81..efa4c49654 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -7,6 +7,7 @@ var validator = require('validator'); var meta = require('../meta'); var user = require('../user'); var plugins = require('../plugins'); +var topics = require('../topics'); var helpers = require('./helpers'); var Controllers = module.exports; @@ -279,6 +280,47 @@ Controllers.compose = function (req, res, next) { }); }; +Controllers.composePost = function (req, res) { + var body = req.body; + var data = { + uid: req.uid, + req: req, + timestamp: Date.now(), + content: body.content, + }; + req.body.noscript = 'true'; + + if (!data.content) { + return helpers.noScriptErrors(req, res, '[[error:invalid-data]]', 400); + } + + if (body.tid) { + data.tid = body.tid; + + topics.reply(data, function (err, result) { + if (err) { + return helpers.noScriptErrors(req, res, err.message, 400); + } + user.updateOnlineUsers(result.uid); + + res.redirect(nconf.get('relative_path') + '/post/' + result.pid); + }); + } else if (body.cid) { + data.cid = body.cid; + data.title = body.title; + data.tags = []; + data.thumb = ''; + + topics.post(data, function (err, result) { + if (err) { + return helpers.noScriptErrors(req, res, err.message, 400); + } + + res.redirect(nconf.get('relative_path') + '/topic/' + result.topicData.slug); + }); + } +}; + Controllers.confirmEmail = function (req, res) { user.email.confirm(req.params.code, function (err) { res.render('confirm', { diff --git a/src/routes/index.js b/src/routes/index.js index 5023dcc3d3..2f2a790944 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -34,6 +34,8 @@ function mainRoutes(app, middleware, controllers) { setupPageRoute(app, '/search', middleware, [], controllers.search.search); setupPageRoute(app, '/reset/:code?', middleware, [], controllers.reset); setupPageRoute(app, '/tos', middleware, [], controllers.termsOfUse); + + app.post('/compose', middleware.applyCSRF, controllers.composePost); } function modRoutes(app, middleware, controllers) { diff --git a/src/views/400.tpl b/src/views/400.tpl index 9c263fcff1..c36f1b2f48 100644 --- a/src/views/400.tpl +++ b/src/views/400.tpl @@ -1,4 +1,12 @@ <div class="alert alert-danger"> <strong>[[global:400.title]]</strong> + <!-- IF error --> + <p>{error}</p> + <!-- ELSE --> <p>[[global:400.message, {config.relative_path}]]</p> + <!-- ENDIF error --> + + <!-- IF returnLink --> + <p>[[error:goback]]</p> + <!-- ENDIF returnLink --> </div> diff --git a/src/views/403.tpl b/src/views/403.tpl index e6800ed72d..bf93b496cd 100644 --- a/src/views/403.tpl +++ b/src/views/403.tpl @@ -6,6 +6,10 @@ <p>[[global:403.message]]</p> <!-- ENDIF error --> + <!-- IF returnLink --> + <p>[[error:goback]]</p> + <!-- ENDIF returnLink --> + <!-- IF !loggedIn --> <p>[[global:403.login, {config.relative_path}]]</p> <!-- ENDIF !loggedIn --> diff --git a/src/views/500.tpl b/src/views/500.tpl index 3abb9e8e27..7795fbbf8a 100644 --- a/src/views/500.tpl +++ b/src/views/500.tpl @@ -3,4 +3,8 @@ <p>[[global:500.message]]</p> <p>{path}</p> <!-- IF error --><p>{error}</p><!-- ENDIF error --> + + <!-- IF returnLink --> + <p>[[error:goback]]</p> + <!-- ENDIF returnLink --> </div> diff --git a/test/authentication.js b/test/authentication.js index 3a986f483a..55602777a2 100644 --- a/test/authentication.js +++ b/test/authentication.js @@ -55,6 +55,7 @@ describe('authentication', function () { email: email, username: username, password: password, + 'password-confirm': password, }, json: true, jar: jar, @@ -90,6 +91,7 @@ describe('authentication', function () { email: 'admin@nodebb.org', username: 'admin', password: 'adminpwd', + 'password-confirm': 'adminpwd', userLang: 'it', }, json: true, diff --git a/test/controllers.js b/test/controllers.js index 6a3882ea5e..7aa1b27957 100644 --- a/test/controllers.js +++ b/test/controllers.js @@ -158,6 +158,7 @@ describe('Controllers', function () { var data = { username: 'interstitial', password: '123456', + 'password-confirm': '123456', email: 'test@me.com', }; diff --git a/test/user.js b/test/user.js index a7204b01ca..7802912dd0 100644 --- a/test/user.js +++ b/test/user.js @@ -1274,6 +1274,7 @@ describe('User', function () { helpers.registerUser({ username: 'rejectme', password: '123456', + 'password-confirm': '123456', email: 'reject@me.com', }, function (err) { assert.ifError(err); @@ -1304,6 +1305,7 @@ describe('User', function () { helpers.registerUser({ username: 'acceptme', password: '123456', + 'password-confirm': '123456', email: 'accept@me.com', }, function (err) { assert.ifError(err);