started testing with roles

This commit is contained in:
Andris Reinman 2018-08-28 14:37:06 +03:00
parent 78da5dce42
commit beca0b1e33
7 changed files with 1587 additions and 1461 deletions

61
api.js
View file

@ -10,6 +10,8 @@ const MessageHandler = require('./lib/message-handler');
const ImapNotifier = require('./lib/imap-notifier');
const db = require('./lib/db');
const certs = require('./lib/certs');
const ObjectID = require('mongodb').ObjectID;
const rootUser = new ObjectID('0'.repeat(24));
const usersRoutes = require('./lib/api/users');
const addressesRoutes = require('./lib/api/addresses');
@ -79,21 +81,64 @@ server.use(
);
server.use((req, res, next) => {
if (config.api.accessToken && ![req.query.accessToken, req.headers['x-access-token']].includes(config.api.accessToken)) {
res.status(403);
res.charSet('utf-8');
return res.json({
error: 'Invalid accessToken value'
});
}
let accessToken = req.query.accessToken || req.headers['x-access-token'] || false;
if (req.query.accessToken) {
delete req.query.accessToken;
}
let tokenRequired = false;
let fail = () => {
res.status(403);
res.charSet('utf-8');
return res.json({
error: 'Invalid accessToken value',
code: 'InvalidToken'
});
};
req.validate = permission => {
if (!permission.granted) {
let err = new Error('Not enough privileges');
err.responseCode = 403;
err.code = 'MissingPrivileges';
throw err;
}
};
// hard coded master token
if (config.api.accessToken) {
tokenRequired = true;
if (config.api.accessToken === accessToken) {
req.role = 'root';
req.user = rootUser;
return next();
}
}
// TODO: dynamically allocated tokens
if (tokenRequired) {
// no valid token found
return fail();
}
// allow all
req.role = 'root';
req.user = rootUser;
next();
});
logger.token('user', req => (req.user && req.user.toString()) || '?'.repeat(24));
logger.token('url', req => {
if (/\baccessToken=/.test(req.url)) {
return req.url.replace(/\baccessToken=[^&]+/g, 'accessToken=' + 'x'.repeat(6));
}
return req.url;
});
server.use(
logger(':method :url :status :time-spent :append', {
logger(':remote-addr :user :method :url :status :time-spent :append', {
stream: {
write: message => {
message = (message || '').toString();

View file

@ -19,6 +19,9 @@ enabled=false
#cipher="aes192"
#secret="a secret cat"
[roles]
# @include "roles.json"
[tls]
# If certificate path is not defined, use global or built-in self-signed certs
#key="/path/to/server/key.pem"

10
config/roles.json Normal file
View file

@ -0,0 +1,10 @@
{
"root": {
"addresses": {
"create:any": ["*"],
"read:any": ["*"],
"update:any": ["*"],
"delete:any": ["*"]
}
}
}

File diff suppressed because it is too large Load diff

13
lib/roles.js Normal file
View file

@ -0,0 +1,13 @@
'use strict';
const config = require('wild-config');
const AccessControl = require('accesscontrol');
const ac = new AccessControl();
ac.setGrants(config.api.roles);
config.on('reload', () => {
ac.setGrants(config.api.roles);
});
module.exports.can = role => ac.can(role);

View file

@ -488,9 +488,20 @@ module.exports = {
try {
await middleware(req, res, next);
} catch (err) {
res.json({
let data = {
error: err.message
});
};
if (err.responseCode) {
res.status(err.responseCode);
}
if (err.code) {
data.code = err.code;
}
res.charSet('utf-8');
res.json(data);
return next();
}
}

View file

@ -36,6 +36,7 @@
"request": "2.88.0"
},
"dependencies": {
"accesscontrol": "^2.2.1",
"base32.js": "0.1.0",
"bcryptjs": "2.4.3",
"bugsnag": "2.4.3",