Skip to content

Commit

Permalink
Release 1.1.0 (haraka#4)
Browse files Browse the repository at this point in the history
* spf: use async/await dns
* replace many callbacks with async/await
* make check_host more linear
* ci(publish): only when package.json bumped
* index: safeguard cfg path with optional chaining
* dep(nopt): bump 6 -> 7
* dev: remove version bump from PR template
  • Loading branch information
msimerson authored Dec 18, 2022
1 parent 2390b21 commit 820f63b
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 462 deletions.
1 change: 0 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ Checklist:
- [ ] docs updated
- [ ] tests updated
- [ ] Changes.md updated
- [ ] package.json.version bumped
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
branches:
- master
paths:
- package.json

env:
CI: true
Expand Down
9 changes: 9 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@

### Unreleased

### [1.1.0] - 2022-12-17

- spf: use async/await dns
- replace many callbacks with async/await
- make check_host more linear
- ci(publish): only when package.json bumped
- index: safeguard cfg path with optional chaining, fixes #2
- dep(nopt): bump 6 -> 7


### [1.0.1] - 2022-07-23

Expand Down
87 changes: 41 additions & 46 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ exports.load_spf_ini = function () {
plugin.cfg.lookup_timeout = plugin.cfg.main.lookup_timeout || plugin.timeout - 1;
}

exports.helo_spf = function (next, connection, helo) {
exports.helo_spf = async function (next, connection, helo) {
const plugin = this;

// bypass auth'ed or relay'ing hosts if told to
Expand Down Expand Up @@ -113,16 +113,13 @@ exports.helo_spf = function (next, connection, helo) {
const timer = setTimeout(() => {
timeout = true;
connection.loginfo(plugin, 'timeout');
return next();
next();
}, plugin.cfg.lookup_timeout * 1000);

spf.check_host(connection.remote.ip, helo, null, (err, result) => {
try {
const result = await spf.check_host(connection.remote.ip, helo, null)
if (timer) clearTimeout(timer);
if (timeout) return;
if (err) {
connection.logerror(plugin, err);
return next();
}
const host = connection.hello.host;
plugin.log_result(connection, 'helo', host, `postmaster@${host}`, spf.result(result));

Expand All @@ -134,11 +131,14 @@ exports.helo_spf = function (next, connection, helo) {
emit: true,
});
if (spf.result(result) === 'Pass') connection.results.add(plugin, { pass: host });
next();
});
}
catch (err) {
connection.logerror(plugin, err);
}
next();
}

exports.hook_mail = function (next, connection, params) {
exports.hook_mail = async function (next, connection, params) {
const plugin = this;

const txn = connection?.transaction;
Expand All @@ -154,7 +154,7 @@ exports.hook_mail = function (next, connection, params) {
// For messages from private IP space...
if (connection.remote?.is_private) {
if (!connection.relaying) return next();
if (connection.relaying && plugin.cfg.relay?.context !== 'myself') {
if (plugin.cfg.relay?.context !== 'myself') {
txn.results.add(plugin, {skip: 'host(private_ip)'});
return next(CONT, 'envelope from private IP space');
}
Expand Down Expand Up @@ -214,43 +214,38 @@ exports.hook_mail = function (next, connection, params) {
plugin.return_results(next, connection, spf, 'mfrom', result, mfrom);
}

// typical inbound (!relay)
if (!connection.relaying) {
return spf.check_host(connection.remote.ip, host, mfrom, ch_cb);
}
try {
// Always check the client IP first. A relay could be sending inbound mail
// from a non-local domain, which could case an incorrect SPF Fail result
// if we check the public IP first. Only check the public IP if the
// client IP returns a result other than 'Pass'.
const result = await spf.check_host(connection.remote.ip, host, mfrom)

// outbound (relaying), context=sender
if (plugin.cfg.relay.context === 'sender') {
return spf.check_host(connection.remote.ip, host, mfrom, ch_cb);
}
// typical inbound (!relay)
if (!connection.relaying) return ch_cb(result)

// outbound (relaying), context=myself
net_utils.get_public_ip((e, my_public_ip) => {
// We always check the client IP first, because a relay
// could be sending inbound mail from a non-local domain
// which could case an incorrect SPF Fail result if we
// check the public IP first, so we only check the public
// IP if the client IP returns a result other than 'Pass'.
spf.check_host(connection.remote.ip, host, mfrom, (err, result) => {
let spf_result;
if (result) {
spf_result = spf.result(result).toLowerCase();
}
if (err || (spf_result && spf_result !== 'pass')) {
if (e) return ch_cb(e); // Error looking up public IP

if (!my_public_ip) {
return ch_cb(new Error(`failed to discover public IP`));
}
spf = new SPF();
spf.check_host(my_public_ip, host, mfrom, (er, r) => {
ch_cb(er, r, my_public_ip);
});
return;
// outbound (relaying), context=sender
if (plugin.cfg.relay.context === 'sender') return ch_cb(result)

// outbound (relaying), context=myself
const my_public_ip = await net_utils.get_public_ip()

let spf_result;
if (result) spf_result = spf.result(result).toLowerCase();

if (spf_result && spf_result !== 'pass') {
if (!my_public_ip) {
return ch_cb(new Error(`failed to discover public IP`));
}
ch_cb(err, result, connection.remote.ip);
});
});
spf = new SPF();
const r = await spf.check_host(my_public_ip, host, mfrom)
return ch_cb(null, r, my_public_ip);
}
ch_cb(null, result, connection.remote.ip);
}
catch (err) {
ch_cb(err)
}
}

exports.log_result = function (connection, scope, host, mfrom, result, ip) {
Expand Down Expand Up @@ -319,7 +314,7 @@ exports.save_to_header = (connection, spf, result, mfrom, host, id, ip) => {
exports.skip_hosts = function (connection) {
const plugin = this;

const skip = plugin.cfg.skip;
const skip = plugin?.cfg?.skip;
if (skip) {
if (skip.relaying && connection.relaying) return 'relay';
if (skip.auth && connection.notes.auth_user) return 'auth';
Expand Down
Loading

0 comments on commit 820f63b

Please sign in to comment.