updated ASP handling

This commit is contained in:
Andris Reinman 2018-01-11 11:20:12 +02:00
parent dc552ae1c5
commit 5a09cfb14a
7 changed files with 72 additions and 75 deletions

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. Under construction, see old docs here: https://github.com/nodemailer/wildduck/blob/master/docs/api.md", "title": "WildDuck API", "url": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-01-09T12:03:14.104Z", "url": "http://apidocjs.com", "version": "0.17.6" } });
define({ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs. Under construction, see old docs here: https://github.com/nodemailer/wildduck/blob/master/docs/api.md", "title": "WildDuck API", "url": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-01-11T09:18:19.445Z", "url": "http://apidocjs.com", "version": "0.17.6" } });

View file

@ -1 +1 @@
{ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs. Under construction, see old docs here: https://github.com/nodemailer/wildduck/blob/master/docs/api.md", "title": "WildDuck API", "url": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-01-09T12:03:14.104Z", "url": "http://apidocjs.com", "version": "0.17.6" } }
{ "name": "wildduck", "version": "1.0.0", "description": "WildDuck API docs. Under construction, see old docs here: https://github.com/nodemailer/wildduck/blob/master/docs/api.md", "title": "WildDuck API", "url": "http://localhost:8080", "sampleUrl": false, "defaultVersion": "0.0.0", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2018-01-11T09:18:19.445Z", "url": "http://apidocjs.com", "version": "0.17.6" } }

View file

@ -104,16 +104,6 @@ indexes:
name: asps_user
key:
user: 1
active: 1
expires: 1
- collection: asps
index:
name: asps_autoexpire
# autoremove expired asps entries after 180 days
expireAfterSeconds: 15552000
key:
expires: 1
# Indexes for the authentication log collection
- collection: authlog

View file

@ -25,8 +25,8 @@ module.exports = (db, server, userHandler) => {
* @apiSuccess {String} results.id ID of the Application Password
* @apiSuccess {String} results.description Description
* @apiSuccess {String[]} results.scopes Allowed scopes for the Application Password
* @apiSuccess {String} results.used Datestring of last use or false if password has not been used
* @apiSuccess {String} results.created Datestring
* @apiSuccess {String} results.expires Datestring if this is a temporary Application Password or <code>false</code> if not
*
* @apiError error Description of the error
*
@ -45,8 +45,8 @@ module.exports = (db, server, userHandler) => {
* "imap",
* "smtp"
* ],
* "created": "2017-11-28T14:08:23.520Z",
* "expires": false
* "used": false,
* "created": "2017-11-28T14:08:23.520Z"
* }
* ]
* }
@ -111,16 +111,7 @@ module.exports = (db, server, userHandler) => {
db.users
.collection('asps')
.find({
user,
active: true,
$or: [
{
expires: false
},
{
expires: { $gt: new Date() }
}
]
user
})
.sort({ _id: 1 })
.toArray((err, asps) => {
@ -143,8 +134,8 @@ module.exports = (db, server, userHandler) => {
id: asp._id,
description: asp.description,
scopes: asp.scopes,
created: asp.created,
expires: asp.expires
used: asp.used || false,
created: asp.created
}))
});
@ -167,7 +158,6 @@ module.exports = (db, server, userHandler) => {
* @apiParam {String} user ID of the User
* @apiParam {String} description Description
* @apiParam {String[]} scopes List of scopes this Password applies to. Special scope "*" indicates that this password can be used for any scope except "master"
* @apiParam {String} [expires] Datestring if this is a temporary Application Password
* @apiParam {Boolean} [generateMobileconfig] If true then result contains a mobileconfig formatted file with account config
* @apiParam {String} [sess] Session identifier for the logs
* @apiParam {String} [ip] IP address for the logs
@ -227,7 +217,6 @@ module.exports = (db, server, userHandler) => {
.truthy(['Y', 'true', 'yes', 'on', 1])
.falsy(['N', 'false', 'no', 'off', 0, ''])
.default(false),
expires: Joi.date(),
sess: Joi.string().max(255),
ip: Joi.string().ip({
version: ['ipv4', 'ipv6'],

View file

@ -437,16 +437,7 @@ class UserHandler {
this.users
.collection('asps')
.find({
user: userData._id,
active: true,
$or: [
{
expires: false
},
{
expires: { $gt: new Date() }
}
]
user: userData._id
})
.toArray((err, asps) => {
if (err) {
@ -488,22 +479,42 @@ class UserHandler {
if (!asp.scopes.includes('*') && !asp.scopes.includes(requiredScope)) {
meta.result = 'fail';
meta.source = 'asp';
meta.asp = asp._id.toString();
meta.asp = asp._id;
meta.aname = asp.description;
return this.logAuthEvent(userData._id, meta, () => authFail(new Error('Authentication failed. Invalid scope')));
}
meta.result = 'success';
meta.source = 'asp';
meta.asp = asp._id.toString();
return this.logAuthEvent(userData._id, meta, () => {
meta.asp = asp._id;
meta.aname = asp.description;
this.logAuthEvent(userData._id, meta, (err, r) => {
if (err) {
// don't really care
}
this.redis.del(rlkey, () => false);
authSuccess(null, {
user: userData._id,
username: userData.username,
scope: requiredScope,
asp: asp._id.toString(),
require2fa: false // application scope never requires 2FA
});
this.users.collection('asps').findOneAndUpdate(
{
_id: asp._id
},
{
$set: {
used: new Date(),
authEvent: r.insertedId
}
},
() => {
authSuccess(null, {
user: userData._id,
username: userData.username,
scope: requiredScope,
asp: asp._id.toString(),
require2fa: false // application scope never requires 2FA
});
}
);
});
});
};
@ -586,8 +597,6 @@ class UserHandler {
scopes,
password: bcrypt.hashSync(password, consts.BCRYPT_ROUNDS),
selector,
active: true,
expires: data.expires || false,
created: new Date()
};
@ -622,6 +631,7 @@ class UserHandler {
{
action: 'create asp',
asp: passwordData._id,
aname: passwordData.description,
result: 'success',
sess: data.session,
ip: data.ip
@ -638,38 +648,46 @@ class UserHandler {
}
deleteASP(user, asp, data, callback) {
return this.users.collection('asps').findOneAndUpdate(
return this.users.collection('asps').findOne(
{
_id: asp,
user
},
{
$set: {
active: false,
expires: new Date()
}
},
(err, result) => {
(err, asp) => {
if (err) {
err.code = 'InternalDatabaseError';
return callback(err);
}
if (!result || !result.value) {
return callback(new Error('Application Specific Password was not found'));
if (!asp) {
let err = new Error('Application Specific Password was not found');
err.code = 'AspNotFound';
return callback(err);
}
return this.logAuthEvent(
user,
{
action: 'delete asp',
asp,
result: 'success',
sess: data.session,
ip: data.ip
},
() => callback(null, true)
);
this.users.collection('asps').deleteOne({ _id: asp._id }, (err, r) => {
if (err) {
err.code = 'InternalDatabaseError';
return callback(err);
}
if (r.deletedCount) {
return this.logAuthEvent(
user,
{
action: 'delete asp',
asp: asp._id,
aname: asp.description,
result: 'success',
sess: data.session,
ip: data.ip
},
() => callback(null, true)
);
} else {
return callback(null, true);
}
});
}
);
}
@ -2256,7 +2274,7 @@ function getStringSelector(str) {
for (let i = 0, len = hash.length; i < len; i++) {
sum += hash[i];
}
return Buffer.from([sum % 256]).toString('hex');
return (sum % 32).toString(16);
}
module.exports = UserHandler;