mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-01-01 13:13:53 +08:00
updated ASP handling
This commit is contained in:
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
|
@ -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"
}
});
|
||||
|
|
|
@ -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"
}
}
|
||||
|
|
10
indexes.yaml
10
indexes.yaml
|
@ -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
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue