mailauth 5.0.1 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +7 -0
- package/lib/spf/macro.js +7 -2
- package/lib/spf/spf-verify.js +10 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.0.2](https://github.com/postalsys/mailauth/compare/v5.0.1...v5.0.2) (2026-08-19)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **spf:** expand %{d} macro to the domain currently being evaluated ([#126](https://github.com/postalsys/mailauth/issues/126)) ([53c4522](https://github.com/postalsys/mailauth/commit/53c45220a1af41febb5b901c251ed4cc66de511e))
|
|
9
|
+
|
|
3
10
|
## [5.0.1](https://github.com/postalsys/mailauth/compare/v5.0.0...v5.0.1) (2026-08-07)
|
|
4
11
|
|
|
5
12
|
|
package/lib/spf/macro.js
CHANGED
|
@@ -12,11 +12,12 @@ const os = require('node:os');
|
|
|
12
12
|
* @param {String} values.ip Sender IP address
|
|
13
13
|
* @param {String} values.helo Client's HELO/EHLO domain
|
|
14
14
|
* @param {String} [values.mta] Hostname of the MTA or MX server that processes the message
|
|
15
|
+
* @param {String} [values.domain] Domain currently being evaluated by check_host(), changes on include/redirect recursion (RFC 7208 sections 5.2, 6.1)
|
|
15
16
|
*/
|
|
16
17
|
const macro = (input, values) => {
|
|
17
18
|
input = (input || '').toString();
|
|
18
19
|
|
|
19
|
-
let { sender, ip, helo, mta } = values || {};
|
|
20
|
+
let { sender, ip, helo, mta, domain } = values || {};
|
|
20
21
|
|
|
21
22
|
sender = (sender || '').toString();
|
|
22
23
|
ip = (ip || '').toString();
|
|
@@ -64,11 +65,15 @@ const macro = (input, values) => {
|
|
|
64
65
|
break;
|
|
65
66
|
|
|
66
67
|
case 'o':
|
|
67
|
-
case 'd':
|
|
68
68
|
case 'p': // validated domain name is unsupported, instead we use the unvalidated sender domain
|
|
69
69
|
curval = senderDomain;
|
|
70
70
|
break;
|
|
71
71
|
|
|
72
|
+
case 'd':
|
|
73
|
+
// current <domain> of check_host(), not the sender domain (these only match at the top level)
|
|
74
|
+
curval = domain || senderDomain;
|
|
75
|
+
break;
|
|
76
|
+
|
|
72
77
|
case 'i':
|
|
73
78
|
curval = ipaddr.parse(ip).toNormalizedString();
|
|
74
79
|
if (net.isIPv6(ip)) {
|
package/lib/spf/spf-verify.js
CHANGED
|
@@ -72,6 +72,9 @@ const spfVerify = async (domain, opts) => {
|
|
|
72
72
|
|
|
73
73
|
let addr = ipaddr.parse(opts.ip);
|
|
74
74
|
|
|
75
|
+
// %{d} must expand to the domain currently being evaluated, which changes on include/redirect recursion
|
|
76
|
+
let macroValues = { sender: opts.sender, ip: opts.ip, helo: opts.helo, mta: opts.mta, domain };
|
|
77
|
+
|
|
75
78
|
let resolver = opts.resolver || dns.resolve;
|
|
76
79
|
|
|
77
80
|
let responses;
|
|
@@ -135,7 +138,7 @@ const spfVerify = async (domain, opts) => {
|
|
|
135
138
|
let modifier = part.substr(0, splitPos).toLowerCase();
|
|
136
139
|
let value = part.substr(splitPos + 1);
|
|
137
140
|
|
|
138
|
-
value = macro(value,
|
|
141
|
+
value = macro(value, macroValues)
|
|
139
142
|
// remove trailing dot
|
|
140
143
|
.replace(/\.$/, '');
|
|
141
144
|
|
|
@@ -254,7 +257,7 @@ const spfVerify = async (domain, opts) => {
|
|
|
254
257
|
case 'include':
|
|
255
258
|
{
|
|
256
259
|
try {
|
|
257
|
-
let redirect = macro(val,
|
|
260
|
+
let redirect = macro(val, macroValues)
|
|
258
261
|
// remove trailing dot
|
|
259
262
|
.replace(/\.$/, '');
|
|
260
263
|
let sub = await spfVerify(redirect, opts);
|
|
@@ -328,7 +331,7 @@ const spfVerify = async (domain, opts) => {
|
|
|
328
331
|
let { domain: a, cidr4, cidr6 } = parseCidrValue(val, domain, type);
|
|
329
332
|
let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
|
|
330
333
|
|
|
331
|
-
a = macro(a,
|
|
334
|
+
a = macro(a, macroValues);
|
|
332
335
|
|
|
333
336
|
try {
|
|
334
337
|
a = punycode.toASCII(a);
|
|
@@ -354,7 +357,7 @@ const spfVerify = async (domain, opts) => {
|
|
|
354
357
|
let { domain: mxDomain, cidr4, cidr6 } = parseCidrValue(val, domain, type);
|
|
355
358
|
let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
|
|
356
359
|
|
|
357
|
-
mxDomain = macro(mxDomain,
|
|
360
|
+
mxDomain = macro(mxDomain, macroValues);
|
|
358
361
|
|
|
359
362
|
try {
|
|
360
363
|
mxDomain = punycode.toASCII(mxDomain);
|
|
@@ -397,7 +400,7 @@ const spfVerify = async (domain, opts) => {
|
|
|
397
400
|
|
|
398
401
|
case 'exists':
|
|
399
402
|
{
|
|
400
|
-
let existDomain = macro(val,
|
|
403
|
+
let existDomain = macro(val, macroValues);
|
|
401
404
|
try {
|
|
402
405
|
existDomain = punycode.toASCII(existDomain);
|
|
403
406
|
} catch (err) {
|
|
@@ -420,12 +423,8 @@ const spfVerify = async (domain, opts) => {
|
|
|
420
423
|
throw err;
|
|
421
424
|
}
|
|
422
425
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
ptrDomain = macro(val, opts);
|
|
426
|
-
} else {
|
|
427
|
-
ptrDomain = macro('%{d}', opts);
|
|
428
|
-
}
|
|
426
|
+
// bare "ptr" defaults to %{d}, the currently evaluated domain
|
|
427
|
+
let ptrDomain = val ? macro(val, macroValues) : domain;
|
|
429
428
|
ptrDomain = formatDomain(ptrDomain);
|
|
430
429
|
|
|
431
430
|
// Step 1. Resolve PTR hostnames
|