Skip to content

Commit

Permalink
feat: parse header to get resulting objects
Browse files Browse the repository at this point in the history
  • Loading branch information
niftylettuce committed Aug 6, 2020
1 parent b31b042 commit 7fc3ec0
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 7 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,19 @@ authenticateMessage(message, authservId, ip, mailFrom, helo)
})();
```
The value of `result` is an String with the new Authentication-Results header to add to the top of the message headers.
The value of `result` is an Object with properties `header` (String), and Objects for `spf`, `dkim`, `arc`, and `dmarc`. These Object's contain a `result` (String) and conditionally a `reason` (String) value.
An example `result` object is provided below:
```js
{
header: 'Authentication-Results: example.com; spf=none smtp.helo=domain.of.sender.net smtp.mailfrom=test.com; dkim=pass header.d=forwardemail.net; arc=pass; dmarc=fail (Used From Domain Record) header.from=gmail.com policy.dmarc=none',
spf: { result: 'none' },
dkim: { result: 'pass' },
arc: { result: 'pass' },
dmarc: { policy: 'none', result: 'fail', reason: 'Used From Domain Record' }
}
```
## Contributors
Expand Down
50 changes: 49 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ if (!semver.satisfies(version, '>= 3.5'))
`Python v3.5+ is required, you currently have v${version} installed`
);

const KEYS = ['spf', 'dkim', 'arc', 'dmarc'];

function authenticateMessage(message, ...args) {
const command = `python3 ${scripts.authenticateMessage} ${args.join(' ')}`;
debug(command);
Expand All @@ -57,7 +59,53 @@ function authenticateMessage(message, ...args) {
child.stdin.end();
child.on('close', () => {
if (stderr.length > 0) return reject(new Error(stderr.join('')));
resolve(stdout.join(''));
// Authentication-Results: mx1.forwardemail.net; spf=fail reason="SPF fail - not authorized" smtp.helo=jacks-macbook-pro.local [email protected]; dkim=fail; arc=none; dmarc=fail (Used From Domain Record) header.from=forwardemail.net policy.dmarc=reject
const result = { header: stdout.join('').trim() };
for (const key of KEYS) {
result[key] = {};
}

result.dmarc.policy = 'none';

const terms = result.header
.split(/;/)
.map((t) => t.trim())
.filter((t) => t !== '');

for (const term of terms) {
const split = term.split('=');
if (term.startsWith('spf=')) {
result.spf.result = split[1].split(' ')[0];
const index = term.indexOf('reason=');
if (index !== -1)
result.spf.reason = term
.slice(index + 'reason='.length)
.split('"')[1];
} else if (term.startsWith('dkim=')) {
result.dkim.result = split[1].split(' ')[0];
const index = term.indexOf('(');
if (index !== -1)
result.dkim.reason = term.slice(index + '('.length).split(')')[0];
} else if (term.startsWith('arc=')) {
result.arc.result = split[1].split(' ')[0];
// TODO: right now this does not return a comment due to this issue:
// <https://github.com/ValiMail/authentication-headers/issues/12
} else if (term.startsWith('dmarc=')) {
result.dmarc.result = split[1].split(' ')[0];
// reason
const index = term.indexOf('(');
if (index !== -1)
result.dmarc.reason = term.slice(index + '('.length).split(')')[0];
// policy
const policyIndex = term.indexOf('policy.dmarc=');
if (policyIndex !== -1)
result.dmarc.policy = term
.slice(policyIndex + 'policy.dmarc='.length)
.split(' ')[0];
}
}

resolve(result);
});
});
}
Expand Down
23 changes: 18 additions & 5 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,24 @@ test('authenticate message', async (t) => {
'domain.of.sender.net'
);

t.is(
result,
'Authentication-Results: example.com; spf=none smtp.helo=domain.of.sender.net smtp.mailfrom=test.com; dkim=pass header.d=forwardemail.net; arc=pass; dmarc=fail (Used From Domain Record) header.from=gmail.com policy.dmarc=none'
);
t.deepEqual(result, {
arc: {
result: 'pass'
},
dkim: {
result: 'pass'
},
dmarc: {
policy: 'none',
reason: 'Used From Domain Record',
result: 'fail'
},
header:
'Authentication-Results: example.com; spf=none smtp.helo=domain.of.sender.net smtp.mailfrom=test.com; dkim=pass header.d=forwardemail.net; arc=pass; dmarc=fail (Used From Domain Record) header.from=gmail.com policy.dmarc=none',
spf: {
result: 'none'
}
});
});

test('arc sign throws error with missing From header', async (t) => {
Expand All @@ -46,5 +60,4 @@ test('arc sign throws error with missing From header', async (t) => {
),
{ message: /IndexError: list index out of range/g }
);
t.pass();
});

0 comments on commit 7fc3ec0

Please sign in to comment.