mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-09-20 07:16:05 +08:00
v1.4.0
This commit is contained in:
parent
196fa4be06
commit
29dfd6c55d
|
@ -2,7 +2,7 @@
|
|||
mongo="mongodb://127.0.0.1:27017/wildduck"
|
||||
|
||||
# redis connection string to connect to a single master (see below for Sentinel example)
|
||||
redis="redis://127.0.0.1:6379/3"
|
||||
#redis="redis://127.0.0.1:6379/3"
|
||||
|
||||
# WildDuck allows using different kind of data in different databases
|
||||
# If you do not provide a database config value, then main database connection
|
||||
|
@ -26,6 +26,11 @@ sender="zone-mta"
|
|||
|
||||
#queued="mail"
|
||||
|
||||
[redis]
|
||||
host="127.0.0.1"
|
||||
port=6379
|
||||
db=3
|
||||
|
||||
## Connect to Redis Sentinel instead of single master
|
||||
# [redis]
|
||||
# name="mymaster"
|
||||
|
|
13
indexes.yaml
13
indexes.yaml
|
@ -120,7 +120,16 @@ indexes:
|
|||
name: user
|
||||
key:
|
||||
user: 1
|
||||
_id: -1
|
||||
_id: -1 # sort newer first
|
||||
|
||||
- collection: authlog
|
||||
type: users # index applies to users database
|
||||
index:
|
||||
name: insert
|
||||
key:
|
||||
user: 1
|
||||
created: 1
|
||||
key: 1
|
||||
|
||||
- collection: authlog
|
||||
type: users # index applies to users database
|
||||
|
@ -152,7 +161,7 @@ indexes:
|
|||
index:
|
||||
name: user_hashed
|
||||
key:
|
||||
user: hashed
|
||||
user: hashed # sharding
|
||||
|
||||
- collection: authlog
|
||||
type: users # index applies to users database
|
||||
|
|
|
@ -74,7 +74,7 @@ module.exports.connect = callback => {
|
|||
module.exports.redisConfig = tools.redisConfig(config.dbs.redis);
|
||||
module.exports.redis = new Redis(module.exports.redisConfig);
|
||||
|
||||
return callback(null, module.exports.database);
|
||||
module.exports.redis.connect(() => callback(null, module.exports.database));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -323,6 +323,7 @@ class UserHandler {
|
|||
return callback(null, false);
|
||||
}
|
||||
|
||||
// first check if client IP is not used too much
|
||||
this.rateLimitIP(meta, 0, (err, res) => {
|
||||
if (err) {
|
||||
err.code = 'InternalDatabaseError';
|
||||
|
@ -330,6 +331,7 @@ class UserHandler {
|
|||
}
|
||||
|
||||
if (!res.success) {
|
||||
// too many failed attempts from this IP
|
||||
return rateLimitResponse(res, callback);
|
||||
}
|
||||
|
||||
|
@ -339,9 +341,8 @@ class UserHandler {
|
|||
}
|
||||
|
||||
if (!query) {
|
||||
meta.username = username;
|
||||
meta.result = 'unknown';
|
||||
return this.logAuthEvent(null, meta, () => callback(null, false));
|
||||
// nothing to do here
|
||||
return callback(null, false);
|
||||
}
|
||||
|
||||
this.users.collection('users').findOne(
|
||||
|
@ -364,41 +365,36 @@ class UserHandler {
|
|||
}
|
||||
|
||||
if (!userData) {
|
||||
if (query.unameview) {
|
||||
meta.username = query.unameview;
|
||||
} else {
|
||||
meta.user = query._id;
|
||||
}
|
||||
meta.result = 'unknown';
|
||||
return this.logAuthEvent(null, meta, () => {
|
||||
// rate limit failed authentication attempts against non-existent users as well
|
||||
let ustring = (query.unameview || query._id || '').toString();
|
||||
|
||||
this.rateLimit(ustring, meta, 1, (err, res) => {
|
||||
if (err) {
|
||||
err.code = 'InternalDatabaseError';
|
||||
return callback(err);
|
||||
}
|
||||
if (!res.success) {
|
||||
return rateLimitResponse(res, callback);
|
||||
}
|
||||
callback(null, false);
|
||||
});
|
||||
// rate limit failed authentication attempts against non-existent users as well
|
||||
let ustring = (query.unameview || query._id || '').toString();
|
||||
return this.rateLimit(ustring, meta, 1, (err, res) => {
|
||||
if (err) {
|
||||
err.code = 'InternalDatabaseError';
|
||||
return callback(err);
|
||||
}
|
||||
if (!res.success) {
|
||||
// does not really matter but respond with a rate limit error, not auth fail error
|
||||
return rateLimitResponse(res, callback);
|
||||
}
|
||||
callback(null, false);
|
||||
});
|
||||
}
|
||||
|
||||
// check if there are not too many auth attemtp for that user
|
||||
this.rateLimitUser(userData._id, 0, (err, res) => {
|
||||
if (err) {
|
||||
err.code = 'InternalDatabaseError';
|
||||
return callback(err);
|
||||
}
|
||||
if (!res.success) {
|
||||
// too many failed attempts for this user
|
||||
return rateLimitResponse(res, callback);
|
||||
}
|
||||
|
||||
if (userData.disabled) {
|
||||
// disabled users can not log in
|
||||
meta.result = 'disabled';
|
||||
// TODO: should we send some specific error message?
|
||||
return this.logAuthEvent(userData._id, meta, () => callback(null, false));
|
||||
}
|
||||
|
||||
|
@ -589,6 +585,7 @@ class UserHandler {
|
|||
if (err) {
|
||||
// don't really care
|
||||
}
|
||||
let authEvent = r && r.insertedId;
|
||||
this.rateLimitReleaseUser(userData._id, () => false);
|
||||
this.users.collection('asps').findOneAndUpdate(
|
||||
{
|
||||
|
@ -597,7 +594,7 @@ class UserHandler {
|
|||
{
|
||||
$set: {
|
||||
used: new Date(),
|
||||
authEvent: r.insertedId
|
||||
authEvent
|
||||
}
|
||||
},
|
||||
() => {
|
||||
|
@ -2701,24 +2698,57 @@ class UserHandler {
|
|||
}
|
||||
|
||||
logAuthEvent(user, entry, callback) {
|
||||
if (this.authlogExpireDays === false) {
|
||||
// only log auth events if we have a valid user id and logging is not disabled
|
||||
if (!user || !tools.isId(user) || this.authlogExpireDays === false) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
if (user) {
|
||||
entry.user = user;
|
||||
} else {
|
||||
entry.user = entry.user || new ObjectID('000000000000000000000000');
|
||||
}
|
||||
let now = new Date();
|
||||
|
||||
entry.user = typeof user === 'string' ? new ObjectID(user) : user;
|
||||
entry.action = entry.action || 'authentication';
|
||||
entry.created = new Date();
|
||||
entry.created = now;
|
||||
|
||||
if (typeof this.authlogExpireDays === 'number' && this.authlogExpireDays !== 0) {
|
||||
// this entry expires in set days
|
||||
entry.expires = new Date(Date.now() + Math.abs(this.authlogExpireDays) * 24 * 3600 * 1000);
|
||||
}
|
||||
|
||||
return this.users.collection('authlog').insertOne(entry, callback);
|
||||
// key is for merging similar events
|
||||
entry.key = crypto
|
||||
.createHash('md5')
|
||||
.update([entry.protocol, entry.ip, entry.action, entry.result].map(v => (v || '').toString()).join('^'))
|
||||
.digest();
|
||||
|
||||
return this.users.collection('authlog').findOneAndUpdate(
|
||||
{
|
||||
user: entry.user,
|
||||
created: {
|
||||
$gte: new Date(Date.now() - 3600 * 1000)
|
||||
},
|
||||
key: entry.key
|
||||
},
|
||||
{
|
||||
$setOnInsert: entry,
|
||||
$inc: {
|
||||
events: 1
|
||||
},
|
||||
$set: {
|
||||
last: now
|
||||
}
|
||||
},
|
||||
{
|
||||
upsert: true,
|
||||
projection: { _id: true },
|
||||
returnOriginal: false
|
||||
},
|
||||
(err, r) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null, r && r.value && r.value._id);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
logout(user, reason, callback) {
|
||||
|
|
12
package.json
12
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wildduck",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"description": "IMAP/POP3 server built with Node.js and MongoDB",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
@ -30,7 +30,7 @@
|
|||
"mailparser": "2.3.2",
|
||||
"markdown-toc": "1.2.0",
|
||||
"mocha": "5.2.0",
|
||||
"request": "2.87.0"
|
||||
"request": "2.88.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"base32.js": "^0.1.0",
|
||||
|
@ -41,10 +41,10 @@
|
|||
"html-to-text": "4.0.0",
|
||||
"humanname": "0.2.2",
|
||||
"iconv-lite": "0.4.23",
|
||||
"ioredfour": "1.0.2-ioredis",
|
||||
"ioredis": "3.2.2",
|
||||
"ioredfour": "1.0.2-ioredis-02",
|
||||
"ioredis": "4.0.0",
|
||||
"isemail": "3.1.3",
|
||||
"joi": "13.5.2",
|
||||
"joi": "13.6.0",
|
||||
"js-yaml": "3.12.0",
|
||||
"key-fingerprint": "1.1.0",
|
||||
"libbase64": "1.0.3",
|
||||
|
@ -54,7 +54,7 @@
|
|||
"mailsplit": "4.2.3",
|
||||
"mobileconfig": "2.1.0",
|
||||
"mongo-cursor-pagination": "^7.1.0",
|
||||
"mongodb": "3.1.1",
|
||||
"mongodb": "3.1.3",
|
||||
"mongodb-extended-json": "1.10.0",
|
||||
"node-forge": "0.7.5",
|
||||
"nodemailer": "4.6.7",
|
||||
|
|
Loading…
Reference in a new issue