From cc87db7a4f147b23888ed0887f4b201b3294ef6b Mon Sep 17 00:00:00 2001 From: titanism <101466223+titanism@users.noreply.github.com> Date: Wed, 8 Jan 2025 02:04:20 -0600 Subject: [PATCH] fix: fixed SRS issues --- helpers/check-srs.js | 21 ++++++++++++++++++++- helpers/get-forwarding-addresses.js | 4 ++-- helpers/get-recipients.js | 16 +++++++++++++++- helpers/on-data-mx.js | 3 --- helpers/on-data.js | 2 ++ test/mx/index.js | 11 ++++++++++- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/helpers/check-srs.js b/helpers/check-srs.js index e5f7d020ab..21a9ffe4b1 100644 --- a/helpers/check-srs.js +++ b/helpers/check-srs.js @@ -21,7 +21,26 @@ function checkSRS(address, shouldThrow = false, ignoreHook = false) { if (!REGEX_SRS0.test(address) && !REGEX_SRS1.test(address)) return address; try { - const reversed = srs.reverse(address); + // + // sometimes senders send to a lowercase version of the MAIL FROM + // which is going to mess things up here because case sensitivity is needed + // therefore we will do a rewrite here if necessary + // + const index = address.indexOf('@'); + const local = address.slice(0, index).split('='); + const domain = address.slice(index + 1); + + // + // > local.split('=') + // [ 'srs0', '4f4d', 't7', 'example.com', 'john' ] + // and we need + // SRS0=4f4d=T7=example.com=john + // therefore keys 0 and 2 need capitalized + // + if (local[0]) local[0] = local[0].toUpperCase(); // SRS0 + if (local[2]) local[2] = local[2].toUpperCase(); // T7 + const srsAddress = `${local.join('=')}@${domain}`; + const reversed = srs.reverse(srsAddress); if (_.isNull(reversed)) throw new Error('Bad signature'); return reversed; } catch (_err) { diff --git a/helpers/get-forwarding-addresses.js b/helpers/get-forwarding-addresses.js index 62661d0cdb..39c3a05772 100644 --- a/helpers/get-forwarding-addresses.js +++ b/helpers/get-forwarding-addresses.js @@ -229,7 +229,7 @@ async function getForwardingAddresses( if (!isSANB(record) && !hasIMAP) throw new SMTPError( `${address} is not yet configured with its email service provider ${config.urls.web} ;`, - { responseCode: 421, ignore_hook: true } + { responseCode: 421, ignore_hook: true, notConfigured: true } ); // e.g. user@example.com => user@gmail.com @@ -557,7 +557,7 @@ async function getForwardingAddresses( if (forwardingAddresses.length === 0 && !hasIMAP) { throw new SMTPError( `${address} is not yet configured with its email service provider ${config.urls.web} ;`, - { responseCode: 421, ignore_hook: true } + { responseCode: 421, ignore_hook: true, notConfigured: true } ); } diff --git a/helpers/get-recipients.js b/helpers/get-recipients.js index b7126bdacd..060c7b7698 100644 --- a/helpers/get-recipients.js +++ b/helpers/get-recipients.js @@ -332,6 +332,19 @@ async function getRecipients(session, scan) { webhookKey }; } catch (err) { + if (err.notConfigured && to.srs) { + return { + address: to.address, + addresses: [to.address], + port: 25, + hasIMAP: false, + aliasPublicKey: false, + vacationResponder: false, + // TODO: only do this if MX server of sender used our service + srs: true + }; + } + logger.warn(err, { session }); err.responseCode = getErrorCode(err); bounces.push({ @@ -609,7 +622,8 @@ async function getRecipients(session, scan) { port: recipient.port, recipient: recipient.address, to: [address.to], - replacements + replacements, + ...(recipient.srs ? { srs: true } : {}) }); } } diff --git a/helpers/on-data-mx.js b/helpers/on-data-mx.js index 83e8867d4f..4981af0eb5 100644 --- a/helpers/on-data-mx.js +++ b/helpers/on-data-mx.js @@ -1690,9 +1690,6 @@ async function onDataMX(session, headers, body) { } } - // TODO: fix the SRS0 thing (not rewriting properly. e.g. RCD) - // TODO: if it was SRS rewritten then it shouldn't 421 it should deliver to the address still - // // send vacation responders if necessary in series // diff --git a/helpers/on-data.js b/helpers/on-data.js index d26c821017..8c64fd049b 100644 --- a/helpers/on-data.js +++ b/helpers/on-data.js @@ -100,7 +100,9 @@ async function onData(stream, _session, fn) { // however because srs0 was rewritten from SRS0 // and because tv was rewritten from TV it is not being delivered correctly // + const original = to.address; to.address = checkSRS(to.address, shouldThrow); + if (original !== to.address) to.srs = true; return to; }), async (to) => { diff --git a/test/mx/index.js b/test/mx/index.js index 442a9fc486..060493a711 100644 --- a/test/mx/index.js +++ b/test/mx/index.js @@ -18,6 +18,7 @@ const pWaitFor = require('p-wait-for'); const pify = require('pify'); const test = require('ava'); const { SMTPServer } = require('smtp-server'); +const { SRS } = require('sender-rewriting-scheme'); const utils = require('../utils'); @@ -40,6 +41,7 @@ import('@ava/get-port').then((obj) => { const asyncMxConnect = pify(mxConnect); const IP_ADDRESS = ip.address(); const tls = { rejectUnauthorized: false }; +const srs = new SRS(config.srs); test.before(utils.setupMongoose); test.before(utils.setupRedisClient); @@ -333,7 +335,14 @@ test('imap/forward/webhook', async (t) => { transporter.sendMail({ envelope: { from: 'test@test.com', - to: `test@${domain.name}` + to: [ + `test@${domain.name}`, + // + // NOTE: this is purposely formatted incorrectly + // to test when mail servers send to lowercase version of MAIL FROM + // (we have logic that accounts for this, see `#helpers/check-srs`) + srs.forward(`test@${domain.name}`, env.WEB_HOST).toLowerCase() + ] }, raw: ` To: test@${domain.name}