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": "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>

Loading…
Cancel
Save