mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat(writeapi): token generation/delete routes, ACP updates
This commit is contained in:
@@ -6,5 +6,7 @@
|
|||||||
|
|
||||||
"uid": "User ID",
|
"uid": "User ID",
|
||||||
"uid-help-text": "Specify a User ID to associate with this token. If the user ID is <code>0</code>, it will be considered a <em>master</em> token, which can assume the identity of other users based on the <code>_uid</code> parameter",
|
"uid-help-text": "Specify a User ID to associate with this token. If the user ID is <code>0</code>, it will be considered a <em>master</em> token, which can assume the identity of other users based on the <code>_uid</code> parameter",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"no-description": "No description specified.",
|
||||||
|
"token-on-save": "Token will be generated once form is saved"
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ const notifications = require('../../notifications');
|
|||||||
const meta = require('../../meta');
|
const meta = require('../../meta');
|
||||||
const events = require('../../events');
|
const events = require('../../events');
|
||||||
const translator = require('../../translator');
|
const translator = require('../../translator');
|
||||||
|
const utils = require('../../utils');
|
||||||
|
|
||||||
const db = require('../../database');
|
const db = require('../../database');
|
||||||
const helpers = require('../helpers');
|
const helpers = require('../helpers');
|
||||||
@@ -218,3 +219,40 @@ Users.unban = async (req, res) => {
|
|||||||
|
|
||||||
helpers.formatApiResponse(200, res);
|
helpers.formatApiResponse(200, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Users.generateToken = async (req, res) => {
|
||||||
|
if (!res.locals.privileges['admin:settings']) {
|
||||||
|
return helpers.formatApiResponse(403, res, new Error('[[error:no-privileges]]'));
|
||||||
|
} else if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid, 10)) {
|
||||||
|
return helpers.formatApiResponse(401, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = await meta.settings.get('core.api');
|
||||||
|
const newToken = {
|
||||||
|
token: utils.generateUUID(),
|
||||||
|
uid: req.user.uid,
|
||||||
|
description: req.body.description || '',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
settings.tokens.push(newToken);
|
||||||
|
await meta.settings.set('core.api', settings);
|
||||||
|
helpers.formatApiResponse(200, res, newToken);
|
||||||
|
};
|
||||||
|
|
||||||
|
Users.deleteToken = async (req, res) => {
|
||||||
|
if (!res.locals.privileges['admin:settings']) {
|
||||||
|
return helpers.formatApiResponse(403, res, new Error('[[error:no-privileges]]'));
|
||||||
|
} else if (parseInt(req.params.uid, 10) !== parseInt(req.user.uid, 10)) {
|
||||||
|
return helpers.formatApiResponse(401, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = await meta.settings.get('core.api');
|
||||||
|
const beforeLen = settings.tokens.length;
|
||||||
|
settings.tokens = settings.tokens.filter(tokenObj => tokenObj.token !== req.params.token);
|
||||||
|
if (beforeLen !== settings.tokens.length) {
|
||||||
|
await meta.settings.set('core.api', settings);
|
||||||
|
helpers.formatApiResponse(200, res);
|
||||||
|
} else {
|
||||||
|
helpers.formatApiResponse(404, res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ module.exports = function (middleware) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
middleware.exposePrivilegeSet = async (req, res, next) => {
|
middleware.exposePrivilegeSet = async (req, res, next) => {
|
||||||
// Exposes a user's global privilege set
|
// Exposes a user's global/admin privilege set
|
||||||
res.locals.privileges = await privileges.global.get(req.user.uid);
|
res.locals.privileges = { ...await privileges.global.get(req.user.uid), ...await privileges.admin.get(req.user.uid) };
|
||||||
return next();
|
return next();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -169,6 +169,23 @@ Plugins.reload = async function () {
|
|||||||
return { plugin, settings, quiet };
|
return { plugin, settings, quiet };
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Plugins.registerHook('core', {
|
||||||
|
hook: 'filter:settings.get',
|
||||||
|
method: async ({ plugin, values }) => {
|
||||||
|
if (plugin === 'core.api' && Array.isArray(values.tokens)) {
|
||||||
|
values.tokens = values.tokens.map((tokenObj) => {
|
||||||
|
tokenObj.uid = parseInt(tokenObj.uid, 10);
|
||||||
|
if (tokenObj.timestamp) {
|
||||||
|
tokenObj.timestampISO = new Date(parseInt(tokenObj.timestamp, 10)).toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenObj;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { plugin, values };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Lower priority runs earlier
|
// Lower priority runs earlier
|
||||||
Object.keys(Plugins.loadedHooks).forEach(function (hook) {
|
Object.keys(Plugins.loadedHooks).forEach(function (hook) {
|
||||||
|
|||||||
@@ -29,51 +29,8 @@ function authenticatedRoutes() {
|
|||||||
setupApiRoute(router, '/:uid/ban', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivileges], 'put', controllers.write.users.ban);
|
setupApiRoute(router, '/:uid/ban', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivileges], 'put', controllers.write.users.ban);
|
||||||
setupApiRoute(router, '/:uid/ban', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivileges], 'delete', controllers.write.users.unban);
|
setupApiRoute(router, '/:uid/ban', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivileges], 'delete', controllers.write.users.unban);
|
||||||
|
|
||||||
/**
|
setupApiRoute(router, '/:uid/tokens', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivilegeSet], 'post', controllers.write.users.generateToken);
|
||||||
* Chat routes were not migrated because chats may get refactored... also the logic is derpy
|
setupApiRoute(router, '/:uid/tokens/:token', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivilegeSet], 'delete', controllers.write.users.deleteToken);
|
||||||
* It also does not take into account multiple chats for a given user.
|
|
||||||
*/
|
|
||||||
// app.route('/:uid/chats')
|
|
||||||
// .post(apiMiddleware.requireUser, function(req, res) {
|
|
||||||
// if (!utils.checkRequired(['message'], req, res)) {
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var timestamp = parseInt(req.body.timestamp, 10) || Date.now();
|
|
||||||
|
|
||||||
// function addMessage(roomId) {
|
|
||||||
// Messaging.addMessage({
|
|
||||||
// uid: req.user.uid,
|
|
||||||
// roomId: roomId,
|
|
||||||
// content: req.body.message,
|
|
||||||
// timestamp: timestamp,
|
|
||||||
// }, function(err, message) {
|
|
||||||
// if (parseInt(req.body.quiet, 10) !== 1) {
|
|
||||||
// Messaging.notifyUsersInRoom(req.user.uid, roomId, message);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return errorHandler.handle(err, res, message);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Messaging.canMessageUser(req.user.uid, req.params.uid, function(err) {
|
|
||||||
// if (err) {
|
|
||||||
// return errorHandler.handle(err, res);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (req.body.roomId) {
|
|
||||||
// addMessage(req.body.roomId);
|
|
||||||
// } else {
|
|
||||||
// Messaging.newRoom(req.user.uid, [req.params.uid], function(err, roomId) {
|
|
||||||
// if (err) {
|
|
||||||
// return errorHandler.handle(err, res);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// addMessage(roomId);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement this later...
|
* Implement this later...
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<form>
|
<form>
|
||||||
<input type="hidden" name="token">
|
<input type="hidden" name="token" />
|
||||||
|
<input type="hidden" name="timestamp" />
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="uid">[[admin/settings/api:uid]]</label>
|
<label for="uid">[[admin/settings/api:uid]]</label>
|
||||||
<input type="number" name="uid" class="form-control" placeholder="1" min="0" />
|
<input type="number" name="uid" class="form-control" placeholder="1" min="0" />
|
||||||
|
|||||||
@@ -2,8 +2,16 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-9">
|
||||||
<span class="label label-primary">{{{ if uid }}}uid {uid}{{{ else }}}master{{{ end }}}</span>
|
<span class="label label-primary">{{{ if uid }}}uid {uid}{{{ else }}}master{{{ end }}}</span>
|
||||||
{{{ if token }}}<input type="text" readonly="readonly" value="{token}" size="32" />{{{ else }}}<em class="text-warning">Token will be generated once form is saved</em>{{{ end }}}<br />
|
{{{ if token }}}<input type="text" readonly="readonly" value="{token}" size="32" />{{{ else }}}<em class="text-warning">[[admin/settings/api:token-on-save]]</em>{{{ end }}}<br />
|
||||||
<small>{description}</small>
|
<p>
|
||||||
|
{{{ if description }}}
|
||||||
|
{description}
|
||||||
|
{{{ else }}}
|
||||||
|
<em>[[admin/settings/api:no-description]]</em>
|
||||||
|
{{{ end }}}
|
||||||
|
<br />
|
||||||
|
<small>{timestampISO}</small>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-3 text-right">
|
<div class="col-xs-3 text-right">
|
||||||
<button type="button" data-type="edit" class="btn btn-info">Edit</button>
|
<button type="button" data-type="edit" class="btn btn-info">Edit</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user