From c4fbed24f82b5ad274705531226056f62fac0062 Mon Sep 17 00:00:00 2001 From: Julian Lam <julian@nodebb.org> Date: Thu, 20 Jul 2017 08:51:04 -0400 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9c86d9b2904e14927cd7e9679b92aec0951d1063 Merge: ebfa63a 5a7f811 Author: Julian Lam <julian@nodebb.org> Date: Thu Jul 20 08:41:39 2017 -0400 Merge branch 'noscript-login' of https://github.com/An-dz/NodeBB into noscript commit 5a7f81185e8f9bd7d2d011c3d495988be7e437a3 Author: André Zanghelini <an_dz@simutrans-forum> Date: Mon Jul 17 23:07:14 2017 -0300 Rename clashing variable 'next' commit ebfa63a984073a58c17aa408c363cdb03ef89985 Merge: c1801cd f159d0d Author: Julian Lam <julian@nodebb.org> Date: Mon Jul 17 16:30:40 2017 -0400 Merge branch 'noscript-logout' of https://github.com/An-dz/NodeBB into noscript commit c1801cda14e6363491e30b659902e2ae71f7e1f7 Merge: 7a5f9f3 9fd542d Author: Julian Lam <julian@nodebb.org> Date: Mon Jul 17 16:30:31 2017 -0400 Merge branch 'noscript-register' of https://github.com/An-dz/NodeBB into noscript commit 7a5f9f35abc834bb72ddddc9ca07d34f2fde8353 Merge: 44851f9 d37b95c Author: Julian Lam <julian@nodebb.org> Date: Mon Jul 17 16:30:10 2017 -0400 Merge branch 'noscript-compose' of https://github.com/An-dz/NodeBB into noscript commit f159d0d9ef1b7f600e830a96fdb4b9c87c79bb4a Author: André Zanghelini <an_dz@simutrans-forum> Date: Thu Jul 6 12:16:38 2017 -0300 Prevent form submit Required for theme change commit d37b95cb71d32d4483190609798e244c331db165 Author: André Zanghelini <an_dz@simutrans-forum> Date: Thu Jul 6 01:49:52 2017 -0300 Prevent link action with scripts Required for the theme change that changes the buttons to `a` tags. commit 9fd542d8970b7d1a4126f4edc4b44eab7d708fb0 Author: André Zanghelini <an_dz@simutrans-forum> Date: Wed Jul 5 19:57:56 2017 -0300 Fix tests commit cdad5bf8c2891ad76f7441fd4d8a74b058a14e6d Author: André Zanghelini <an_dz@simutrans-forum> Date: Wed Jul 5 19:09:17 2017 -0300 Update error handling commit 4ff11cd136a4fb98483f837e2cebc741380dfe76 Author: André Zanghelini <an_dz@simutrans-forum> Date: Wed Jul 5 17:29:08 2017 -0300 Remove async waterfall commit df01d44e821a70c984b89e9585a325c3e02c6e37 Author: André Zanghelini <an_dz@simutrans-forum> Date: Wed Jul 5 16:59:43 2017 -0300 Set noscript compose as noscript at start commit 4bcc380da72239b8315cc849a77a3036e06e4a12 Author: André Zanghelini <an_dz@simutrans-forum> Date: Wed Jul 5 16:59:12 2017 -0300 Remove last useless next commit b5eac6fea11e209934c0648a7e75ad07a2167123 Author: André Zanghelini <an_dz@simutrans-forum> Date: Sun Jul 2 18:35:08 2017 -0300 Last function requires no next commit 20a5cce6e6e32a454c304c448383707ec44c75a8 Author: André Zanghelini <an_dz@simutrans-forum> Date: Sun Jul 2 18:06:58 2017 -0300 Remove more useless next calls commit 85ee22a79bcbbb1995106f43d4c74d6ba9206cab Author: André Zanghelini <an_dz@simutrans-forum> Date: Sun Jul 2 17:46:07 2017 -0300 Remove useless next calls commit 7d984c47ad24faac1fe537dee4a5a7d697e8634c Author: André Zanghelini <an_dz@simutrans-forum> Date: Sun Jul 2 15:45:31 2017 -0300 Support old themes commit 4a09dfbd08253115c342a9e829c4e6940cecb8cc Author: André Zanghelini <an_dz@simutrans-forum> Date: Sun Jul 2 15:37:23 2017 -0300 Moved all error handling into helpers function commit 391aa6e67ef9ab67304005e14ac0633cdb630713 Author: André Zanghelini <an_dz@simutrans-forum> Date: Thu Jun 8 15:37:37 2017 -0300 ESLint - Fix mixed conditionals commit 80ccc6fd581d791f31e7ab62de8de611837bfc3c Author: André Zanghelini <an_dz@simutrans-forum> Date: Sat Jun 3 18:08:15 2017 -0300 Compose without scripts commit 2aca811256721238ca0cede4954213d369009885 Author: André Zanghelini <an_dz@simutrans-forum> Date: Sat Jun 3 18:00:44 2017 -0300 Register without scripts commit 097bb51577fb26f8e22f86dc274cb670ab606a8a Author: André Zanghelini <an_dz@simutrans-forum> Date: Sat Jun 3 16:42:15 2017 -0300 Logout without scripts commit d497e08109891079656fee1c145043a9c0e55f2e Author: André Zanghelini <an_dz@simutrans-forum> Date: Sat Jun 3 16:27:10 2017 -0300 Login without script --- public/src/app.js | 6 ++-- public/src/client/login.js | 1 + public/src/client/register.js | 1 + public/src/client/topic/postTools.js | 3 +- src/controllers/authentication.js | 40 ++++++++++++++++++-------- src/controllers/helpers.js | 18 ++++++++++++ src/controllers/index.js | 42 ++++++++++++++++++++++++++++ src/routes/index.js | 2 ++ src/views/400.tpl | 8 ++++++ src/views/403.tpl | 4 +++ src/views/500.tpl | 4 +++ test/authentication.js | 2 ++ test/controllers.js | 1 + test/user.js | 2 ++ 14 files changed, 120 insertions(+), 14 deletions(-) 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);