This commit is contained in:
Andris Reinman 2020-05-08 10:43:59 +03:00
parent faa713d12e
commit 4f0c25aa4c
7 changed files with 50 additions and 61 deletions

View file

@ -8,7 +8,7 @@ secure=false
# If set requires all API calls to have accessToken query argument with that value
# http://localhost:8080/users?accessToken=somesecretvalue
#accessToken="somesecretvalue"
accessToken="somesecretvalue"
[accessControl]
# If true then require a valid access token to perform API calls

View file

@ -278,6 +278,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler) => {
* @apiSuccess {String} results.bcc.address Address of the recipient
* @apiSuccess {String} results.subject Message subject
* @apiSuccess {String} results.date Datestring
* @apiSuccess {Number} results.size Message size in bytes
* @apiSuccess {String} results.intro First 128 bytes of the message
* @apiSuccess {Boolean} results.attachments Does the message have attachments
* @apiSuccess {Boolean} results.seen Is this message alread seen or not
@ -317,6 +318,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler) => {
* "date": "2003-10-24T06:28:34.000Z",
* "intro": "Welcome to Ryan Finnie's MIME torture test. This message was designed to introduce a couple of the newer features of MIME-aware…",
* "attachments": true,
* "size": 1234,
* "seen": true,
* "deleted": false,
* "flagged": true,
@ -460,6 +462,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler) => {
'mimeTree.parsedHeader.content-type': true,
'mimeTree.parsedHeader.references': true,
ha: true,
size: true,
intro: true,
unseen: true,
undeleted: true,
@ -985,6 +988,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler) => {
'mimeTree.parsedHeader.references': true,
ha: true,
intro: true,
size: true,
unseen: true,
undeleted: true,
flagged: true,
@ -2465,7 +2469,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler) => {
let envelopeFrom = envelope.from;
envelope.from = data.from.address = await validateFromAddress(userData, envelopeFrom);
if (!envelope.to.length && referencedMessage && ['reply', 'replyAll'].includes(result.value.reference.action)) {
if (!result.value.to && !envelope.to.length && referencedMessage && ['reply', 'replyAll'].includes(result.value.reference.action)) {
envelope.to = envelope.to.concat(parseAddresses(referencedMessage.replyTo || [])).concat(parseAddresses(referencedMessage.replyCc || []));
data.to = [].concat(referencedMessage.replyTo || []);
data.cc = [].concat(referencedMessage.replyCc || []);
@ -3246,6 +3250,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler) => {
'mimeTree.parsedHeader.references': true,
ha: true,
intro: true,
size: true,
unseen: true,
undeleted: true,
flagged: true,
@ -3935,6 +3940,7 @@ function formatMessageListing(messageData) {
date: messageData.hdate.toISOString(),
intro: messageData.intro,
attachments: !!messageData.ha,
size: messageData.size,
seen: !messageData.unseen,
deleted: !messageData.undeleted,
flagged: messageData.flagged,

View file

@ -483,9 +483,11 @@ class FilterHandler {
filterResults.push({ delete: true });
return {
userData,
response: 'Message dropped by policy as ' + prepared.id.toString(),
error: err
response: {
userData,
response: 'Message dropped by policy as ' + prepared.id.toString(),
error: err
}
};
}
@ -700,13 +702,7 @@ async function checkFilter(filterData, prepared, maildata) {
}
}
if (
query.text &&
maildata.text
.toLowerCase()
.replace(/\s+/g, ' ')
.indexOf(query.text.toLowerCase()) < 0
) {
if (query.text && maildata.text.toLowerCase().replace(/\s+/g, ' ').indexOf(query.text.toLowerCase()) < 0) {
// message plaintext does not match the text field value
return false;
}
@ -733,10 +729,7 @@ function parseReceived(str) {
}
});
let date = str
.split(';')
.pop()
.trim();
let date = str.split(';').pop().trim();
if (date) {
date = new Date(date);
if (date.getTime()) {

View file

@ -1,7 +1,7 @@
'use strict';
const crypto = require('crypto');
const uuidV1 = require('uuid/v1');
const { v1: uuidV1 } = require('uuid');
const ObjectID = require('mongodb').ObjectID;
const Indexer = require('../imap-core/lib/indexer/indexer');
const ImapNotifier = require('./imap-notifier');
@ -470,10 +470,7 @@ class MessageHandler {
let raw = options.rawchunks || options.raw;
let processAudits = async () => {
let audits = await this.database
.collection('audits')
.find({ user: mailboxData.user })
.toArray();
let audits = await this.database.collection('audits').find({ user: mailboxData.user }).toArray();
let now = new Date();
for (let auditData of audits) {
@ -505,9 +502,7 @@ class MessageHandler {
};
// do not use more suitable .finally() as it is not supported in Node v8
return processAudits()
.then(next)
.catch(next);
return processAudits().then(next).catch(next);
}
);
});
@ -600,7 +595,7 @@ class MessageHandler {
_user: messageData.user,
_mailbox: messageData.mailbox,
_uid: messageData.uid,
_message_id: messageData._id,
_stored_id: messageData._id,
_expires: messageData.rdate,
_sess: options.session && options.session.id,
_size: messageData.size
@ -1142,10 +1137,7 @@ class MessageHandler {
.map(line => {
line = Buffer.from(line, 'binary').toString();
let key = line
.substr(0, line.indexOf(':'))
.trim()
.toLowerCase();
let key = line.substr(0, line.indexOf(':')).trim().toLowerCase();
if (!INDEXED_HEADERS.includes(key)) {
// do not index this header
@ -1180,17 +1172,13 @@ class MessageHandler {
// trim long values as mongodb indexed fields can not be too long
if (Buffer.byteLength(key, 'utf-8') >= 255) {
key = Buffer.from(key)
.slice(0, 255)
.toString();
key = Buffer.from(key).slice(0, 255).toString();
key = key.substr(0, key.length - 4);
}
if (Buffer.byteLength(value, 'utf-8') >= 880) {
// value exceeds MongoDB max indexed value length
value = Buffer.from(value)
.slice(0, 880)
.toString();
value = Buffer.from(value).slice(0, 880).toString();
// remove last 4 chars to be sure we do not have any incomplete unicode sequences
value = value.substr(0, value.length - 4);
}
@ -1270,13 +1258,7 @@ class MessageHandler {
.split(/\s+/)
.map(id => id.replace(/[<>]/g, '').trim())
.filter(id => id)
.map(id =>
crypto
.createHash('sha1')
.update(id)
.digest('base64')
.replace(/[=]+$/g, '')
)
.map(id => crypto.createHash('sha1').update(id).digest('base64').replace(/[=]+$/g, ''))
);
subject = this.normalizeSubject(subject, {
@ -1617,13 +1599,7 @@ class MessageHandler {
if (/^content-type:/i.test(line)) {
let parts = line.split(':');
let value = parts.slice(1).join(':');
if (
value
.split(';')
.shift()
.trim()
.toLowerCase() === 'multipart/encrypted'
) {
if (value.split(';').shift().trim().toLowerCase() === 'multipart/encrypted') {
// message is already encrypted, do nothing
return callback(null, false);
}

View file

@ -470,7 +470,22 @@ class POP3Connection extends EventEmitter {
// https://tools.ietf.org/html/rfc1939#section-6
command_QUIT() {
let finish = () => {
let deleted = this.session.listing.messages.filter(message => message.popped);
let finish = err => {
if (!err) {
deleted.forEach(message => {
this._server.loggelf({
short_message: '[POP3DELETE]',
_mail_action: 'pop3_delete',
_message_id: message.id,
_username: this.session.user && this.session.user.username,
_sess: this.id,
_ip: this.remoteAddress
});
});
}
this.session = false;
this.send('+OK Bye');
this.close();
@ -481,7 +496,6 @@ class POP3Connection extends EventEmitter {
}
this.session.state = 'UPDATE';
let deleted = this.session.listing.messages.filter(message => message.popped);
let seen = this.session.listing.messages.filter(message => !message.seen && message.fetched && !message.popped);
if (!deleted.length && !seen.length) {
@ -813,9 +827,7 @@ class POP3Connection extends EventEmitter {
return next();
}
let credentials = Buffer.from(plain, 'base64')
.toString()
.split('\x00');
let credentials = Buffer.from(plain, 'base64').toString().split('\x00');
if (credentials.length !== 3) {
this.send('-ERR malformed command');
return next();

View file

@ -1,6 +1,6 @@
{
"name": "wildduck",
"version": "1.24.0",
"version": "1.25.0",
"description": "IMAP/POP3 server built with Node.js and MongoDB",
"main": "server.js",
"scripts": {
@ -16,7 +16,7 @@
"license": "EUPL-1.1+",
"devDependencies": {
"ajv": "6.12.2",
"apidoc": "0.20.1",
"apidoc": "0.22.1",
"browserbox": "0.9.1",
"chai": "4.2.0",
"eslint": "6.8.0",
@ -29,7 +29,7 @@
"grunt-shell-spawn": "0.4.0",
"grunt-wait": "0.3.0",
"mailparser": "2.7.7",
"mocha": "7.1.1",
"mocha": "7.1.2",
"request": "2.88.2",
"supertest": "4.0.2"
},
@ -55,8 +55,8 @@
"libqp": "1.1.0",
"mailsplit": "4.6.4",
"mobileconfig": "2.3.1",
"mongo-cursor-pagination": "7.2.0",
"mongodb": "3.5.6",
"mongo-cursor-pagination": "7.3.0",
"mongodb": "3.5.7",
"mongodb-extended-json": "1.11.0",
"node-forge": "0.9.1",
"nodemailer": "6.4.6",
@ -72,8 +72,8 @@
"speakeasy": "2.0.0",
"u2f": "0.1.3",
"utf7": "1.0.2",
"uuid": "7.0.3",
"wild-config": "1.5.0",
"uuid": "8.0.0",
"wild-config": "1.5.1",
"yargs": "15.3.1"
},
"repository": {

View file

@ -440,6 +440,8 @@ module.exports = done => {
loggelf: message => loggelf(message)
});
server.loggelf = loggelf;
server.on('error', err => {
if (!started) {
started = true;