Skip to content

Commit 5196759

Browse files
committed
Merge branch 'master' of github.com:zone-eu/wildduck into ZMS-3
2 parents 60bca78 + fe2d4a5 commit 5196759

30 files changed

+681
-138
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
- uses: actions/checkout@v6
3030

3131
- name: Start MongoDB
32-
uses: supercharge/mongodb-github-action@1.7.0
32+
uses: supercharge/mongodb-github-action@1.12.1
3333
with:
3434
mongodb-version: 6.0
3535
mongodb-port: 27017

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.46.20"
2+
".": "1.46.21"
33
}

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## [1.46.21](https://github.com/zone-eu/wildduck/compare/v1.46.20...v1.46.21) (2026-02-09)
4+
5+
6+
### Bug Fixes
7+
8+
* **logging-autoreply:** ZMSA-65: loggelf autoreply error in filterHandler.storeMessage ([#983](https://github.com/zone-eu/wildduck/issues/983)) ([7b43049](https://github.com/zone-eu/wildduck/commit/7b43049a614a3bafc6d878e8923b81557e80e789))
9+
* **logging-redis:** ZMSA-78: Improve redis config, error logging and retry handling ([#987](https://github.com/zone-eu/wildduck/issues/987)) ([86d2627](https://github.com/zone-eu/wildduck/commit/86d26276a5ad58a689ea60378a71ec6f827bdad2))
10+
* **messages-search:** ZMSA-80: fix SearchString import. Fix messages search q param parsing, add search tests for q param ([#990](https://github.com/zone-eu/wildduck/issues/990)) ([312f9f7](https://github.com/zone-eu/wildduck/commit/312f9f787fc75881c15303f7833be978e4325f21))
11+
* ZMSA-64: on API outbound email sends add passwordType: master to envelope object ([#978](https://github.com/zone-eu/wildduck/issues/978)) ([24ba575](https://github.com/zone-eu/wildduck/commit/24ba57520afd88aa5435fc365f55ea3695f0d66a))
12+
313
## [1.46.20](https://github.com/zone-eu/wildduck/compare/v1.46.19...v1.46.20) (2026-01-29)
414

515

lib/api/addresses.js

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const {
2626
AddressLimits,
2727
AutoreplyInfo
2828
} = require('../schemas/response/addresses-schemas');
29-
const { userId, addressEmail, addressId } = require('../schemas/request/general-schemas');
29+
const { userId, addressEmailOrWildcard, addressId } = require('../schemas/request/general-schemas');
3030
const { Autoreply } = require('../schemas/request/addresses-schemas');
3131
const { mongopagingFindWrapper } = require('../mongopaging-find-wrapper');
3232

@@ -40,7 +40,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
4040
validationObjs: {
4141
requestBody: {},
4242
queryParams: {
43-
query: Joi.string().trim().empty('').max(255).description('Partial match of an address'),
43+
query: Joi.string().trim().empty('').max(255).default('').description('Partial match of an address'),
4444
forward: Joi.string().trim().empty('').max(255).description('Partial match of a forward email address or URL'),
4545
tags: Joi.string().trim().empty('').max(1024).description('Comma separated list of tags. The Address must have at least one to be set'),
4646
requiredTags: Joi.string()
@@ -271,18 +271,11 @@ module.exports = (db, server, userHandler, settingsHandler) => {
271271
summary: 'Create new Address',
272272
name: 'createUserAddress',
273273
description:
274-
'Add a new email address for a User. Addresses can contain unicode characters. Dots in usernames are normalized so no need to create both "firstlast@example.com" and "first.last@example.com" Special addresses `*@example.com`, `*suffix@example.com` and `username@*` catches all emails to these domains or users without a registered destination (requires allowWildcard argument)',
274+
'Add a new email address for a User. Addresses can contain unicode characters. Dots in usernames are normalized so no need to create both "firstlast@example.com" and "first.last@example.com" Special addresses `*@example.com` and `username@*` catch all emails to these domains or users without a registered destination (requires allowWildcard argument)',
275275
tags: ['Addresses'],
276276
validationObjs: {
277277
requestBody: {
278-
address: Joi.alternatives()
279-
.try(
280-
addressEmail,
281-
Joi.string()
282-
.regex(/^\w+@\*$/, 'special address')
283-
.description('Wildcard address')
284-
)
285-
.description('String. Either an e-mail address or a wildduck address'),
278+
address: addressEmailOrWildcard.description('String. Either an e-mail address or a wildcard address').required(),
286279
name: Joi.string().empty('').trim().max(128).description('Identity name'),
287280
main: booleanSchema.description('Indicates if this is the default address for the User'),
288281
allowWildcard: booleanSchema.description(
@@ -309,7 +302,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
309302
description: 'Success',
310303
model: Joi.object({
311304
success: successRes,
312-
id: Joi.string().required().description('ID of the address')
305+
id: addressId.description('ID of the address')
313306
}).$_setFlag('objectName', 'CreateUserAddressResponse')
314307
}
315308
}
@@ -756,7 +749,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
756749
success: successRes,
757750
id: addressId,
758751
name: Joi.string().description('Identity name'),
759-
address: addressEmail,
752+
address: addressEmailOrWildcard,
760753
main: booleanSchema.required().description('Indicates if this is the default address for the User'),
761754
created: Joi.date().required().description('Datestring of the time the address was created'),
762755
tags: Joi.array().items(Joi.string()).required().description('List of tags associated with the Address'),
@@ -1612,10 +1605,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
16121605
tags: ['Addresses'],
16131606
validationObjs: {
16141607
requestBody: {
1615-
address: Joi.alternatives()
1616-
.try(addressEmail, Joi.string().regex(/^\w+@\*$/, 'special address'))
1617-
.required()
1618-
.description('E-mail Address'),
1608+
address: addressEmailOrWildcard.description('E-mail address or wildcard address').required(),
16191609
name: Joi.string().empty('').trim().max(128).description('Identity name'),
16201610
targets: Joi.array()
16211611
.items(
@@ -1631,7 +1621,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
16311621
),
16321622
forwards: Joi.number().min(0).default(0).description('Daily allowed forwarding count for this address'),
16331623
allowWildcard: booleanSchema.description(
1634-
'If true then address value can be in the form of `*@example.com`, otherwise using * is not allowed'
1624+
'If true then address value can be in the form of `*@example.com` or `username@*`, otherwise using * is not allowed'
16351625
),
16361626
autoreply: Autoreply,
16371627
tags: Joi.array().items(Joi.string().trim().max(128)).description('A list of tags associated with this address'),
@@ -2339,7 +2329,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
23392329
model: Joi.object({
23402330
success: successRes,
23412331
id: addressId,
2342-
address: addressEmail,
2332+
address: addressEmailOrWildcard,
23432333
name: Joi.string().description('Identity name'),
23442334
targets: Joi.array().items(Joi.string()).description('List of forwarding targets'),
23452335
limits: AddressLimits,
@@ -2469,19 +2459,23 @@ module.exports = (db, server, userHandler, settingsHandler) => {
24692459
ip: sessIPSchema
24702460
},
24712461
pathParams: {
2472-
address: Joi.alternatives().try(addressId, addressEmail).required().description('ID of the Address or e-mail address string')
2462+
address: Joi.alternatives()
2463+
.try(addressId, addressEmailOrWildcard)
2464+
.required()
2465+
.description('ID of the Address or e-mail address string (including wildcard addresses)')
24732466
},
24742467
response: {
24752468
200: {
24762469
description: 'Success',
24772470
model: Joi.object({
24782471
success: successRes,
24792472
id: addressId,
2480-
address: addressEmail,
2481-
name: Joi.string().required().description('Identity name'),
2473+
address: addressEmailOrWildcard,
2474+
user: userId.optional().description('User ID this address belongs to if this is a User address'),
2475+
name: Joi.string().allow('').description('Identity name'),
24822476
targets: Joi.array().items(Joi.string()).description('List of forwarding targets if this is a Forwarded address'),
2483-
limits: AddressLimits,
2484-
autoreply: AutoreplyInfo,
2477+
limits: AddressLimits.optional(),
2478+
autoreply: AutoreplyInfo.optional(),
24852479
tags: Joi.array().items(Joi.string()).required().description('List of tags associated with the Address'),
24862480
created: Joi.date().required().description('Datestring of the time the address was created'),
24872481
metaData: Joi.object({}).description('Metadata object (if available)'),

lib/api/asps.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ module.exports = (db, server, userHandler) => {
5757
.$_setFlag('objectName', 'LastUse')
5858
.description('Information about last use'),
5959
created: Joi.date().required().description('Datestring'),
60-
expires: Joi.date().required().description('Application password expires after the given date')
60+
expires: Joi.date().description('Application password expires after the given date')
6161
}).$_setFlag('objectName', 'GetASPsResult')
6262
)
6363
.required()
@@ -216,7 +216,7 @@ module.exports = (db, server, userHandler) => {
216216
.$_setFlag('objectName', 'LastUse')
217217
.description('Information about last use'),
218218
created: Joi.date().required().description('Datestring'),
219-
expires: Joi.date().required().description('Application password expires after the given date')
219+
expires: Joi.date().description('Application password expires after the given date')
220220
}).$_setFlag('objectName', 'GetASPResponse')
221221
}
222222
}
@@ -289,7 +289,7 @@ module.exports = (db, server, userHandler) => {
289289
time: aspData.used || undefined,
290290
event: aspData.authEvent || undefined
291291
},
292-
expires: asp.expires,
292+
expires: aspData.expires,
293293
created: aspData.created
294294
});
295295
})
@@ -311,6 +311,7 @@ module.exports = (db, server, userHandler) => {
311311
.required()
312312
)
313313
.unique()
314+
.default(['*'])
314315
.description(
315316
'List of scopes this Password applies to. Special scope "*" indicates that this password can be used for any scope except "master"'
316317
),
@@ -345,13 +346,11 @@ module.exports = (db, server, userHandler) => {
345346
.description(
346347
'Application Specific Password. Generated password is whitespace agnostic, so it could be displayed to the client as "abcd efgh ijkl mnop" instead of "abcdefghijklmnop"'
347348
),
348-
mobileconfig: Joi.string()
349-
.required()
350-
.description(
351-
'Base64 encoded mobileconfig file. Generated profile file should be sent to the client with Content-Type value of application/x-apple-aspen-config.'
352-
),
353-
name: Joi.string().required().description('Account name'),
354-
address: Joi.string().required().description('Account address or the address specified in params of this endpoint')
349+
mobileconfig: Joi.string().description(
350+
'Base64 encoded mobileconfig file. Present when generateMobileconfig is true. Generated profile file should be sent to the client with Content-Type value of application/x-apple-aspen-config.'
351+
),
352+
name: Joi.string().description('Account name. Present when generateMobileconfig is true.'),
353+
address: Joi.string().description('Account address or the address specified in params of this endpoint. Present when generateMobileconfig is true.')
355354
}).$_setFlag('objectName', 'CreateASPResponse')
356355
}
357356
}

lib/api/audit.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const tools = require('../tools');
66
const roles = require('../roles');
77
const mboxExport = require('../mbox-export');
88
const ObjectId = require('mongodb').ObjectId;
9-
const { sessSchema, sessIPSchema } = require('../schemas');
9+
const { sessSchema, sessIPSchema, metaDataSchema } = require('../schemas');
1010
const { userId } = require('../schemas/request/general-schemas');
1111
const { successRes } = require('../schemas/response/general-schemas');
1212

@@ -24,6 +24,8 @@ module.exports = (db, server, auditHandler) => {
2424
start: Joi.date().empty('').allow(false).description('Start time as ISO date'),
2525
end: Joi.date().empty('').allow(false).description('End time as ISO date'),
2626
expires: Joi.date().empty('').greater('now').required().description('Expiration date. Audit data is deleted after this date'),
27+
notes: Joi.string().trim().max(1024).empty('').description('Optional audit notes'),
28+
meta: metaDataSchema.label('meta').description('Optional metadata, must be an object or JSON formatted string'),
2729
sess: sessSchema,
2830
ip: sessIPSchema
2931
},
@@ -72,17 +74,29 @@ module.exports = (db, server, auditHandler) => {
7274
let start = result.value.start;
7375
let end = result.value.end;
7476
let expires = result.value.expires;
77+
let notes = result.value.notes;
78+
let meta = result.value.meta;
79+
80+
if (meta && typeof meta === 'string') {
81+
try {
82+
meta = JSON.parse(meta);
83+
} catch (err) {
84+
meta = undefined;
85+
}
86+
}
7587

7688
let audit = await auditHandler.create({
7789
user,
7890
start,
7991
end,
80-
expires
92+
expires,
93+
notes,
94+
meta
8195
});
8296

8397
return res.json({
8498
success: true,
85-
id: audit
99+
id: audit.toString()
86100
});
87101
})
88102
);
@@ -109,7 +123,13 @@ module.exports = (db, server, auditHandler) => {
109123
user: userId,
110124
start: Joi.date().empty('').allow(false).description('Start time as ISO date'),
111125
end: Joi.date().empty('').allow(false).description('End time as ISO date'),
112-
expires: Joi.date().empty('').greater('now').required().description('Expiration date. Audit data is deleted after this date'),
126+
expires: Joi.date().required().description('Expiration date. Audit data is deleted after this date'),
127+
notes: Joi.string().description('Optional audit notes'),
128+
meta: Joi.object().description('Custom metadata for this audit'),
129+
deleted: Joi.boolean().description('If true then audit has been deleted'),
130+
deletedTime: Joi.date().description('Time the audit was deleted'),
131+
audited: Joi.number().description('How many messages have been audited'),
132+
lastAuditedMessage: Joi.date().description('Timestamp of the last audited message'),
113133
import: Joi.object({
114134
status: Joi.string().required().description('Status of the audit'),
115135
failed: Joi.number().required().description('How many messages failed'),
@@ -163,10 +183,16 @@ module.exports = (db, server, auditHandler) => {
163183
return res.json({
164184
success: true,
165185
id: auditData._id.toString(),
166-
user: auditData.user,
186+
user: auditData.user.toString(),
167187
start: auditData.start && auditData.start.toISOString(),
168188
end: auditData.end && auditData.end.toISOString(),
169189
expires: auditData.expires && auditData.expires.toISOString(),
190+
notes: auditData.notes,
191+
meta: auditData.meta ? tools.formatMetaData(auditData.meta) : undefined,
192+
deleted: !!auditData.deleted,
193+
deletedTime: auditData.deletedTime ? auditData.deletedTime.toISOString() : undefined,
194+
audited: auditData.audited,
195+
lastAuditedMessage: auditData.lastAuditedMessage ? auditData.lastAuditedMessage.toISOString() : undefined,
170196
import: auditData.import
171197
});
172198
})

0 commit comments

Comments
 (0)