mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-12-27 02:10:52 +08:00
updated api permissions
This commit is contained in:
parent
70a5619c26
commit
5596f47a1a
14 changed files with 1709 additions and 2044 deletions
|
@ -39,11 +39,32 @@
|
|||
"delete:any": ["*"]
|
||||
},
|
||||
|
||||
"autoreplies": {
|
||||
"create:any": ["*"],
|
||||
"read:any": ["*"],
|
||||
"update:any": ["*"],
|
||||
"delete:any": ["*"]
|
||||
},
|
||||
|
||||
"filters": {
|
||||
"create:any": ["*"],
|
||||
"read:any": ["*"],
|
||||
"update:any": ["*"],
|
||||
"delete:any": ["*"]
|
||||
},
|
||||
|
||||
"dkim": {
|
||||
"create:any": ["*"],
|
||||
"read:any": ["*"],
|
||||
"update:any": ["*"],
|
||||
"delete:any": ["*"]
|
||||
},
|
||||
|
||||
"domainaliases": {
|
||||
"create:any": ["*"],
|
||||
"read:any": ["*"],
|
||||
"update:any": ["*"],
|
||||
"delete:any": ["*"]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -82,6 +103,20 @@
|
|||
"read:own": ["*"],
|
||||
"update:own": ["*"],
|
||||
"delete:own": ["*"]
|
||||
},
|
||||
|
||||
"autoreplies": {
|
||||
"create:own": ["*"],
|
||||
"read:own": ["*"],
|
||||
"update:own": ["*"],
|
||||
"delete:own": ["*"]
|
||||
},
|
||||
|
||||
"filters": {
|
||||
"create:own": ["*"],
|
||||
"read:own": ["*"],
|
||||
"update:own": ["*"],
|
||||
"delete:own": ["*"]
|
||||
}
|
||||
},
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
define({
"name": "wildduck",
"version": "1.0.0",
"description": "WildDuck API docs",
"title": "WildDuck API",
"url": "https://api.wildduck.email",
"sampleUrl": false,
"defaultVersion": "0.0.0",
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2018-10-11T08:48:03.541Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
});
|
||||
define({
"name": "wildduck",
"version": "1.0.0",
"description": "WildDuck API docs",
"title": "WildDuck API",
"url": "https://api.wildduck.email",
"sampleUrl": false,
"defaultVersion": "0.0.0",
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2018-10-12T08:13:42.322Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
});
|
||||
|
|
|
@ -1 +1 @@
|
|||
{
"name": "wildduck",
"version": "1.0.0",
"description": "WildDuck API docs",
"title": "WildDuck API",
"url": "https://api.wildduck.email",
"sampleUrl": false,
"defaultVersion": "0.0.0",
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2018-10-11T08:48:03.541Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
}
|
||||
{
"name": "wildduck",
"version": "1.0.0",
"description": "WildDuck API docs",
"title": "WildDuck API",
"url": "https://api.wildduck.email",
"sampleUrl": false,
"defaultVersion": "0.0.0",
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2018-10-12T08:13:42.322Z",
"url": "http://apidocjs.com",
"version": "0.17.6"
}
}
|
||||
|
|
|
@ -2,11 +2,17 @@
|
|||
|
||||
const Joi = require('joi');
|
||||
const ObjectID = require('mongodb').ObjectID;
|
||||
const tools = require('../../tools');
|
||||
const roles = require('../../roles');
|
||||
const util = require('util');
|
||||
|
||||
// Custom 2FA needs to be enabled if your website handles its own 2FA and you want to disable
|
||||
// master password usage for IMAP/POP/SMTP clients
|
||||
|
||||
module.exports = (db, server, userHandler) => {
|
||||
const enableCustom2fa = util.promisify(userHandler.enableCustom2fa.bind(userHandler));
|
||||
const disableCustom2fa = util.promisify(userHandler.disableCustom2fa.bind(userHandler));
|
||||
|
||||
/**
|
||||
* @api {put} /users/:user/2fa/custom Enable custom 2FA for an user
|
||||
* @apiName EnableCustom2FA
|
||||
|
@ -46,53 +52,54 @@ module.exports = (db, server, userHandler) => {
|
|||
* "code": "UserNotFound"
|
||||
* }
|
||||
*/
|
||||
server.put('/users/:user/2fa/custom', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.put(
|
||||
'/users/:user/2fa/custom',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
userHandler.enableCustom2fa(user, result.value, (err, success) => {
|
||||
if (err) {
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: err.message,
|
||||
code: err.code
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
// permissions check
|
||||
if (req.user && req.user === result.value.user) {
|
||||
req.validate(roles.can(req.role).updateOwn('users'));
|
||||
} else {
|
||||
req.validate(roles.can(req.role).updateAny('users'));
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
let success = await enableCustom2fa(user, result.value);
|
||||
|
||||
res.json({
|
||||
success
|
||||
});
|
||||
|
||||
return next();
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {delete} /users/:user/2fa/custom Disable custom 2FA for an user
|
||||
|
@ -133,53 +140,54 @@ module.exports = (db, server, userHandler) => {
|
|||
* "code": "UserNotFound"
|
||||
* }
|
||||
*/
|
||||
server.del('/users/:user/2fa/custom', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.del(
|
||||
'/users/:user/2fa/custom',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
req.query.user = req.params.user;
|
||||
|
||||
const result = Joi.validate(req.query, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
req.query.user = req.params.user;
|
||||
|
||||
userHandler.disableCustom2fa(user, result.value, (err, success) => {
|
||||
if (err) {
|
||||
const result = Joi.validate(req.query, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: err.message,
|
||||
code: err.code
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
// permissions check
|
||||
if (req.user && req.user === result.value.user) {
|
||||
req.validate(roles.can(req.role).updateOwn('users'));
|
||||
} else {
|
||||
req.validate(roles.can(req.role).updateAny('users'));
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
let success = await disableCustom2fa(user, result.value);
|
||||
|
||||
res.json({
|
||||
success
|
||||
});
|
||||
|
||||
return next();
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
const Joi = require('joi');
|
||||
const ObjectID = require('mongodb').ObjectID;
|
||||
const tools = require('../tools');
|
||||
const roles = require('../roles');
|
||||
|
||||
module.exports = (db, server) => {
|
||||
/**
|
||||
|
@ -49,93 +51,98 @@ module.exports = (db, server) => {
|
|||
* "error": "This user does not exist"
|
||||
* }
|
||||
*/
|
||||
server.put('/users/:user/autoreply', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.put(
|
||||
'/users/:user/autoreply',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
status: Joi.boolean()
|
||||
.truthy(['Y', 'true', 'yes', 'on', '1', 1])
|
||||
.falsy(['N', 'false', 'no', 'off', '0', 0, ''])
|
||||
.default(false),
|
||||
name: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128),
|
||||
subject: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128),
|
||||
text: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128 * 1024),
|
||||
html: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128 * 1024),
|
||||
start: Joi.date()
|
||||
.empty('')
|
||||
.allow(false),
|
||||
end: Joi.date()
|
||||
.empty('')
|
||||
.allow(false),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
status: Joi.boolean()
|
||||
.truthy(['Y', 'true', 'yes', 'on', '1', 1])
|
||||
.falsy(['N', 'false', 'no', 'off', '0', 0, ''])
|
||||
.default(false),
|
||||
name: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128),
|
||||
subject: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128),
|
||||
text: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128 * 1024),
|
||||
html: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(128 * 1024),
|
||||
start: Joi.date()
|
||||
.empty('')
|
||||
.allow(false),
|
||||
end: Joi.date()
|
||||
.empty('')
|
||||
.allow(false),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!result.value.name && 'name' in req.params) {
|
||||
result.value.name = '';
|
||||
}
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (!result.value.subject && 'subject' in req.params) {
|
||||
result.value.subject = '';
|
||||
}
|
||||
|
||||
if (!result.value.text && 'text' in req.params) {
|
||||
result.value.text = '';
|
||||
if (!result.value.html) {
|
||||
// make sure we also update html part
|
||||
result.value.html = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.value.html && 'html' in req.params) {
|
||||
result.value.html = '';
|
||||
if (!result.value.text) {
|
||||
// make sure we also update plaintext part
|
||||
result.value.text = '';
|
||||
}
|
||||
}
|
||||
|
||||
let user = (result.value.user = new ObjectID(result.value.user));
|
||||
db.users.collection('users').updateOne({ _id: user }, { $set: { autoreply: result.value.status } }, (err, r) => {
|
||||
if (err) {
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: err.message
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
// permissions check
|
||||
if (req.user && req.user === result.value.user) {
|
||||
req.validate(roles.can(req.role).updateOwn('autoreplies'));
|
||||
} else {
|
||||
req.validate(roles.can(req.role).updateAny('autoreplies'));
|
||||
}
|
||||
|
||||
if (!result.value.name && 'name' in req.params) {
|
||||
result.value.name = '';
|
||||
}
|
||||
|
||||
if (!result.value.subject && 'subject' in req.params) {
|
||||
result.value.subject = '';
|
||||
}
|
||||
|
||||
if (!result.value.text && 'text' in req.params) {
|
||||
result.value.text = '';
|
||||
if (!result.value.html) {
|
||||
// make sure we also update html part
|
||||
result.value.html = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.value.html && 'html' in req.params) {
|
||||
result.value.html = '';
|
||||
if (!result.value.text) {
|
||||
// make sure we also update plaintext part
|
||||
result.value.text = '';
|
||||
}
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
|
||||
let r = await db.users.collection('users').updateOne({ _id: user }, { $set: { autoreply: result.value.status } });
|
||||
|
||||
if (!r.matchedCount) {
|
||||
res.json({
|
||||
error: 'Unknown user'
|
||||
|
@ -143,23 +150,16 @@ module.exports = (db, server) => {
|
|||
return next();
|
||||
}
|
||||
|
||||
db.database.collection('autoreplies').updateOne({ user }, { $set: result.value }, { upsert: true }, (err, r) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: err.message
|
||||
});
|
||||
return next();
|
||||
}
|
||||
r = await db.database.collection('autoreplies').updateOne({ user }, { $set: result.value }, { upsert: true });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
id: r.insertedId
|
||||
});
|
||||
|
||||
return next();
|
||||
res.json({
|
||||
success: true,
|
||||
id: r.insertedId
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return next();
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {get} /users/:user/autoreply Request Autoreply information
|
||||
|
@ -206,45 +206,48 @@ module.exports = (db, server) => {
|
|||
* "error": "This user does not exist"
|
||||
* }
|
||||
*/
|
||||
server.get('/users/:user/autoreply', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.get(
|
||||
'/users/:user/autoreply',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
db.database.collection('autoreplies').findOne({ user }, (err, entry) => {
|
||||
if (err) {
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: err.message
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
// permissions check
|
||||
if (req.user && req.user === result.value.user) {
|
||||
req.validate(roles.can(req.role).readOwn('autoreplies'));
|
||||
} else {
|
||||
req.validate(roles.can(req.role).readAny('autoreplies'));
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
|
||||
let entry = await db.database.collection('autoreplies').findOne({ user });
|
||||
|
||||
entry = entry || {};
|
||||
res.json({
|
||||
success: true,
|
||||
|
@ -253,13 +256,13 @@ module.exports = (db, server) => {
|
|||
subject: entry.subject || '',
|
||||
text: entry.text || '',
|
||||
html: entry.html || '',
|
||||
start: entry.start,
|
||||
end: entry.end
|
||||
start: entry.start || false,
|
||||
end: entry.end || false
|
||||
});
|
||||
|
||||
return next();
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {delete} /users/:user/autoreply Delete Autoreply information
|
||||
|
@ -292,59 +295,54 @@ module.exports = (db, server) => {
|
|||
* "error": "This user does not exist"
|
||||
* }
|
||||
*/
|
||||
server.del('/users/:user/autoreply', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.del(
|
||||
'/users/:user/autoreply',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
user: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let user = new ObjectID(result.value.user);
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
db.users.collection('users').updateOne({ _id: user }, { $set: { autoreply: false } }, err => {
|
||||
if (err) {
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: err.message
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
db.database.collection('autoreplies').deleteOne({ user }, err => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: err.message
|
||||
});
|
||||
return next();
|
||||
}
|
||||
// permissions check
|
||||
if (req.user && req.user === result.value.user) {
|
||||
req.validate(roles.can(req.role).deleteOwn('autoreplies'));
|
||||
} else {
|
||||
req.validate(roles.can(req.role).deleteAny('autoreplies'));
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
let user = new ObjectID(result.value.user);
|
||||
|
||||
return next();
|
||||
await db.users.collection('users').updateOne({ _id: user }, { $set: { autoreply: false } });
|
||||
await db.database.collection('autoreplies').deleteOne({ user });
|
||||
|
||||
res.json({
|
||||
success: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return next();
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ const Joi = require('../joi');
|
|||
const MongoPaging = require('mongo-cursor-pagination');
|
||||
const ObjectID = require('mongodb').ObjectID;
|
||||
const tools = require('../tools');
|
||||
const roles = require('../roles');
|
||||
|
||||
module.exports = (db, server) => {
|
||||
/**
|
||||
|
@ -104,6 +105,9 @@ module.exports = (db, server) => {
|
|||
return next();
|
||||
}
|
||||
|
||||
// permissions check
|
||||
req.validate(roles.can(req.role).readAny('domainaliases'));
|
||||
|
||||
let query = result.value.query;
|
||||
let limit = result.value.limit;
|
||||
let page = result.value.page;
|
||||
|
@ -229,92 +233,99 @@ module.exports = (db, server) => {
|
|||
* "error": "This user does not exist"
|
||||
* }
|
||||
*/
|
||||
server.post('/domainaliases', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.post(
|
||||
'/domainaliases',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.max(255)
|
||||
//.hostname()
|
||||
.required(),
|
||||
domain: Joi.string()
|
||||
.max(255)
|
||||
//.hostname()
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.max(255)
|
||||
//.hostname()
|
||||
.required(),
|
||||
domain: Joi.string()
|
||||
.max(255)
|
||||
//.hostname()
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let alias = tools.normalizeDomain(req.params.alias);
|
||||
let domain = tools.normalizeDomain(req.params.domain);
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
alias
|
||||
},
|
||||
{
|
||||
projection: { _id: 1 }
|
||||
},
|
||||
(err, aliasData) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
if (aliasData) {
|
||||
res.json({
|
||||
error: 'This domain alias already exists',
|
||||
code: 'AliasExists'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
// insert alias address to email address registry
|
||||
db.users.collection('domainaliases').insertOne(
|
||||
// permissions check
|
||||
req.validate(roles.can(req.role).createAny('domainaliases'));
|
||||
|
||||
let alias = tools.normalizeDomain(req.params.alias);
|
||||
let domain = tools.normalizeDomain(req.params.domain);
|
||||
|
||||
let aliasData;
|
||||
|
||||
try {
|
||||
aliasData = await db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
alias,
|
||||
domain,
|
||||
created: new Date()
|
||||
alias
|
||||
},
|
||||
(err, r) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let insertId = r.insertedId;
|
||||
|
||||
res.json({
|
||||
success: !!insertId,
|
||||
id: insertId
|
||||
});
|
||||
return next();
|
||||
{
|
||||
projection: { _id: 1 }
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
if (aliasData) {
|
||||
res.json({
|
||||
error: 'This domain alias already exists',
|
||||
code: 'AliasExists'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let r;
|
||||
|
||||
try {
|
||||
// insert alias address to email address registry
|
||||
r = await db.users.collection('domainaliases').insertOne({
|
||||
alias,
|
||||
domain,
|
||||
created: new Date()
|
||||
});
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let insertId = r.insertedId;
|
||||
|
||||
res.json({
|
||||
success: !!insertId,
|
||||
id: insertId
|
||||
});
|
||||
return next();
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {get} /domainaliases/resolve/:alias Resolve ID for a domain aias
|
||||
|
@ -349,67 +360,74 @@ module.exports = (db, server) => {
|
|||
* "error": "This alias does not exist"
|
||||
* }
|
||||
*/
|
||||
server.get('/domainaliases/resolve/:alias', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.get(
|
||||
'/domainaliases/resolve/:alias',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.max(255)
|
||||
//.hostname()
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.max(255)
|
||||
//.hostname()
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let alias = tools.normalizeDomain(result.value.alias);
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
alias
|
||||
},
|
||||
{
|
||||
projection: { _id: 1 }
|
||||
},
|
||||
(err, aliasData) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
if (!aliasData) {
|
||||
res.json({
|
||||
error: 'This alias does not exist',
|
||||
code: 'AliasNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
if (result.error) {
|
||||
res.json({
|
||||
success: true,
|
||||
id: aliasData._id
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// permissions check
|
||||
req.validate(roles.can(req.role).readAny('domainaliases'));
|
||||
|
||||
let alias = tools.normalizeDomain(result.value.alias);
|
||||
|
||||
let aliasData;
|
||||
try {
|
||||
aliasData = await db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
alias
|
||||
},
|
||||
{
|
||||
projection: { _id: 1 }
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!aliasData) {
|
||||
res.json({
|
||||
error: 'This alias does not exist',
|
||||
code: 'AliasNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
id: aliasData._id
|
||||
});
|
||||
|
||||
return next();
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {get} /domainaliases/:alias Request Alias information
|
||||
|
@ -450,70 +468,75 @@ module.exports = (db, server) => {
|
|||
* "error": "This Alias does not exist"
|
||||
* }
|
||||
*/
|
||||
server.get('/domainaliases/:alias', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.get(
|
||||
'/domainaliases/:alias',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let alias = new ObjectID(result.value.alias);
|
||||
|
||||
db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
_id: alias
|
||||
},
|
||||
(err, aliasData) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
if (!aliasData) {
|
||||
res.status(404);
|
||||
res.json({
|
||||
error: 'Invalid or unknown alias',
|
||||
code: 'AliasNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
success: true,
|
||||
id: aliasData._id,
|
||||
alias: aliasData.alias,
|
||||
domain: aliasData.domain,
|
||||
created: aliasData.created
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// permissions check
|
||||
req.validate(roles.can(req.role).readAny('domainaliases'));
|
||||
|
||||
let alias = new ObjectID(result.value.alias);
|
||||
|
||||
let aliasData;
|
||||
try {
|
||||
aliasData = await db.users.collection('domainaliases').findOne({
|
||||
_id: alias
|
||||
});
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!aliasData) {
|
||||
res.status(404);
|
||||
res.json({
|
||||
error: 'Invalid or unknown alias',
|
||||
code: 'AliasNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
id: aliasData._id,
|
||||
alias: aliasData.alias,
|
||||
domain: aliasData.domain,
|
||||
created: aliasData.created
|
||||
});
|
||||
|
||||
return next();
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* @api {delete} /domainaliases/:alias Delete an Alias
|
||||
|
@ -546,83 +569,87 @@ module.exports = (db, server) => {
|
|||
* "error": "Database error"
|
||||
* }
|
||||
*/
|
||||
server.del('/domainaliases/:alias', (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
server.del(
|
||||
'/domainaliases/:alias',
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
res.charSet('utf-8');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
const schema = Joi.object().keys({
|
||||
alias: Joi.string()
|
||||
.hex()
|
||||
.lowercase()
|
||||
.length(24)
|
||||
.required(),
|
||||
sess: Joi.string().max(255),
|
||||
ip: Joi.string().ip({
|
||||
version: ['ipv4', 'ipv6'],
|
||||
cidr: 'forbidden'
|
||||
})
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let alias = new ObjectID(result.value.alias);
|
||||
const result = Joi.validate(req.params, schema, {
|
||||
abortEarly: false,
|
||||
convert: true
|
||||
});
|
||||
|
||||
db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
_id: alias
|
||||
},
|
||||
{
|
||||
projection: { _id: 1 }
|
||||
},
|
||||
(err, aliasData) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
if (result.error) {
|
||||
res.json({
|
||||
error: result.error.message,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!aliasData) {
|
||||
res.status(404);
|
||||
res.json({
|
||||
error: 'Invalid or unknown email alias identifier',
|
||||
code: 'AliasNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
// permissions check
|
||||
req.validate(roles.can(req.role).deleteAny('domainaliases'));
|
||||
|
||||
// delete address from email address registry
|
||||
db.users.collection('domainaliases').deleteOne(
|
||||
let alias = new ObjectID(result.value.alias);
|
||||
|
||||
let aliasData;
|
||||
try {
|
||||
aliasData = await db.users.collection('domainaliases').findOne(
|
||||
{
|
||||
_id: alias
|
||||
},
|
||||
(err, r) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: !!r.deletedCount
|
||||
});
|
||||
return next();
|
||||
{
|
||||
projection: { _id: 1 }
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
if (!aliasData) {
|
||||
res.status(404);
|
||||
res.json({
|
||||
error: 'Invalid or unknown email alias identifier',
|
||||
code: 'AliasNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let r;
|
||||
try {
|
||||
// delete address from email address registry
|
||||
r = await db.users.collection('domainaliases').deleteOne({
|
||||
_id: alias
|
||||
});
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: !!r.deletedCount
|
||||
});
|
||||
return next();
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
1519
lib/api/filters.js
1519
lib/api/filters.js
File diff suppressed because it is too large
Load diff
|
@ -85,7 +85,7 @@ module.exports = (db, server, mailboxHandler) => {
|
|||
* @apiErrorExample {json} Error-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "error": "This mailbox does not exist"
|
||||
* "error": "Database error"
|
||||
* }
|
||||
*/
|
||||
server.get(
|
||||
|
|
1165
lib/api/messages.js
1165
lib/api/messages.js
File diff suppressed because it is too large
Load diff
|
@ -1336,6 +1336,7 @@ module.exports = (db, server, userHandler) => {
|
|||
}
|
||||
req.validate(permission);
|
||||
result.value = permission.filter(result.value);
|
||||
|
||||
if (result.value.audit) {
|
||||
result.value.audit = new ObjectID(result.value.audit);
|
||||
}
|
||||
|
|
|
@ -209,7 +209,9 @@ class ImapNotifier extends EventEmitter {
|
|||
}
|
||||
|
||||
if (!mailboxData) {
|
||||
return callback(null, new Error('Selected mailbox does not exist'));
|
||||
let err = new Error('Selected mailbox does not exist');
|
||||
err.code = 'NoSuchMailbox';
|
||||
return callback(null, err);
|
||||
}
|
||||
|
||||
let modseq = mailboxData.modifyIndex;
|
||||
|
|
4
pop3.js
4
pop3.js
|
@ -302,7 +302,9 @@ function markAsSeen(session, messages, callback) {
|
|||
|
||||
let mailboxData = item && item.value;
|
||||
if (!item) {
|
||||
return callback(new Error('Mailbox does not exist'));
|
||||
let err = new Error('Selected mailbox does not exist');
|
||||
err.code = 'NoSuchMailbox';
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
db.database.collection('messages').updateMany(
|
||||
|
|
Loading…
Reference in a new issue