-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: fixed alias token verification, wrapped resolveTxt with try/catc…
…h, added and updated tests
- Loading branch information
Showing
2 changed files
with
172 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ const createTangerine = require('#helpers/create-tangerine'); | |
const env = require('#config/env'); | ||
const logger = require('#helpers/logger'); | ||
const processEmail = require('#helpers/process-email'); | ||
const { Emails } = require('#models'); | ||
const { Emails, Aliases } = require('#models'); | ||
|
||
const asyncMxConnect = pify(mxConnect); | ||
const IP_ADDRESS = ip.address(); | ||
|
@@ -185,6 +185,157 @@ Test`.trim() | |
} | ||
}); | ||
|
||
test('auth with pass as alias', async (t) => { | ||
const smtp = new SMTP({ client: t.context.client }, true); | ||
const port = await getPort(); | ||
await smtp.listen(port); | ||
|
||
const user = await factory.create('user', { | ||
plan: 'enhanced_protection', | ||
[config.userFields.planSetAt]: dayjs().startOf('day').toDate() | ||
}); | ||
|
||
await factory.create('payment', { | ||
user: user._id, | ||
amount: 300, | ||
invoice_at: dayjs().startOf('day').toDate(), | ||
method: 'free_beta_program', | ||
duration: ms('30d'), | ||
plan: user.plan, | ||
kind: 'one-time' | ||
}); | ||
|
||
await user.save(); | ||
|
||
const resolver = createTangerine(t.context.client, logger); | ||
|
||
const domain = await factory.create('domain', { | ||
members: [{ user: user._id, group: 'admin' }], | ||
plan: user.plan, | ||
resolver, | ||
has_smtp: true | ||
}); | ||
|
||
const alias = await factory.create('alias', { | ||
user: user._id, | ||
domain: domain._id, | ||
recipients: [user.email] | ||
}); | ||
|
||
await alias.createToken(); | ||
await alias.save(); | ||
|
||
// spoof dns records | ||
const map = new Map(); | ||
|
||
map.set( | ||
`txt:${domain.name}`, | ||
resolver.spoofPacket( | ||
domain.name, | ||
'TXT', | ||
[`${config.paidPrefix}${domain.verification_record}`], | ||
true | ||
) | ||
); | ||
|
||
// dkim | ||
map.set( | ||
`txt:${domain.dkim_key_selector}._domainkey.${domain.name}`, | ||
resolver.spoofPacket( | ||
`${domain.dkim_key_selector}._domainkey.${domain.name}`, | ||
'TXT', | ||
[`v=DKIM1; k=rsa; p=${domain.dkim_public_key.toString('base64')};`], | ||
true | ||
) | ||
); | ||
|
||
// spf | ||
map.set( | ||
`txt:${env.WEB_HOST}`, | ||
resolver.spoofPacket( | ||
`${env.WEB_HOST}`, | ||
'TXT', | ||
[`v=spf1 ip4:${IP_ADDRESS} -all`], | ||
true | ||
) | ||
); | ||
|
||
// cname | ||
map.set( | ||
`cname:${domain.return_path}.${domain.name}`, | ||
resolver.spoofPacket( | ||
`${domain.return_path}.${domain.name}`, | ||
'CNAME', | ||
[env.WEB_HOST], | ||
true | ||
) | ||
); | ||
|
||
// cname -> txt | ||
map.set( | ||
`txt:${domain.return_path}.${domain.name}`, | ||
resolver.spoofPacket( | ||
`${domain.return_path}.${domain.name}`, | ||
'TXT', | ||
[`v=spf1 ip4:${IP_ADDRESS} -all`], | ||
true | ||
) | ||
); | ||
|
||
// dmarc | ||
map.set( | ||
`txt:_dmarc.${domain.name}`, | ||
resolver.spoofPacket( | ||
`_dmarc.${domain.name}`, | ||
'TXT', | ||
[ | ||
// TODO: consume dmarc reports and parse dmarc-$domain | ||
`v=DMARC1; p=reject; pct=100; rua=mailto:dmarc-${domain.id}@forwardemail.net;` | ||
], | ||
true | ||
) | ||
); | ||
|
||
// store spoofed dns cache | ||
await resolver.options.cache.mset(map); | ||
|
||
const transporter = nodemailer.createTransport({ | ||
logger, | ||
debug: true, | ||
host: IP_ADDRESS, | ||
port, | ||
ignoreTLS: true, | ||
secure: true, | ||
tls: { | ||
rejectUnauthorized: false | ||
}, | ||
auth: { | ||
user: `${alias.name}@${domain.name}`, | ||
pass: 'test' | ||
} | ||
}); | ||
|
||
const err = await t.throwsAsync( | ||
transporter.sendMail({ | ||
envelope: { | ||
from: `${alias.name}@${domain.name}`, | ||
to: '[email protected]' | ||
}, | ||
raw: ` | ||
To: [email protected] | ||
From: [email protected] | ||
Subject: test | ||
Content-Type: text/plain; charset=us-ascii | ||
Content-Transfer-Encoding: 7bit | ||
Test`.trim() | ||
}) | ||
); | ||
|
||
t.is(err.responseCode, 535); | ||
t.regex(err.message, /Invalid password/); | ||
}); | ||
|
||
test('smtp outbound auth', async (t) => { | ||
const smtp = new SMTP({ client: t.context.client }, false); | ||
const { resolver } = smtp; | ||
|
@@ -225,6 +376,10 @@ test('smtp outbound auth', async (t) => { | |
t.true(typeof pass === 'string' && pass.length === 24); | ||
await alias.save(); | ||
|
||
const isValid = await Aliases.isValidPassword(alias.tokens, pass); | ||
|
||
t.true(isValid); | ||
|
||
const combos = [ | ||
{ user: 'a', pass: 'a' }, | ||
{ user: `beep@${domain.name}`, pass }, | ||
|