mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-12-26 18:01:01 +08:00
started testing with roles
This commit is contained in:
parent
78da5dce42
commit
beca0b1e33
7 changed files with 1587 additions and 1461 deletions
61
api.js
61
api.js
|
@ -10,6 +10,8 @@ const MessageHandler = require('./lib/message-handler');
|
||||||
const ImapNotifier = require('./lib/imap-notifier');
|
const ImapNotifier = require('./lib/imap-notifier');
|
||||||
const db = require('./lib/db');
|
const db = require('./lib/db');
|
||||||
const certs = require('./lib/certs');
|
const certs = require('./lib/certs');
|
||||||
|
const ObjectID = require('mongodb').ObjectID;
|
||||||
|
const rootUser = new ObjectID('0'.repeat(24));
|
||||||
|
|
||||||
const usersRoutes = require('./lib/api/users');
|
const usersRoutes = require('./lib/api/users');
|
||||||
const addressesRoutes = require('./lib/api/addresses');
|
const addressesRoutes = require('./lib/api/addresses');
|
||||||
|
@ -79,21 +81,64 @@ server.use(
|
||||||
);
|
);
|
||||||
|
|
||||||
server.use((req, res, next) => {
|
server.use((req, res, next) => {
|
||||||
if (config.api.accessToken && ![req.query.accessToken, req.headers['x-access-token']].includes(config.api.accessToken)) {
|
let accessToken = req.query.accessToken || req.headers['x-access-token'] || false;
|
||||||
res.status(403);
|
|
||||||
res.charSet('utf-8');
|
|
||||||
return res.json({
|
|
||||||
error: 'Invalid accessToken value'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (req.query.accessToken) {
|
if (req.query.accessToken) {
|
||||||
delete 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();
|
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(
|
server.use(
|
||||||
logger(':method :url :status :time-spent :append', {
|
logger(':remote-addr :user :method :url :status :time-spent :append', {
|
||||||
stream: {
|
stream: {
|
||||||
write: message => {
|
write: message => {
|
||||||
message = (message || '').toString();
|
message = (message || '').toString();
|
||||||
|
|
|
@ -19,6 +19,9 @@ enabled=false
|
||||||
#cipher="aes192"
|
#cipher="aes192"
|
||||||
#secret="a secret cat"
|
#secret="a secret cat"
|
||||||
|
|
||||||
|
[roles]
|
||||||
|
# @include "roles.json"
|
||||||
|
|
||||||
[tls]
|
[tls]
|
||||||
# If certificate path is not defined, use global or built-in self-signed certs
|
# If certificate path is not defined, use global or built-in self-signed certs
|
||||||
#key="/path/to/server/key.pem"
|
#key="/path/to/server/key.pem"
|
||||||
|
|
10
config/roles.json
Normal file
10
config/roles.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"root": {
|
||||||
|
"addresses": {
|
||||||
|
"create:any": ["*"],
|
||||||
|
"read:any": ["*"],
|
||||||
|
"update:any": ["*"],
|
||||||
|
"delete:any": ["*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2945
lib/api/addresses.js
2945
lib/api/addresses.js
File diff suppressed because it is too large
Load diff
13
lib/roles.js
Normal file
13
lib/roles.js
Normal 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);
|
15
lib/tools.js
15
lib/tools.js
|
@ -488,9 +488,20 @@ module.exports = {
|
||||||
try {
|
try {
|
||||||
await middleware(req, res, next);
|
await middleware(req, res, next);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.json({
|
let data = {
|
||||||
error: err.message
|
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();
|
return next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"request": "2.88.0"
|
"request": "2.88.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"accesscontrol": "^2.2.1",
|
||||||
"base32.js": "0.1.0",
|
"base32.js": "0.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bugsnag": "2.4.3",
|
"bugsnag": "2.4.3",
|
||||||
|
|
Loading…
Reference in a new issue