mail: require catch all to be absolute

This commit is contained in:
Girish Ramakrishnan
2022-09-11 11:15:21 +02:00
parent 2a93c703ef
commit 4e75694ac6
5 changed files with 42 additions and 5 deletions

View File

@@ -2514,4 +2514,5 @@
* eventlog: distinguish ghost/impersonate logins from others
* ldap: remove virtual user and admin groups to ldap user records
* Randomize certificate generation cronjob to lighten load on Let's Encrypt servers
* mail: catch all address can be any domain

View File

@@ -0,0 +1,18 @@
'use strict';
const safe = require('safetydance');
exports.up = async function (db) {
const mailDomains = await db.runSql('SELECT * FROM mail', []);
for (const mailDomain of mailDomains) {
let catchAll = safe.JSON.parse(mailDomain.catchAllJson) || [];
if (catchAll.length === 0) continue;
catchAll = catchAll.map(a => `${a}@${mailDomain.domain}`);
await db.runSql('UPDATE mail SET catchAllJson = ? WHERE domain = ?', [ JSON.stringify(catchAll), mailDomain.domain ]);
}
};
exports.down = async function( /* db */) {
};

View File

@@ -1042,6 +1042,10 @@ async function setCatchAllAddress(domain, addresses) {
assert.strictEqual(typeof domain, 'string');
assert(Array.isArray(addresses));
for (const address of addresses) {
if (!validator.isEmail(address)) throw new BoxError(BoxError.BAD_FIELD, `Invalid catch all address: ${address}`);
}
await updateDomain(domain, { catchAll: addresses });
safe(restartMail(), { debug }); // have to restart mail container since haraka cannot watch symlinked config files (mail.ini)

View File

@@ -352,10 +352,19 @@ describe('Mail API', function () {
expect(response.statusCode).to.equal(400);
});
it('cannot set with bad addresses field', async function () {
const response = await superagent.post(`${serverUrl}/api/v1/mail/${dashboardDomain}/catch_all`)
.query({ access_token: owner.token })
.send({ addresses: [ 'user1' ] })
.ok(() => true);
expect(response.statusCode).to.equal(400);
});
it('set succeeds', async function () {
const response = await superagent.post(`${serverUrl}/api/v1/mail/${dashboardDomain}/catch_all`)
.query({ access_token: owner.token })
.send({ addresses: [ 'user1' ] });
.send({ addresses: [ `user1@${dashboardDomain}` ] });
expect(response.statusCode).to.equal(202);
});
@@ -365,7 +374,7 @@ describe('Mail API', function () {
.query({ access_token: owner.token });
expect(response.statusCode).to.equal(200);
expect(response.body.catchAll).to.eql([ 'user1' ]);
expect(response.body.catchAll).to.eql([ `user1@${dashboardDomain}` ]);
});
});

View File

@@ -40,11 +40,16 @@ describe('Mail', function () {
expect(mailConfig.mailFromValidation).to.be(false);
});
it('can set catch all address', async function () {
await mail.setCatchAllAddress(domain.domain, [ 'user1', 'user2' ]);
it('cannot set invalid catch all address', async function () {
const [error] = await safe(mail.setCatchAllAddress(domain.domain, [ 'user1' ]));
expect(error.reason).to.be(BoxError.BAD_FIELD);
});
it('can set invalid catch all address', async function () {
await mail.setCatchAllAddress(domain.domain, [ `user1@${domain.domain}`, `user2@${domain.domain}` ]);
const mailConfig = await mail.getDomain(domain.domain);
expect(mailConfig.catchAll).to.eql([ 'user1', 'user2' ]);
expect(mailConfig.catchAll).to.eql([ `user1@${domain.domain}`, `user2@${domain.domain}` ]);
});
it('can set mail relay', async function () {