v1.18.x
Julian Lam 10 years ago
parent 4f38a33702
commit deac12c540

@ -149,6 +149,10 @@ var socket,
app.cacheBuster = config['cache-buster']; app.cacheBuster = config['cache-buster'];
require(['csrf'], function(csrf) {
csrf.set(data.csrf_token);
});
bootbox.setDefaults({ bootbox.setDefaults({
locale: config.userLang locale: config.userLang
}); });
@ -164,8 +168,16 @@ var socket,
}; };
app.logout = function() { app.logout = function() {
$.post(RELATIVE_PATH + '/logout', function() { require(['csrf'], function(csrf) {
$.ajax(RELATIVE_PATH + '/logout', {
type: 'POST',
headers: {
'x-csrf-token': csrf.get()
},
success: function() {
window.location.href = RELATIVE_PATH + '/'; window.location.href = RELATIVE_PATH + '/';
}
});
}); });
}; };

@ -1,7 +1,7 @@
"use strict"; "use strict";
/* global define, app, RELATIVE_PATH */ /* global define, app, RELATIVE_PATH */
define('forum/login', function() { define('forum/login', ['csrf'], function(csrf) {
var Login = {}; var Login = {};
Login.init = function() { Login.init = function() {
@ -14,7 +14,7 @@ define('forum/login', function() {
if (!$('#username').val() || !$('#password').val()) { if (!$('#username').val() || !$('#password').val()) {
translator.translate('[[error:invalid-username-or-password]]', function(translated) { translator.translate('[[error:invalid-username-or-password]]', function(translated) {
errorEl.find('p').text(translated) errorEl.find('p').text(translated);
errorEl.show(); errorEl.show();
}); });
} else { } else {
@ -22,7 +22,21 @@ define('forum/login', function() {
if (!submitEl.hasClass('disabled')) { if (!submitEl.hasClass('disabled')) {
submitEl.addClass('disabled'); submitEl.addClass('disabled');
formEl.submit(); formEl.ajaxSubmit({
headers: {
'x-csrf-token': csrf.get()
},
success: function(data, status) {
window.location.href = data;
},
error: function(data, status) {
translator.translate(data.responseText, config.defaultLang, function(translated) {
errorEl.find('p').text(translated)
errorEl.show();
submitEl.removeClass('disabled');
});
}
});
} }
} }
}); });

@ -3,7 +3,7 @@
/* globals define, app, utils, socket, config */ /* globals define, app, utils, socket, config */
define('forum/register', function() { define('forum/register', ['csrf'], function(csrf) {
var Register = {}, var Register = {},
validationError = false, validationError = false,
successIcon = '<i class="fa fa-check"></i>'; successIcon = '<i class="fa fa-check"></i>';
@ -176,7 +176,24 @@ define('forum/register', function() {
e.preventDefault(); e.preventDefault();
validateForm(function() { validateForm(function() {
if (!validationError) { if (!validationError) {
registerBtn.parents('form').trigger('submit'); registerBtn.addClass('disabled');
registerBtn.parents('form').ajaxSubmit({
headers: {
'x-csrf-token': csrf.get()
},
success: function(data, status) {
window.location.href = data;
},
error: function(data, status) {
var errorEl = $('#register-error-notify');
translator.translate(data.responseText, config.defaultLang, function(translated) {
errorEl.find('p').text(translated)
errorEl.show();
registerBtn.removeClass('disabled');
});
}
});
} }
}); });
}); });

@ -2,7 +2,7 @@
/* globals define, utils, config, app */ /* globals define, utils, config, app */
define('composer/uploads', ['composer/preview'], function(preview) { define('composer/uploads', ['composer/preview', 'csrf'], function(preview, csrf) {
var uploads = { var uploads = {
inProgress: {} inProgress: {}
}; };
@ -235,16 +235,13 @@ define('composer/uploads', ['composer/preview'], function(preview) {
textarea.val(current.replace(re, filename + '](' + text + ')')); textarea.val(current.replace(re, filename + '](' + text + ')'));
} }
$(this).find('#postUploadCsrf').val($('#csrf').attr('data-csrf'));
if (formData) {
formData.append('_csrf', $('#csrf').attr('data-csrf'));
}
uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || []; uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || [];
uploads.inProgress[post_uuid].push(1); uploads.inProgress[post_uuid].push(1);
$(this).ajaxSubmit({ $(this).ajaxSubmit({
headers: {
'x-csrf-token': csrf.get()
},
resetForm: true, resetForm: true,
clearForm: true, clearForm: true,
formData: formData, formData: formData,
@ -291,19 +288,15 @@ define('composer/uploads', ['composer/preview'], function(preview) {
thumbForm.attr('action', config.relative_path + params.route); thumbForm.attr('action', config.relative_path + params.route);
thumbForm.off('submit').submit(function() { thumbForm.off('submit').submit(function() {
var csrf = $('#csrf').attr('data-csrf');
$(this).find('#thumbUploadCsrf').val(csrf);
if(formData) {
formData.append('_csrf', csrf);
}
spinner.removeClass('hide'); spinner.removeClass('hide');
uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || []; uploads.inProgress[post_uuid] = uploads.inProgress[post_uuid] || [];
uploads.inProgress[post_uuid].push(1); uploads.inProgress[post_uuid].push(1);
$(this).ajaxSubmit({ $(this).ajaxSubmit({
headers: {
'x-csrf-token': csrf.get()
},
formData: formData, formData: formData,
error: onUploadError, error: onUploadError,
success: function(uploads) { success: function(uploads) {

@ -1,4 +1,4 @@
define('uploader', function() { define('uploader', ['csrf'], function(csrf) {
var module = {}, var module = {},
maybeParse = function(response) { maybeParse = function(response) {
@ -20,7 +20,7 @@ define('uploader', function() {
uploadForm[0].reset(); uploadForm[0].reset();
uploadForm.attr('action', route); uploadForm.attr('action', route);
uploadForm.find('#params').val(JSON.stringify(params)); uploadForm.find('#params').val(JSON.stringify(params));
uploadForm.find('#csrfToken').val($('#csrf').attr('data-csrf')); // uploadForm.find('#csrfToken').val(csrf.get());
if(fileSize) { if(fileSize) {
uploadForm.find('#upload-file-size').html(fileSize); uploadForm.find('#upload-file-size').html(fileSize);
@ -61,6 +61,9 @@ define('uploader', function() {
} }
$(this).ajaxSubmit({ $(this).ajaxSubmit({
headers: {
'x-csrf-token': csrf.get()
},
error: function(xhr) { error: function(xhr) {
xhr = maybeParse(xhr); xhr = maybeParse(xhr);
error('Error: ' + xhr.status); error('Error: ' + xhr.status);

@ -345,7 +345,6 @@ accountsController.accountEdit = function(req, res, next) {
} }
userData.hasPassword = !!password; userData.hasPassword = !!password;
userData.csrf = req.csrfToken();
res.render('account/edit', userData); res.render('account/edit', userData);
}); });

@ -141,8 +141,7 @@ function filterAndRenderCategories(req, res, next, active) {
}); });
res.render('admin/manage/categories', { res.render('admin/manage/categories', {
categories: categoryData, categories: categoryData
csrf: req.csrfToken()
}); });
}); });
} }
@ -223,9 +222,7 @@ adminController.languages.get = function(req, res, next) {
adminController.settings.get = function(req, res, next) { adminController.settings.get = function(req, res, next) {
var term = req.params.term ? req.params.term : 'general'; var term = req.params.term ? req.params.term : 'general';
res.render('admin/settings/' + term, { res.render('admin/settings/' + term);
'csrf': req.csrfToken()
});
}; };
adminController.logger.get = function(req, res, next) { adminController.logger.get = function(req, res, next) {

@ -52,6 +52,7 @@ apiController.getConfig = function(req, res, next) {
config['css-buster'] = meta.css.hash; config['css-buster'] = meta.css.hash;
config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1; config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1;
config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest'; config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest';
config.csrf_token = req.csrfToken();
if (!req.user) { if (!req.user) {
if (res.locals.isAPI) { if (res.locals.isAPI) {

@ -239,7 +239,6 @@ categoriesController.get = function(req, res, next) {
data.currentPage = page; data.currentPage = page;
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
data.csrf = req.csrfToken();
if (!res.locals.isAPI) { if (!res.locals.isAPI) {
// Paginator for noscript // Paginator for noscript

@ -143,7 +143,6 @@ Controllers.login = function(req, res, next) {
data.alternate_logins = loginStrategies.length > 0; data.alternate_logins = loginStrategies.length > 0;
data.authentication = loginStrategies; data.authentication = loginStrategies;
data.token = req.csrfToken();
data.showResetLink = emailersPresent; data.showResetLink = emailersPresent;
data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1; data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1;
data.allowRegistration = parseInt(meta.config.allowRegistration, 10) === 1; data.allowRegistration = parseInt(meta.config.allowRegistration, 10) === 1;
@ -174,7 +173,6 @@ Controllers.register = function(req, res, next) {
data.authentication = loginStrategies; data.authentication = loginStrategies;
data.token = req.csrfToken();
data.minimumUsernameLength = meta.config.minimumUsernameLength; data.minimumUsernameLength = meta.config.minimumUsernameLength;
data.maximumUsernameLength = meta.config.maximumUsernameLength; data.maximumUsernameLength = meta.config.maximumUsernameLength;
data.minimumPasswordLength = meta.config.minimumPasswordLength; data.minimumPasswordLength = meta.config.minimumPasswordLength;

@ -239,7 +239,6 @@ topicsController.get = function(req, res, next) {
data['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; data['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1;
data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
data.csrf = req.csrfToken();
topics.increaseViewCount(tid); topics.increaseViewCount(tid);

@ -71,7 +71,6 @@ middleware.buildHeader = function(req, res, next) {
return next(err); return next(err);
} }
var data = { var data = {
csrf: req.csrfToken ? req.csrfToken() : undefined,
relative_path: nconf.get('relative_path'), relative_path: nconf.get('relative_path'),
plugins: pluginData.custom_header.plugins, plugins: pluginData.custom_header.plugins,
authentication: pluginData.custom_header.authentication, authentication: pluginData.custom_header.authentication,

@ -260,7 +260,6 @@ middleware.renderHeader = function(req, res, callback) {
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
'brand:logo': meta.config['brand:logo'] || '', 'brand:logo': meta.config['brand:logo'] || '',
'brand:logo:display': meta.config['brand:logo']?'':'hide', 'brand:logo:display': meta.config['brand:logo']?'':'hide',
csrf: req.csrfToken ? req.csrfToken() : undefined,
navigation: custom_header.navigation, navigation: custom_header.navigation,
allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1, allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1,
searchEnabled: plugins.hasListeners('filter:search.query') searchEnabled: plugins.hasListeners('filter:search.query')

@ -21,6 +21,7 @@ function apiRoutes(app, middleware, controllers) {
function adminRouter(middleware, controllers) { function adminRouter(middleware, controllers) {
var router = express.Router(); var router = express.Router();
router.use(middleware.applyCSRF);
router.use(middleware.admin.buildHeader); router.use(middleware.admin.buildHeader);
router.get('/', controllers.admin.home); router.get('/', controllers.admin.home);
@ -45,9 +46,9 @@ function addRoutes(router, middleware, controllers) {
router.get('/general/languages', controllers.admin.languages.get); router.get('/general/languages', controllers.admin.languages.get);
router.get('/general/sounds', controllers.admin.sounds.get); router.get('/general/sounds', controllers.admin.sounds.get);
router.get('/manage/categories', middleware.applyCSRF, controllers.admin.categories.active); router.get('/manage/categories', controllers.admin.categories.active);
router.get('/manage/categories/active', middleware.applyCSRF, controllers.admin.categories.active); router.get('/manage/categories/active', controllers.admin.categories.active);
router.get('/manage/categories/disabled', middleware.applyCSRF, controllers.admin.categories.disabled); router.get('/manage/categories/disabled', controllers.admin.categories.disabled);
router.get('/manage/tags', controllers.admin.tags.get); router.get('/manage/tags', controllers.admin.tags.get);
@ -62,7 +63,7 @@ function addRoutes(router, middleware, controllers) {
router.get('/manage/groups', controllers.admin.groups.get); router.get('/manage/groups', controllers.admin.groups.get);
router.get('/settings/:term?', middleware.applyCSRF, controllers.admin.settings.get); router.get('/settings/:term?', controllers.admin.settings.get);
router.get('/appearance/:term?', controllers.admin.appearance.get); router.get('/appearance/:term?', controllers.admin.appearance.get);

@ -198,7 +198,7 @@ module.exports = function(app, middleware, controllers) {
var router = express.Router(); var router = express.Router();
app.use('/api', router); app.use('/api', router);
router.get('/config', controllers.api.getConfig); router.get('/config', middleware.applyCSRF, controllers.api.getConfig);
router.get('/widgets/render', controllers.api.renderWidgets); router.get('/widgets/render', controllers.api.renderWidgets);
router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.accounts.getUserByUID); router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.accounts.getUserByUID);

@ -56,7 +56,7 @@
})); }));
}); });
router.post('/logout', logout); router.post('/logout', Auth.middleware.applyCSRF, logout);
router.post('/register', Auth.middleware.applyCSRF, register); router.post('/register', Auth.middleware.applyCSRF, register);
router.post('/login', Auth.middleware.applyCSRF, login); router.post('/login', Auth.middleware.applyCSRF, login);
@ -147,8 +147,7 @@
function continueLogin(req, res, next) { function continueLogin(req, res, next) {
passport.authenticate('local', function(err, userData, info) { passport.authenticate('local', function(err, userData, info) {
if (err) { if (err) {
req.flash('error', err.message); return res.status(403).send(err.message);
return res.redirect(nconf.get('relative_path') + '/login');
} }
if (!userData) { if (!userData) {
@ -156,8 +155,7 @@
info = '[[error:invalid-username-or-password]]'; info = '[[error:invalid-username-or-password]]';
} }
req.flash('error', info); return res.status(403).send(info);
return res.redirect(nconf.get('relative_path') + '/login');
} }
// Alter user cookie depending on passed-in option // Alter user cookie depending on passed-in option
@ -174,8 +172,7 @@
uid: userData.uid uid: userData.uid
}, function(err) { }, function(err) {
if (err) { if (err) {
req.flash('error', err.message); return res.status(403).send(err.message);
return res.redirect(nconf.get('relative_path') + '/login');
} }
if (userData.uid) { if (userData.uid) {
user.logIP(userData.uid, req.ip); user.logIP(userData.uid, req.ip);
@ -184,11 +181,12 @@
} }
if (!req.session.returnTo) { if (!req.session.returnTo) {
res.redirect(nconf.get('relative_path') + '/'); res.status(200).send(nconf.get('relative_path') + '/');
} else { } else {
var next = req.session.returnTo; var next = req.session.returnTo;
delete req.session.returnTo; delete req.session.returnTo;
res.redirect(nconf.get('relative_path') + next);
res.status(200).send(nconf.get('relative_path') + next);
} }
}); });
})(req, res, next); })(req, res, next);
@ -196,7 +194,7 @@
function register(req, res) { function register(req, res) {
if (parseInt(meta.config.allowRegistration, 10) === 0) { if (parseInt(meta.config.allowRegistration, 10) === 0) {
return res.status(403).send(''); return res.sendStatus(403);
} }
var userData = {}; var userData = {};
@ -242,10 +240,10 @@
} }
], function(err, data) { ], function(err, data) {
if (err) { if (err) {
req.flash('error', err.message); return res.status(400).send(err.message);
return res.redirect(nconf.get('relative_path') + '/register');
} }
res.redirect(nconf.get('relative_path') + (data.referrer ? data.referrer : '/'));
res.status(200).send(nconf.get('relative_path') + (data.referrer ? data.referrer : '/'));
}); });
} }

@ -20,7 +20,7 @@ var nconf = require('nconf'),
function mainRoutes(app, middleware, controllers) { function mainRoutes(app, middleware, controllers) {
setupPageRoute(app, '/', middleware, [], controllers.home); setupPageRoute(app, '/', middleware, [], controllers.home);
var loginRegisterMiddleware = [middleware.applyCSRF, middleware.redirectToAccountIfLoggedIn]; var loginRegisterMiddleware = [middleware.redirectToAccountIfLoggedIn];
setupPageRoute(app, '/login', middleware, loginRegisterMiddleware, controllers.login); setupPageRoute(app, '/login', middleware, loginRegisterMiddleware, controllers.login);
setupPageRoute(app, '/register', middleware, loginRegisterMiddleware, controllers.register); setupPageRoute(app, '/register', middleware, loginRegisterMiddleware, controllers.register);
@ -40,8 +40,8 @@ function staticRoutes(app, middleware, controllers) {
function topicRoutes(app, middleware, controllers) { function topicRoutes(app, middleware, controllers) {
app.get('/api/topic/teaser/:topic_id', controllers.topics.teaser); app.get('/api/topic/teaser/:topic_id', controllers.topics.teaser);
setupPageRoute(app, '/topic/:topic_id/:slug/:post_index?', middleware, [middleware.applyCSRF], controllers.topics.get); setupPageRoute(app, '/topic/:topic_id/:slug/:post_index?', middleware, [], controllers.topics.get);
setupPageRoute(app, '/topic/:topic_id/:slug?', middleware, [middleware.applyCSRF, middleware.addSlug], controllers.topics.get); setupPageRoute(app, '/topic/:topic_id/:slug?', middleware, [middleware.addSlug], controllers.topics.get);
} }
function tagRoutes(app, middleware, controllers) { function tagRoutes(app, middleware, controllers) {
@ -55,8 +55,8 @@ function categoryRoutes(app, middleware, controllers) {
setupPageRoute(app, '/unread', middleware, [middleware.authenticate], controllers.categories.unread); setupPageRoute(app, '/unread', middleware, [middleware.authenticate], controllers.categories.unread);
app.get('/api/unread/total', middleware.authenticate, controllers.categories.unreadTotal); app.get('/api/unread/total', middleware.authenticate, controllers.categories.unreadTotal);
setupPageRoute(app, '/category/:category_id/:slug/:topic_index', middleware, [middleware.applyCSRF], controllers.categories.get); setupPageRoute(app, '/category/:category_id/:slug/:topic_index', middleware, [], controllers.categories.get);
setupPageRoute(app, '/category/:category_id/:slug?', middleware, [middleware.applyCSRF, middleware.addSlug], controllers.categories.get); setupPageRoute(app, '/category/:category_id/:slug?', middleware, [middleware.addSlug], controllers.categories.get);
} }
function accountRoutes(app, middleware, controllers) { function accountRoutes(app, middleware, controllers) {
@ -70,7 +70,7 @@ function accountRoutes(app, middleware, controllers) {
setupPageRoute(app, '/user/:userslug/topics', middleware, middlewares, controllers.accounts.getTopics); setupPageRoute(app, '/user/:userslug/topics', middleware, middlewares, controllers.accounts.getTopics);
setupPageRoute(app, '/user/:userslug/favourites', middleware, accountMiddlewares, controllers.accounts.getFavourites); setupPageRoute(app, '/user/:userslug/favourites', middleware, accountMiddlewares, controllers.accounts.getFavourites);
setupPageRoute(app, '/user/:userslug/edit', middleware, [middleware.applyCSRF].concat(accountMiddlewares), controllers.accounts.accountEdit); setupPageRoute(app, '/user/:userslug/edit', middleware, accountMiddlewares, controllers.accounts.accountEdit);
setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.accountSettings); setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.accountSettings);
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.getNotifications); setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.getNotifications);
@ -98,7 +98,7 @@ function groupRoutes(app, middleware, controllers) {
function setupPageRoute(router, name, middleware, middlewares, controller) { function setupPageRoute(router, name, middleware, middlewares, controller) {
middlewares = middlewares.concat([middleware.incrementPageViews, middleware.updateLastOnlineTime]); middlewares = middlewares.concat([middleware.incrementPageViews, middleware.updateLastOnlineTime]);
router.get(name, middleware.buildHeader, middlewares, controller); router.get(name, middleware.applyCSRF, middleware.buildHeader, middlewares, controller);
router.get('/api' + name, middlewares, controller); router.get('/api' + name, middlewares, controller);
} }
@ -179,6 +179,10 @@ function handleErrors(err, req, res, next) {
//console.error(err.stack, req.path); //console.error(err.stack, req.path);
winston.error(req.path + '\n', err.stack); winston.error(req.path + '\n', err.stack);
if (err.code === 'EBADCSRFTOKEN') {
return res.sendStatus(403);
}
var status = err.status || 500; var status = err.status || 500;
res.status(status); res.status(status);

@ -17,7 +17,6 @@
<p class="help-block"></p> <p class="help-block"></p>
</div> </div>
<input type="hidden" id="params" name="params"> <input type="hidden" id="params" name="params">
<input type="hidden" id="csrfToken" name="_csrf" />
</form> </form>
<div id="upload-progress-box" class="progress progress-striped"> <div id="upload-progress-box" class="progress progress-striped">

@ -142,8 +142,6 @@
</div> </div>
</div> </div>
<span class="hidden" id="csrf" data-csrf="{csrf}"></span>
<!-- IMPORT admin/partials/categories/new.tpl --> <!-- IMPORT admin/partials/categories/new.tpl -->
<!-- IMPORT admin/partials/categories/permissions.tpl --> <!-- IMPORT admin/partials/categories/permissions.tpl -->
<!-- IMPORT admin/partials/categories/setParent.tpl --> <!-- IMPORT admin/partials/categories/setParent.tpl -->

@ -1,5 +1,4 @@
</div> </div>
<span class="hidden" id="csrf" data-csrf="{csrf}"></span>
<div class="col-lg-3"> <div class="col-lg-3">
<div class="panel panel-default"> <div class="panel panel-default">

Loading…
Cancel
Save