mailauth 4.4.2 → 4.5.0
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/bin/mailauth.js +51 -0
- package/cli.md +30 -0
- package/lib/commands/bodyhash.js +66 -0
- package/lib/commands/sign.js +3 -3
- package/lib/dkim/body/index.js +5 -2
- package/lib/dkim/dkim-signer.js +6 -2
- package/lib/dkim/header/index.js +5 -2
- package/lib/tools.js +6 -2
- package/licenses.txt +2 -2
- package/man/mailauth.1 +1 -1
- package/package.json +6 -6
package/bin/mailauth.js
CHANGED
|
@@ -12,6 +12,7 @@ const commandSign = require('../lib/commands/sign');
|
|
|
12
12
|
const commandSeal = require('../lib/commands/seal');
|
|
13
13
|
const commandSpf = require('../lib/commands/spf');
|
|
14
14
|
const commandVmc = require('../lib/commands/vmc');
|
|
15
|
+
const commandBodyhash = require('../lib/commands/bodyhash');
|
|
15
16
|
|
|
16
17
|
const fs = require('fs');
|
|
17
18
|
const pathlib = require('path');
|
|
@@ -100,6 +101,12 @@ const argv = yargs(hideBin(process.argv))
|
|
|
100
101
|
description: 'Key selector for signing (s= tag)',
|
|
101
102
|
demandOption: true
|
|
102
103
|
})
|
|
104
|
+
.option('algo', {
|
|
105
|
+
alias: 'a',
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'Signing algorithm. Defaults either to rsa-sha256 or ed25519-sha256 depending on the private key format.',
|
|
108
|
+
default: 'rsa-sha256'
|
|
109
|
+
})
|
|
103
110
|
.option('canonicalization', {
|
|
104
111
|
alias: 'c',
|
|
105
112
|
type: 'string',
|
|
@@ -344,6 +351,50 @@ const argv = yargs(hideBin(process.argv))
|
|
|
344
351
|
});
|
|
345
352
|
}
|
|
346
353
|
)
|
|
354
|
+
.command(
|
|
355
|
+
['bodyhash [email]'],
|
|
356
|
+
'Generate a signature body hash for an email',
|
|
357
|
+
yargs => {
|
|
358
|
+
yargs
|
|
359
|
+
|
|
360
|
+
.option('algo', {
|
|
361
|
+
alias: 'a',
|
|
362
|
+
type: 'string',
|
|
363
|
+
description: 'Hashing algorithm. Defaults to sha256.',
|
|
364
|
+
default: 'sha256'
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
.option('canonicalization', {
|
|
368
|
+
alias: 'c',
|
|
369
|
+
type: 'string',
|
|
370
|
+
description: 'Canonicalization algorithm (c= tag)',
|
|
371
|
+
default: 'relaxed'
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
.option('body-length', {
|
|
375
|
+
alias: 'l',
|
|
376
|
+
type: 'number',
|
|
377
|
+
description: 'Maximum length of canonicalizated body to sign (l= tag)'
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
yargs.positional('email', {
|
|
381
|
+
describe: 'Path to the email message file in EML format. If not specified then content is read from stdin'
|
|
382
|
+
});
|
|
383
|
+
},
|
|
384
|
+
argv => {
|
|
385
|
+
commandBodyhash(argv)
|
|
386
|
+
.then(() => {
|
|
387
|
+
process.exit();
|
|
388
|
+
})
|
|
389
|
+
.catch(err => {
|
|
390
|
+
if (!err.suppress) {
|
|
391
|
+
console.error('Failed to calculate body hash for the input message');
|
|
392
|
+
console.error(err);
|
|
393
|
+
}
|
|
394
|
+
process.exit(1);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
)
|
|
347
398
|
.command(
|
|
348
399
|
['license'],
|
|
349
400
|
'Show license information',
|
package/cli.md
CHANGED
|
@@ -14,6 +14,7 @@ Command line utility and a [Node.js library](README.md) for email authentication
|
|
|
14
14
|
- [seal](#seal) - to seal an email with ARC
|
|
15
15
|
- [spf](#spf) - to validate SPF for an IP address and an email address
|
|
16
16
|
- [vmc](#vmc) - to validate BIMI VMC logo files
|
|
17
|
+
- [bodyhash](#bodyhash) - to generate the signature body hash value for an email
|
|
17
18
|
- [license](#license) - display licenses for `mailauth` and included modules
|
|
18
19
|
- [DNS cache file](#dns-cache-file)
|
|
19
20
|
|
|
@@ -320,6 +321,35 @@ $ mailauth vmc -p /path/to/vmc-with-invalid-svg.pem
|
|
|
320
321
|
}
|
|
321
322
|
```
|
|
322
323
|
|
|
324
|
+
### bodyhash
|
|
325
|
+
|
|
326
|
+
`bodyhash` command takes an email message and calculates the body hash value for it
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
$ mailauth bodyhash [options] [email]
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Where
|
|
333
|
+
|
|
334
|
+
- **options** are option flags and arguments
|
|
335
|
+
- **email** is the path to EML formatted email message file. If not provided then email message is read from standard input
|
|
336
|
+
|
|
337
|
+
**Options**
|
|
338
|
+
|
|
339
|
+
- `--algo sha256` or `-a sha256` is the signing algorithm. Defaults to "sha256". Can also use the a= tag format ("rsa-sha256").
|
|
340
|
+
- `--canonicalization algo` or `-c algo` is the body canonicalization algorithm, defaults to "relaxed". Can also use the c= tag format ("relaxed/relaxed").
|
|
341
|
+
- `--body-length 12345` or `-l 12345` is the maximum length of canonicalizated body to sign (l= tag)
|
|
342
|
+
|
|
343
|
+
**Example**
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
$ mailauth bodyhash /path/message.eml -a sha1 --verbose
|
|
347
|
+
Hashing algorithm: sha1
|
|
348
|
+
Body canonicalization algorithm: relaxed
|
|
349
|
+
--------
|
|
350
|
+
j+dD7whKXS1yDmyoWtvClYSyYiQ=
|
|
351
|
+
```
|
|
352
|
+
|
|
323
353
|
### license
|
|
324
354
|
|
|
325
355
|
Display licenses for `mailauth` and included modules.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { DkimSigner } = require('../dkim/dkim-signer');
|
|
4
|
+
const { writeToStream } = require('../tools');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
|
|
7
|
+
const cmd = async argv => {
|
|
8
|
+
let source = argv.email;
|
|
9
|
+
let useStdin = false;
|
|
10
|
+
let stream;
|
|
11
|
+
|
|
12
|
+
if (!source) {
|
|
13
|
+
useStdin = true;
|
|
14
|
+
source = 'standard input';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (argv.verbose) {
|
|
18
|
+
console.error(`Reading email message from ${source}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (useStdin) {
|
|
22
|
+
stream = process.stdin;
|
|
23
|
+
} else {
|
|
24
|
+
stream = fs.createReadStream(source);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isNaN(argv.bodyLength) || argv.bodyLength < 0) {
|
|
28
|
+
argv.bodyLength = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let signatureOpts = {
|
|
32
|
+
type: 'DKIM',
|
|
33
|
+
privateKey: true, // force hash calculation
|
|
34
|
+
canonicalization: argv.canonicalization && (argv.canonicalization.includes('/') ? argv.canonicalization : `/${argv.canonicalization}`),
|
|
35
|
+
algorithm: argv.algo,
|
|
36
|
+
maxBodyLength: argv.bodyLength
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
let dkimSigner = new DkimSigner({ signatureData: [signatureOpts] });
|
|
40
|
+
|
|
41
|
+
let { hashAlgo } = dkimSigner.getAlgorithm(signatureOpts);
|
|
42
|
+
let { bodyCanon } = dkimSigner.getCanonicalization(signatureOpts);
|
|
43
|
+
|
|
44
|
+
if (argv.verbose) {
|
|
45
|
+
if (hashAlgo) {
|
|
46
|
+
console.error(`Hashing algorithm: ${hashAlgo}`);
|
|
47
|
+
}
|
|
48
|
+
if (bodyCanon) {
|
|
49
|
+
console.error(`Body canonicalization algorithm: ${bodyCanon}`);
|
|
50
|
+
}
|
|
51
|
+
if (signatureOpts.maxBodyLength) {
|
|
52
|
+
console.error(`Maximum body length: ${signatureOpts.maxBodyLength}`);
|
|
53
|
+
}
|
|
54
|
+
console.error('--------');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await writeToStream(dkimSigner, stream);
|
|
58
|
+
|
|
59
|
+
let hashKey = `${bodyCanon}:${hashAlgo}:${typeof argv.bodyLength === 'number' ? argv.bodyLength : ''}`;
|
|
60
|
+
const bodyHash = dkimSigner.bodyHashes.get(hashKey)?.hash;
|
|
61
|
+
if (bodyHash) {
|
|
62
|
+
process.stdout.write(bodyHash);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
module.exports = cmd;
|
package/lib/commands/sign.js
CHANGED
|
@@ -48,12 +48,12 @@ const cmd = async argv => {
|
|
|
48
48
|
if (signatureOpts.selector) {
|
|
49
49
|
console.error(`Key selector: ${signatureOpts.selector}`);
|
|
50
50
|
}
|
|
51
|
-
if (signatureOpts.canonicalization) {
|
|
52
|
-
console.error(`Canonicalization algorithm: ${signatureOpts.canonicalization}`);
|
|
53
|
-
}
|
|
54
51
|
if (signatureOpts.algorithm) {
|
|
55
52
|
console.error(`Hashing algorithm: ${signatureOpts.algorithm}`);
|
|
56
53
|
}
|
|
54
|
+
if (signatureOpts.canonicalization) {
|
|
55
|
+
console.error(`Canonicalization algorithm: ${signatureOpts.canonicalization}`);
|
|
56
|
+
}
|
|
57
57
|
if (signatureOpts.maxBodyLength) {
|
|
58
58
|
console.error(`Maximum body length: ${signatureOpts.maxBodyLength}`);
|
|
59
59
|
}
|
package/lib/dkim/body/index.js
CHANGED
|
@@ -10,8 +10,11 @@ const dkimBody = (canonicalization, ...options) => {
|
|
|
10
10
|
return new SimpleHash(...options);
|
|
11
11
|
case 'relaxed':
|
|
12
12
|
return new RelaxedHash(...options);
|
|
13
|
-
default:
|
|
14
|
-
|
|
13
|
+
default: {
|
|
14
|
+
let error = new Error('Unknown body canonicalization');
|
|
15
|
+
error.canonicalization = canonicalization;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
19
|
};
|
|
17
20
|
|
package/lib/dkim/dkim-signer.js
CHANGED
|
@@ -96,11 +96,15 @@ class DkimSigner extends MessageParser {
|
|
|
96
96
|
let [header, body] = canonicalization.split('/');
|
|
97
97
|
|
|
98
98
|
if (!['relaxed', 'simple'].includes(header)) {
|
|
99
|
-
|
|
99
|
+
let error = new Error('Unknown header canonicalization');
|
|
100
|
+
error.canonicalization = header;
|
|
101
|
+
throw error;
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
if (!['relaxed', 'simple'].includes(body)) {
|
|
103
|
-
|
|
105
|
+
let error = new Error('Unknown body canonicalization');
|
|
106
|
+
error.canonicalization = body;
|
|
107
|
+
throw error;
|
|
104
108
|
}
|
|
105
109
|
} catch (err) {
|
|
106
110
|
err.code = 'EINVALIDCANON';
|
package/lib/dkim/header/index.js
CHANGED
|
@@ -11,8 +11,11 @@ const generateCanonicalizedHeader = (type, signingHeaderLines, options) => {
|
|
|
11
11
|
return simpleHeaders(type, signingHeaderLines, options);
|
|
12
12
|
case 'relaxed':
|
|
13
13
|
return relaxedHeaders(type, signingHeaderLines, options);
|
|
14
|
-
default:
|
|
15
|
-
|
|
14
|
+
default: {
|
|
15
|
+
let error = new Error('Unknown header canonicalization');
|
|
16
|
+
error.canonicalization = canonicalization;
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
16
19
|
}
|
|
17
20
|
};
|
|
18
21
|
|
package/lib/tools.js
CHANGED
|
@@ -450,11 +450,15 @@ const validateAlgorithm = (algorithm, strict) => {
|
|
|
450
450
|
let [signAlgo, hashAlgo] = algorithm.toLowerCase().split('-');
|
|
451
451
|
|
|
452
452
|
if (!['rsa', 'ed25519'].includes(signAlgo)) {
|
|
453
|
-
|
|
453
|
+
let error = new Error('Unknown signing algorithm');
|
|
454
|
+
error.signAlgo = signAlgo;
|
|
455
|
+
throw error;
|
|
454
456
|
}
|
|
455
457
|
|
|
456
458
|
if (!['sha256'].concat(!strict ? 'sha1' : []).includes(hashAlgo)) {
|
|
457
|
-
|
|
459
|
+
let error = new Error('Unknown hashing algorithm');
|
|
460
|
+
error.hashAlgo = hashAlgo;
|
|
461
|
+
throw error;
|
|
458
462
|
}
|
|
459
463
|
} catch (err) {
|
|
460
464
|
err.code = 'EINVALIDALGO';
|
package/licenses.txt
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
name license type link installed version author
|
|
2
2
|
---- ------------ ---- ----------------- ------
|
|
3
3
|
@postalsys/vmc MIT https://registry.npmjs.org/@postalsys/vmc/-/vmc-1.0.6.tgz 1.0.6 Postal Systems OÜ
|
|
4
|
-
fast-xml-parser MIT git+https://github.com/NaturalIntelligence/fast-xml-parser.git 4.2.
|
|
4
|
+
fast-xml-parser MIT git+https://github.com/NaturalIntelligence/fast-xml-parser.git 4.2.6 Amit Gupta (https://amitguptagwl.github.io)
|
|
5
5
|
ipaddr.js MIT git://github.com/whitequark/ipaddr.js.git 2.1.0 whitequark <whitequark@whitequark.org>
|
|
6
6
|
joi BSD-3-Clause git://github.com/hapijs/joi.git 17.9.2 n/a
|
|
7
7
|
libmime MIT git://github.com/andris9/libmime.git 5.2.1 Andris Reinman <andris@kreata.ee>
|
|
8
|
-
nodemailer MIT-0 git+https://github.com/nodemailer/nodemailer.git 6.9.
|
|
8
|
+
nodemailer MIT-0 git+https://github.com/nodemailer/nodemailer.git 6.9.4 Andris Reinman
|
|
9
9
|
psl MIT git+ssh://git@github.com/lupomontero/psl.git 1.9.0 Lupo Montero <lupomontero@gmail.com> (https://lupomontero.com/)
|
|
10
10
|
punycode MIT git+https://github.com/mathiasbynens/punycode.js.git 2.3.0 Mathias Bynens https://mathiasbynens.be/
|
|
11
11
|
yargs MIT git+https://github.com/yargs/yargs.git 17.7.2 n/a
|
package/man/mailauth.1
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailauth",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Email authentication library for Node.js",
|
|
5
5
|
"main": "lib/mailauth.js",
|
|
6
6
|
"scripts": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"homepage": "https://github.com/postalsys/mailauth",
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"chai": "4.3.7",
|
|
36
|
-
"eslint": "8.
|
|
36
|
+
"eslint": "8.46.0",
|
|
37
37
|
"eslint-config-nodemailer": "1.2.0",
|
|
38
38
|
"eslint-config-prettier": "8.9.0",
|
|
39
39
|
"js-yaml": "4.1.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@postalsys/vmc": "1.0.6",
|
|
49
|
-
"fast-xml-parser": "4.2.
|
|
49
|
+
"fast-xml-parser": "4.2.7",
|
|
50
50
|
"ipaddr.js": "2.1.0",
|
|
51
51
|
"joi": "17.9.2",
|
|
52
52
|
"libmime": "5.2.1",
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
"LICENSE.txt"
|
|
72
72
|
],
|
|
73
73
|
"targets": [
|
|
74
|
-
"
|
|
75
|
-
"
|
|
74
|
+
"node18-linux-x64",
|
|
75
|
+
"node18-macos-x64",
|
|
76
76
|
"node18-macos-arm64",
|
|
77
|
-
"
|
|
77
|
+
"node18-win-x64"
|
|
78
78
|
],
|
|
79
79
|
"outputPath": "ee-dist"
|
|
80
80
|
}
|