feat(writeapi): token generation/delete routes, ACP updates

v1.18.x
Julian Lam 4 years ago
parent 2928b9b87a
commit 2ec838fc59

@ -6,5 +6,7 @@
"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",
"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 events = require('../../events');
const translator = require('../../translator');
const utils = require('../../utils');
const db = require('../../database');
const helpers = require('../helpers');
@ -218,3 +219,40 @@ Users.unban = async (req, 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) => {
// Exposes a user's global privilege set
res.locals.privileges = await privileges.global.get(req.user.uid);
// Exposes a user's global/admin privilege set
res.locals.privileges = { ...await privileges.global.get(req.user.uid), ...await privileges.admin.get(req.user.uid) };
return next();
};
};

@ -169,6 +169,23 @@ Plugins.reload = async function () {
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
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], 'delete', controllers.write.users.unban);
/**
* Chat routes were not migrated because chats may get refactored... also the logic is derpy
* 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);
// });
// }
// });
// });
setupApiRoute(router, '/:uid/tokens', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivilegeSet], 'post', controllers.write.users.generateToken);
setupApiRoute(router, '/:uid/tokens/:token', middleware, [...middlewares, middleware.assertUser, middleware.exposePrivilegeSet], 'delete', controllers.write.users.deleteToken);
/**
* Implement this later...

@ -1,5 +1,6 @@
<form>
<input type="hidden" name="token">
<input type="hidden" name="token" />
<input type="hidden" name="timestamp" />
<div class="form-group">
<label for="uid">[[admin/settings/api:uid]]</label>
<input type="number" name="uid" class="form-control" placeholder="1" min="0" />

@ -2,8 +2,16 @@
<div class="row">
<div class="col-xs-9">
<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 />
<small>{description}</small>
{{{ 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 />
<p>
{{{ if description }}}
{description}
{{{ else }}}
<em>[[admin/settings/api:no-description]]</em>
{{{ end }}}
<br />
<small>{timestampISO}</small>
</p>
</div>
<div class="col-xs-3 text-right">
<button type="button" data-type="edit" class="btn btn-info">Edit</button>

Loading…
Cancel
Save