mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-01 21:30:30 +01:00
refactor: move session revocation route to write api
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('forum/account/sessions', ['forum/account/header', 'components'], function (header, components) {
|
||||
define('forum/account/sessions', ['forum/account/header', 'components', 'api'], function (header, components, api) {
|
||||
var Sessions = {};
|
||||
|
||||
Sessions.init = function () {
|
||||
@@ -17,15 +17,9 @@ define('forum/account/sessions', ['forum/account/header', 'components'], functio
|
||||
if (uuid) {
|
||||
// This is done via DELETE because a user shouldn't be able to
|
||||
// revoke his own session! This is what logout is for
|
||||
$.ajax({
|
||||
url: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/session/' + uuid,
|
||||
method: 'delete',
|
||||
headers: {
|
||||
'x-csrf-token': config.csrf_token,
|
||||
},
|
||||
}).done(function () {
|
||||
api.del(`/users/${ajaxify.data.uid}/sessions/${uuid}`, {}).then(() => {
|
||||
parentEl.remove();
|
||||
}).fail(function (err) {
|
||||
}).catch((err) => {
|
||||
try {
|
||||
var errorObj = JSON.parse(err.responseText);
|
||||
if (errorObj.loggedIn === false) {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const db = require('../../database');
|
||||
const user = require('../../user');
|
||||
const helpers = require('../helpers');
|
||||
const accountHelpers = require('./helpers');
|
||||
@@ -21,39 +18,3 @@ sessionController.get = async function (req, res, next) {
|
||||
|
||||
res.render('account/sessions', userData);
|
||||
};
|
||||
|
||||
const getSessionAsync = util.promisify(function (sid, callback) {
|
||||
db.sessionStore.get(sid, (err, sessionObj) => callback(err, sessionObj || null));
|
||||
});
|
||||
|
||||
sessionController.revoke = async function (req, res, next) {
|
||||
if (!req.params.hasOwnProperty('uuid')) {
|
||||
return next();
|
||||
}
|
||||
try {
|
||||
const uid = await user.getUidByUserslug(req.params.userslug);
|
||||
if (!uid) {
|
||||
throw new Error('[[error:no-session-found]]');
|
||||
}
|
||||
const sids = await db.getSortedSetRange('uid:' + uid + ':sessions', 0, -1);
|
||||
let _id;
|
||||
for (const sid of sids) {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
const sessionObj = await getSessionAsync(sid);
|
||||
if (sessionObj && sessionObj.meta && sessionObj.meta.uuid === req.params.uuid) {
|
||||
_id = sid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_id) {
|
||||
throw new Error('[[error:no-session-found]]');
|
||||
}
|
||||
|
||||
await user.auth.revokeSession(_id, uid);
|
||||
} catch (err) {
|
||||
return res.status(500).send(err.message);
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const db = require('../../database');
|
||||
const api = require('../../api');
|
||||
const user = require('../../user');
|
||||
const meta = require('../../meta');
|
||||
@@ -120,3 +123,32 @@ Users.deleteToken = async (req, res) => {
|
||||
helpers.formatApiResponse(404, res);
|
||||
}
|
||||
};
|
||||
|
||||
const getSessionAsync = util.promisify(function (sid, callback) {
|
||||
db.sessionStore.get(sid, (err, sessionObj) => callback(err, sessionObj || null));
|
||||
});
|
||||
|
||||
Users.revokeSession = async (req, res) => {
|
||||
// Only admins or global mods (besides the user themselves) can revoke sessions
|
||||
if (parseInt(req.params.uid, 10) !== req.uid && !await user.isAdminOrGlobalMod(req.uid)) {
|
||||
return helpers.formatApiResponse(404, res);
|
||||
}
|
||||
|
||||
const sids = await db.getSortedSetRange('uid:' + req.params.uid + ':sessions', 0, -1);
|
||||
let _id;
|
||||
for (const sid of sids) {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
const sessionObj = await getSessionAsync(sid);
|
||||
if (sessionObj && sessionObj.meta && sessionObj.meta.uuid === req.params.uuid) {
|
||||
_id = sid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_id) {
|
||||
throw new Error('[[error:no-session-found]]');
|
||||
}
|
||||
|
||||
await user.auth.revokeSession(_id, req.params.uid);
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
const winston = require('winston');
|
||||
const nconf = require('nconf');
|
||||
|
||||
var helpers = require('./helpers');
|
||||
var setupPageRoute = helpers.setupPageRoute;
|
||||
|
||||
@@ -39,7 +42,14 @@ module.exports = function (app, middleware, controllers) {
|
||||
setupPageRoute(app, '/user/:userslug/consent', middleware, accountMiddlewares, controllers.accounts.consent.get);
|
||||
setupPageRoute(app, '/user/:userslug/blocks', middleware, accountMiddlewares, controllers.accounts.blocks.getBlocks);
|
||||
setupPageRoute(app, '/user/:userslug/sessions', middleware, accountMiddlewares, controllers.accounts.sessions.get);
|
||||
app.delete('/api/user/:userslug/session/:uuid', [middleware.exposeUid, middleware.ensureSelfOrGlobalPrivilege], controllers.accounts.sessions.revoke);
|
||||
app.delete('/api/user/:userslug/session/:uuid', [middleware.exposeUid], function (req, res, next) {
|
||||
// TODO: Remove this entire route in v1.16.0
|
||||
winston.warn('[router] `/api/user/:userslug/session/:uuid` has been deprecated, use `DELETE /api/v3/users/:uid/sessions/:uuid` or `DELETE /api/v3/users/bySlug/:userslug/sessions/:uuid` instead');
|
||||
if (!res.locals.uid) {
|
||||
return next();
|
||||
}
|
||||
res.redirect(`${nconf.get('relative_path')}/api/v3/users/${res.locals.uid}/sessions/${req.params.uuid}`);
|
||||
});
|
||||
|
||||
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
|
||||
setupPageRoute(app, '/user/:userslug/chats/:roomid?', middleware, middlewares, controllers.accounts.chats.get);
|
||||
|
||||
@@ -35,6 +35,8 @@ function authenticatedRoutes() {
|
||||
setupApiRoute(router, 'post', '/:uid/tokens', [...middlewares, middleware.assert.user], controllers.write.users.generateToken);
|
||||
setupApiRoute(router, 'delete', '/:uid/tokens/:token', [...middlewares, middleware.assert.user], controllers.write.users.deleteToken);
|
||||
|
||||
setupApiRoute(router, 'delete', '/:uid/sessions/:uuid', [...middlewares, middleware.assert.user], controllers.write.users.revokeSession);
|
||||
|
||||
// Shorthand route to access user routes by userslug
|
||||
router.all('/+bySlug/:userslug*?', [], controllers.write.users.redirectBySlug);
|
||||
}
|
||||
|
||||
@@ -813,19 +813,19 @@ describe('Controllers', function () {
|
||||
});
|
||||
|
||||
it('should fail if user doesn\'t exist', function (done) {
|
||||
request.del(nconf.get('url') + '/api/user/doesnotexist/session/1112233', {
|
||||
request.del(`${nconf.get('url')}/api/v3/users/doesnotexist/sessions/1112233`, {
|
||||
jar: jar,
|
||||
headers: {
|
||||
'x-csrf-token': csrf_token,
|
||||
},
|
||||
}, function (err, res, body) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 403);
|
||||
assert.equal(res.statusCode, 404);
|
||||
assert.deepEqual(JSON.parse(body), {
|
||||
response: {},
|
||||
status: {
|
||||
code: 'forbidden',
|
||||
message: 'You are not authorised to make this call',
|
||||
code: 'not-found',
|
||||
message: '[[error:no-user]]',
|
||||
},
|
||||
});
|
||||
done();
|
||||
@@ -839,15 +839,21 @@ describe('Controllers', function () {
|
||||
|
||||
db.sessionStore.get(sid, function (err, sessionObj) {
|
||||
assert.ifError(err);
|
||||
request.del(nconf.get('url') + '/api/user/revokeme/session/' + sessionObj.meta.uuid, {
|
||||
request.del(`${nconf.get('url')}/api/v3/users/${uid}/sessions/${sessionObj.meta.uuid}`, {
|
||||
jar: jar,
|
||||
headers: {
|
||||
'x-csrf-token': csrf_token,
|
||||
},
|
||||
}, function (err, res, body) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.equal(body, 'OK');
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
assert.deepStrictEqual(JSON.parse(body), {
|
||||
status: {
|
||||
code: 'ok',
|
||||
message: 'OK',
|
||||
},
|
||||
response: {},
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user