updated api permissions

This commit is contained in:
Andris Reinman 2018-10-12 11:13:54 +03:00
parent 70a5619c26
commit 5596f47a1a
14 changed files with 1709 additions and 2044 deletions

View file

@ -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

View file

@ -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" } });

View file

@ -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" } }

View file

@ -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();
});
});
})
);
};

View file

@ -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();
})
);
};

View file

@ -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();
})
);
};

File diff suppressed because it is too large Load diff

View file

@ -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(

File diff suppressed because it is too large Load diff

View file

@ -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);
}

View file

@ -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;

View file

@ -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(