Skip to content

Commit

Permalink
Merge branch 'master' into ZMS-87
Browse files Browse the repository at this point in the history
  • Loading branch information
NickOvt authored Nov 20, 2023
2 parents 70ebdbc + ea24b93 commit f85fccc
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 157 deletions.
10 changes: 1 addition & 9 deletions lib/api/mailboxes.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,7 @@ module.exports = (db, server, mailboxHandler) => {
const getMailboxCounter = util.promisify(tools.getMailboxCounter);
const updateMailbox = util.promisify(mailboxHandler.update.bind(mailboxHandler));
const deleteMailbox = util.promisify(mailboxHandler.del.bind(mailboxHandler));
const createMailbox = util.promisify((...args) => {
let callback = args.pop();
mailboxHandler.create(...args, (err, status, id) => {
if (err) {
return callback(err);
}
return callback(null, { status, id });
});
});
const createMailbox = mailboxHandler.createAsync.bind(mailboxHandler);

server.get(
'/users/:user/mailboxes',
Expand Down
26 changes: 23 additions & 3 deletions lib/api/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2248,7 +2248,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
envelope,
files
},
session: result.value.session,
session: result.value.sess,
date,
verificationResults,
flags: []
Expand Down Expand Up @@ -2725,7 +2725,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
});
}

let maxRecipients = Number(userData.maxRecipients) || (await settingsHandler.get('const:max:recipients'));
let maxRecipients = Number(userData.recipients) || (await settingsHandler.get('const:max:recipients'));
let maxRptsTo = await settingsHandler.get('const:max:rcpt_to');

// Trying to send more than allowed recipients count per email
Expand Down Expand Up @@ -2873,6 +2873,26 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
}
}

for (const to of Array.isArray(envelope.to) ? envelope.to : [envelope.to]) {
server.loggelf({
short_message: `[RCPT TO: ${to}] ${result.value.sess}`,
_mail_action: 'rcpt_to',
_user: userData._id.toString(),
_queue_id: queueId,
_sent_mailbox: response.message && response.message.mailbox,
_sent_message: response.message && response.message.id,
_send_time: sendTime && sendTime.toISOString && sendTime.toISOString(),
_from: envelope.from,
_to: to,
_message_id: messageData.msgid,
_subject: messageData.subject,
_sess: result.value.sess,
_ip: result.value.ip,
_limit_allowed: userData.recipients,
_limit_sent: messagesSent + envelope.to.length
});
}

server.loggelf({
short_message: '[SUBMIT] draft',
_mail_action: 'submit_draft',
Expand All @@ -2885,7 +2905,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
_to: envelope.to && envelope.to.join(','),
_message_id: messageData.msgid,
_subject: messageData.subject,
_sess: result.value.session,
_sess: result.value.sess,
_ip: result.value.ip
});

Expand Down
3 changes: 2 additions & 1 deletion lib/audit-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ class AuditHandler {
let expiredAudits = await this.database
.collection('audits')
.find({
expires: { $lt: new Date(), deleted: false }
expires: { $lt: new Date() },
deleted: false
})
.toArray();

Expand Down
5 changes: 4 additions & 1 deletion lib/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,5 +134,8 @@ module.exports = {
MAX_IMAP_UPLOAD: 10 * 1024 * 1024 * 1024,

// maximum number of filters per account
MAX_FILTERS: 400
MAX_FILTERS: 400,

// maximum amount of mailboxes per user
MAX_MAILBOXES: 1500
};
156 changes: 75 additions & 81 deletions lib/mailbox-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const ObjectId = require('mongodb').ObjectId;
const ImapNotifier = require('./imap-notifier');
const { publish, MAILBOX_CREATED, MAILBOX_RENAMED, MAILBOX_DELETED } = require('./events');
const { SettingsHandler } = require('./settings-handler');

class MailboxHandler {
constructor(options) {
Expand All @@ -19,99 +20,92 @@ class MailboxHandler {
redis: this.redis,
pushOnly: true
});

this.settingsHandler = new SettingsHandler({ db: this.database });
}

create(user, path, opts, callback) {
this.database.collection('mailboxes').findOne(
{
user,
path
},
(err, mailboxData) => {
if (err) {
return callback(err);
}
if (mailboxData) {
const err = new Error('Mailbox creation failed with code MailboxAlreadyExists');
err.code = 'ALREADYEXISTS';
err.responseCode = 400;
return callback(err, 'ALREADYEXISTS');
}
this.createAsync(user, path, opts)
.then(mailboxData => callback(null, ...[mailboxData.status, mailboxData.id]))
.catch(err => callback(err));
}

this.users.collection('users').findOne(
{
_id: user
},
{
projection: {
retention: true
}
},
(err, userData) => {
if (err) {
return callback(err);
}
async createAsync(user, path, opts) {
const userData = await this.users.collection('users').findOne({ _id: user }, { projection: { retention: true } });

if (!userData) {
const err = new Error('This user does not exist');
err.code = 'UserNotFound';
err.responseCode = 404;
return callback(err, 'UserNotFound');
}
if (!userData) {
const err = new Error('This user does not exist');
err.code = 'UserNotFound';
err.responseCode = 404;
throw err;
}

mailboxData = {
_id: new ObjectId(),
user,
path,
uidValidity: Math.floor(Date.now() / 1000),
uidNext: 1,
modifyIndex: 0,
subscribed: true,
flags: [],
retention: userData.retention
};
let mailboxData = await this.database.collection('mailboxes').findOne({ user, path });

Object.keys(opts || {}).forEach(key => {
if (!['_id', 'user', 'path'].includes(key)) {
mailboxData[key] = opts[key];
}
});
if (mailboxData) {
const err = new Error('Mailbox creation failed with code MailboxAlreadyExists');
err.code = 'ALREADYEXISTS';
err.responseCode = 400;
throw err;
}

this.database.collection('mailboxes').insertOne(mailboxData, { writeConcern: 'majority' }, (err, r) => {
if (err) {
if (err.code === 11000) {
const err = new Error('Mailbox creation failed with code MailboxAlreadyExists');
err.code = 'ALREADYEXISTS';
err.responseCode = 400;
return callback(err, 'ALREADYEXISTS');
}
return callback(err);
}
const mailboxCountForUser = await this.database.collection('mailboxes').countDocuments({ user });

publish(this.redis, {
ev: MAILBOX_CREATED,
user,
mailbox: r.insertedId,
path: mailboxData.path
}).catch(() => false);
if (mailboxCountForUser > (await this.settingsHandler.get('const:max:mailboxes'))) {
const err = new Error('Mailbox creation failed with code ReachedMailboxCountLimit. Max mailboxes count reached.');
err.code = 'CANNOT';
err.responseCode = 400;
throw err;
}

return this.notifier.addEntries(
mailboxData,
{
command: 'CREATE',
mailbox: r.insertedId,
path
},
() => {
this.notifier.fire(user);
return callback(null, true, mailboxData._id);
}
);
});
}
);
mailboxData = {
_id: new ObjectId(),
user,
path,
uidValidity: Math.floor(Date.now() / 1000),
uidNext: 1,
modifyIndex: 0,
subscribed: true,
flags: [],
retention: userData.retention
};

Object.keys(opts || {}).forEach(key => {
if (!['_id', 'user', 'path'].includes(key)) {
mailboxData[key] = opts[key];
}
});

const r = this.database.collection('mailboxes').insertOne(mailboxData, { writeConcern: 'majority' });

try {
await publish(this.redis, {
ev: MAILBOX_CREATED,
user,
mailbox: r.insertedId,
path: mailboxData.path
});
} catch {
// ignore
}

await this.notifier.addEntries(
mailboxData,
{
command: 'CREATE',
mailbox: r.insertedId,
path
},
() => {
this.notifier.fire(user);
return;
}
);

return {
status: true,
id: mailboxData._id
};
}

rename(user, mailbox, newname, opts, callback) {
Expand Down
9 changes: 9 additions & 0 deletions lib/settings-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ const SETTING_KEYS = [
schema: Joi.number()
},

{
key: 'const:max:mailboxes',
name: 'Max mailboxes',
description: 'Maximum amount of mailboxes for a user',
type: 'number',
constKey: 'MAX_MAILBOXES',
schema: Joi.number()
},

{
key: 'const:max:rcpt_to',
name: 'Max message recipients',
Expand Down
Loading

0 comments on commit f85fccc

Please sign in to comment.