mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-11-10 09:32:28 +08:00
Merge pull request #412 from nodemailer/feature-limit-filters
Allow to limit the count of filters per account
This commit is contained in:
commit
c6007001e0
7 changed files with 122 additions and 34 deletions
2
api.js
2
api.js
|
@ -543,7 +543,7 @@ module.exports = done => {
|
|||
mailboxesRoutes(db, server, mailboxHandler);
|
||||
messagesRoutes(db, server, messageHandler, userHandler, storageHandler, settingsHandler);
|
||||
storageRoutes(db, server, storageHandler);
|
||||
filtersRoutes(db, server, userHandler);
|
||||
filtersRoutes(db, server, userHandler, settingsHandler);
|
||||
domainaccessRoutes(db, server);
|
||||
aspsRoutes(db, server, userHandler);
|
||||
totpRoutes(db, server, userHandler);
|
||||
|
|
|
@ -3426,6 +3426,8 @@ components:
|
|||
$ref: '#/components/schemas/Quota'
|
||||
recipients:
|
||||
$ref: '#/components/schemas/Recipients'
|
||||
filters:
|
||||
$ref: '#/components/schemas/Filters'
|
||||
forwards:
|
||||
$ref: '#/components/schemas/Forwards'
|
||||
received:
|
||||
|
@ -3469,6 +3471,19 @@ components:
|
|||
type: number
|
||||
description: Time until the end of current 24 hour period
|
||||
description: Sending quota
|
||||
Filters:
|
||||
required:
|
||||
- allowed
|
||||
- used
|
||||
type: object
|
||||
properties:
|
||||
allowed:
|
||||
type: number
|
||||
description: How many filters are allowed
|
||||
used:
|
||||
type: number
|
||||
description: How many filters have been created
|
||||
description: Sending quota
|
||||
Forwards:
|
||||
required:
|
||||
- allowed
|
||||
|
@ -4660,12 +4675,23 @@ components:
|
|||
GetFiltersResponse:
|
||||
required:
|
||||
- success
|
||||
- limits
|
||||
- results
|
||||
type: object
|
||||
properties:
|
||||
success:
|
||||
type: boolean
|
||||
description: Indicates successful response
|
||||
limits:
|
||||
type: object
|
||||
description: Filter usage limits for the user account
|
||||
properties:
|
||||
allowed:
|
||||
type: number
|
||||
description: How many filters are allowed
|
||||
used:
|
||||
type: number
|
||||
description: How many filters have been created
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
|
@ -5933,6 +5959,9 @@ components:
|
|||
forwards:
|
||||
type: number
|
||||
description: How many messages per 24 hour can be forwarded
|
||||
filters:
|
||||
type: number
|
||||
description: How many filters are allowed for this account
|
||||
imapMaxUpload:
|
||||
type: number
|
||||
description: How many bytes can be uploaded via IMAP during 24 hour
|
||||
|
@ -6059,6 +6088,9 @@ components:
|
|||
forwards:
|
||||
type: number
|
||||
description: How many messages per 24 hour can be forwarded
|
||||
filters:
|
||||
type: number
|
||||
description: How many filters are allowed for this account
|
||||
imapMaxUpload:
|
||||
type: number
|
||||
description: How many bytes can be uploaded via IMAP during 24 hour
|
||||
|
|
|
@ -10,7 +10,7 @@ const roles = require('../roles');
|
|||
const { nextPageCursorSchema, previousPageCursorSchema, pageNrSchema, sessSchema, sessIPSchema, booleanSchema } = require('../schemas');
|
||||
const { publish, FILTER_DELETED, FILTER_CREATED, FORWARD_ADDED } = require('../events');
|
||||
|
||||
module.exports = (db, server, userHandler) => {
|
||||
module.exports = (db, server, userHandler, settingsHandler) => {
|
||||
server.get(
|
||||
{ name: 'filters', path: '/filters' },
|
||||
tools.asyncifyJson(async (req, res, next) => {
|
||||
|
@ -210,7 +210,7 @@ module.exports = (db, server, userHandler) => {
|
|||
},
|
||||
{
|
||||
projection: {
|
||||
address: true
|
||||
filters: true
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -232,6 +232,9 @@ module.exports = (db, server, userHandler) => {
|
|||
return next();
|
||||
}
|
||||
|
||||
let settings = await settingsHandler.getMulti(['const:max:filters']);
|
||||
let maxFilters = Number(userData.filters) || settings['const:max:filters'];
|
||||
|
||||
let mailboxes;
|
||||
try {
|
||||
mailboxes = await db.database
|
||||
|
@ -282,6 +285,11 @@ module.exports = (db, server, userHandler) => {
|
|||
res.json({
|
||||
success: true,
|
||||
|
||||
limits: {
|
||||
allowed: maxFilters,
|
||||
used: filters.length
|
||||
},
|
||||
|
||||
results: filters.map(filterData => {
|
||||
let descriptions = getFilterStrings(filterData, mailboxes);
|
||||
|
||||
|
@ -565,6 +573,53 @@ module.exports = (db, server, userHandler) => {
|
|||
let values = result.value;
|
||||
|
||||
let user = new ObjectId(values.user);
|
||||
|
||||
let userData;
|
||||
try {
|
||||
userData = await db.users.collection('users').findOne(
|
||||
{
|
||||
_id: user
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
filters: true
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!userData) {
|
||||
res.status(404);
|
||||
res.json({
|
||||
error: 'This user does not exist',
|
||||
code: 'UserNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let settings = await settingsHandler.getMulti(['const:max:filters']);
|
||||
let maxFilters = Number(userData.filters) || settings['const:max:filters'];
|
||||
const filtersCount = await db.database.collection('filters').countDocuments({
|
||||
user
|
||||
});
|
||||
|
||||
if (filtersCount >= maxFilters) {
|
||||
res.status(403);
|
||||
res.json({
|
||||
error: 'Maximum filters limit reached',
|
||||
code: 'TooMany',
|
||||
allowed: maxFilters
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let filterData = {
|
||||
_id: new ObjectId(),
|
||||
user,
|
||||
|
@ -668,36 +723,6 @@ module.exports = (db, server, userHandler) => {
|
|||
filterData.action.mailbox = mailboxData._id;
|
||||
}
|
||||
|
||||
let userData;
|
||||
try {
|
||||
userData = await db.users.collection('users').findOne(
|
||||
{
|
||||
_id: user
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
_id: true
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
res.json({
|
||||
error: 'MongoDB Error: ' + err.message,
|
||||
code: 'InternalDatabaseError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!userData) {
|
||||
res.status(404);
|
||||
res.json({
|
||||
error: 'This user does not exist',
|
||||
code: 'UserNotFound'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
|
||||
let r;
|
||||
try {
|
||||
r = await db.database.collection('filters').insertOne(filterData);
|
||||
|
|
|
@ -291,6 +291,8 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
recipients: Joi.number().min(0).default(0),
|
||||
forwards: Joi.number().min(0).default(0),
|
||||
|
||||
filters: Joi.number().min(0).default(0),
|
||||
|
||||
requirePasswordChange: booleanSchema.default(false),
|
||||
|
||||
imapMaxUpload: Joi.number().min(0).default(0),
|
||||
|
@ -726,10 +728,15 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
errors.notify(err, { userId: user });
|
||||
}
|
||||
|
||||
const filtersCount = await db.database.collection('filters').countDocuments({
|
||||
user
|
||||
});
|
||||
|
||||
let settings = await settingsHandler.getMulti([
|
||||
'const:max:storage',
|
||||
'const:max:recipients',
|
||||
'const:max:forwards',
|
||||
'const:max:filters',
|
||||
'const:max:imap:upload',
|
||||
'const:max:imap:download',
|
||||
'const:max:pop3:download'
|
||||
|
@ -738,6 +745,8 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
let recipients = Number(userData.recipients) || config.maxRecipients || settings['const:max:recipients'];
|
||||
let forwards = Number(userData.forwards) || config.maxForwards || settings['const:max:forwards'];
|
||||
|
||||
let filters = Number(userData.filters) || settings['const:max:filters'];
|
||||
|
||||
let recipientsSent = Number(response && response[0] && response[0][1]) || 0;
|
||||
let recipientsTtl = Number(response && response[1] && response[1][1]) || 0;
|
||||
|
||||
|
@ -819,6 +828,11 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
ttl: receivedTtl >= 0 ? receivedTtl : false
|
||||
},
|
||||
|
||||
filters: {
|
||||
allowed: filters,
|
||||
used: filtersCount
|
||||
},
|
||||
|
||||
imapUpload: {
|
||||
allowed: Number(userData.imapMaxUpload) || settings['const:max:imap:upload'],
|
||||
used: imapUpload,
|
||||
|
@ -906,10 +920,13 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
encryptMessages: booleanSchema,
|
||||
encryptForwarded: booleanSchema,
|
||||
retention: Joi.number().min(0),
|
||||
|
||||
quota: Joi.number().min(0),
|
||||
recipients: Joi.number().min(0),
|
||||
forwards: Joi.number().min(0),
|
||||
|
||||
filters: Joi.number().min(0),
|
||||
|
||||
imapMaxUpload: Joi.number().min(0),
|
||||
imapMaxDownload: Joi.number().min(0),
|
||||
pop3MaxDownload: Joi.number().min(0),
|
||||
|
|
|
@ -129,5 +129,8 @@ module.exports = {
|
|||
MAX_POP3_DOWNLOAD: 10 * 1024 * 1024 * 1024,
|
||||
|
||||
// default max IMAP upload size
|
||||
MAX_IMAP_UPLOAD: 10 * 1024 * 1024 * 1024
|
||||
MAX_IMAP_UPLOAD: 10 * 1024 * 1024 * 1024,
|
||||
|
||||
// maximum number of filters per account
|
||||
MAX_FILTERS: 400
|
||||
};
|
||||
|
|
|
@ -98,6 +98,15 @@ const SETTING_KEYS = [
|
|||
constKey: false,
|
||||
confValue: ((config.imap && config.imap.maxUploadMB) || consts.MAX_IMAP_UPLOAD) * 1024 * 1024,
|
||||
schema: Joi.number()
|
||||
},
|
||||
|
||||
{
|
||||
key: 'const:max:filters',
|
||||
name: 'Max filters',
|
||||
description: 'Maximum number of filters for an account',
|
||||
type: 'number',
|
||||
constKey: 'MAX_FILTERS',
|
||||
schema: Joi.number()
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -1409,6 +1409,8 @@ class UserHandler {
|
|||
recipients: data.recipients || 0,
|
||||
forwards: data.forwards || 0,
|
||||
|
||||
filters: data.filters || 0,
|
||||
|
||||
imapMaxUpload: data.imapMaxUpload || 0,
|
||||
imapMaxDownload: data.imapMaxDownload || 0,
|
||||
pop3MaxDownload: data.pop3MaxDownload || 0,
|
||||
|
|
Loading…
Reference in a new issue