Comparing version 1.0.0-dev.3 to 1.0.0
@@ -15,2 +15,6 @@ 'use strict'; | ||
console.log(JSON.stringify(res, false, 2)); | ||
console.log('----'); | ||
console.log(res.headers.trim()); | ||
console.log('----'); | ||
}; | ||
@@ -17,0 +21,0 @@ |
@@ -22,3 +22,3 @@ 'use strict'; | ||
this.headerFrom = false; | ||
this.headerFrom = []; | ||
this.envelopeFrom = false; | ||
@@ -31,4 +31,4 @@ } | ||
let fromHeader = headers.parsed.find(h => h.key === 'from'); | ||
if (fromHeader) { | ||
let fromHeaders = headers.parsed.filter(h => h.key === 'from'); | ||
for (let fromHeader of fromHeaders) { | ||
fromHeader = fromHeader.line.toString(); | ||
@@ -40,7 +40,11 @@ let splitterPos = fromHeader.indexOf(':'); | ||
let from = addressparser(fromHeader.trim()); | ||
this.headerFrom = from.length && from[0].address ? from[0].address : false; | ||
for (let addr of from) { | ||
if (addr && addr.address) { | ||
this.headerFrom.push(addr.address); | ||
} | ||
} | ||
} | ||
if (this.options.returnPath) { | ||
let returnPath = addressparser(this.options.returnPath); | ||
if (this.options.sender) { | ||
let returnPath = addressparser(this.options.sender); | ||
this.envelopeFrom = returnPath.length && returnPath[0].address ? returnPath[0].address : false; | ||
@@ -47,0 +51,0 @@ } else { |
@@ -5,2 +5,3 @@ 'use strict'; | ||
const { spf } = require('./spf'); | ||
const { dmarc } = require('./dmarc'); | ||
const libmime = require('libmime'); | ||
@@ -23,3 +24,9 @@ const os = require('os'); | ||
const [dkimResult, spfResult] = await Promise.all([dkimVerify(input, { resolver: opts.resolver }), spf(opts)]); | ||
const [dkimResult, spfResult] = await Promise.all([ | ||
dkimVerify(input, { | ||
resolver: opts.resolver, | ||
sender: opts.sender | ||
}), | ||
spf(opts) | ||
]); | ||
@@ -39,3 +46,3 @@ let headers = []; | ||
`spf=${spfResult.status}${spfResult.info ? ` (${spfResult.info})` : ''}${ | ||
spfResult['envelope-from'] ? ` smtp.mailfrom=${spfResult['envelope-from']};` : '' | ||
spfResult['envelope-from'] ? ` smtp.mailfrom=${spfResult['envelope-from']}` : '' | ||
}` | ||
@@ -47,7 +54,25 @@ ) | ||
headers.push(`Authentication-Results: ${opts.mta};\r\n ` + arHeader.join('\r\n ')); | ||
let dmarcResult; | ||
if (dkimResult && dkimResult.headerFrom) { | ||
dmarcResult = await dmarc({ | ||
headerFrom: dkimResult.headerFrom, | ||
spfDomains: [].concat((spfResult && spfResult.status === 'pass' && spfResult.domain) || []), | ||
dkimDomains: (dkimResult.results || []).filter(r => r.status === 'pass').map(r => r.signingDomain), | ||
resolver: opts.resolver | ||
}); | ||
if (dmarcResult.info) { | ||
arHeader.push(`${libmime.foldLines(dmarcResult.info)}`); | ||
} | ||
} | ||
return { dkim: dkimResult, spf: spfResult, headers: headers.join('\r\n') + '\r\n' }; | ||
headers.push(`Authentication-Results: ${opts.mta};\r\n ` + arHeader.join(';\r\n ')); | ||
return { | ||
dkim: dkimResult, | ||
spf: spfResult, | ||
dmarc: dmarcResult, | ||
headers: headers.join('\r\n') + '\r\n' | ||
}; | ||
}; | ||
module.exports = { authenticate }; |
@@ -118,12 +118,2 @@ 'use strict'; | ||
try { | ||
if (domain.split('.').some(label => label.length > 63)) { | ||
// too long label | ||
let err = new Error('Too long label'); | ||
err.spfResult = { | ||
error: 'none', | ||
text: 'DNS label too long' | ||
}; | ||
throw err; | ||
} | ||
let validation = domainSchema.validate(domain); | ||
@@ -151,3 +141,3 @@ if (validation.error) { | ||
let response = { 'client-ip': ip }; | ||
let response = { domain, 'client-ip': ip }; | ||
if (helo) { | ||
@@ -154,0 +144,0 @@ response.helo = helo; |
@@ -8,2 +8,4 @@ 'use strict'; | ||
const pki = require('node-forge').pki; | ||
const https = require('https'); | ||
const packageData = require('../package'); | ||
@@ -274,2 +276,36 @@ const defaultFieldNames = | ||
const fetch = url => { | ||
return new Promise((resolve, reject) => { | ||
https | ||
.get( | ||
url, | ||
{ | ||
headers: { | ||
'User-Agent': `mailauth/${packageData.version} (+${packageData.homepage}` | ||
} | ||
}, | ||
res => { | ||
let chunks = []; | ||
let chunklen = 0; | ||
res.on('readable', () => { | ||
let chunk; | ||
while ((chunk = res.read()) !== null) { | ||
chunks.push(chunk); | ||
chunklen += chunk.length; | ||
} | ||
}); | ||
res.on('end', () => { | ||
resolve({ | ||
statusCode: res.statusCode, | ||
headers: res.headers, | ||
body: Buffer.concat(chunks, chunklen) | ||
}); | ||
}); | ||
} | ||
) | ||
.on('error', reject); | ||
}); | ||
}; | ||
module.exports = { | ||
@@ -281,3 +317,4 @@ writeToStream, | ||
parseDkimHeader, | ||
getPublicKey | ||
getPublicKey, | ||
fetch | ||
}; |
{ | ||
"name": "mailauth", | ||
"version": "1.0.0-dev.3", | ||
"version": "1.0.0", | ||
"description": "Email authentication library for Node.js", | ||
@@ -13,15 +13,20 @@ "main": "lib/mailauth.js", | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"keywords": [ | ||
"rfc822", | ||
"email", | ||
"dkim", | ||
"spf" | ||
], | ||
"author": "Andris Reinman", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/andris9/mailauth/issues" | ||
}, | ||
"homepage": "https://github.com/andris9/mailauth#readme", | ||
"homepage": "https://github.com/andris9/mailauth", | ||
"devDependencies": { | ||
"chai": "4.2.0", | ||
"eslint": "7.7.0", | ||
"eslint": "7.8.1", | ||
"eslint-config-nodemailer": "1.2.0", | ||
"eslint-config-prettier": "6.11.0", | ||
"js-yaml": "^3.14.0", | ||
"js-yaml": "3.14.0", | ||
"mbox-reader": "1.1.4", | ||
@@ -32,7 +37,8 @@ "mocha": "8.1.3" | ||
"ipaddr.js": "2.0.0", | ||
"joi": "^17.2.1", | ||
"joi": "17.2.1", | ||
"libmime": "5.0.0", | ||
"node-forge": "0.9.1", | ||
"nodemailer": "6.4.11" | ||
"node-forge": "0.10.0", | ||
"nodemailer": "6.4.11", | ||
"psl": "1.8.0" | ||
} | ||
} |
# mailauth | ||
Email authentication library for Node.js | ||
Email authentication library for Node.js (work in progress) | ||
- [x] SPF verification | ||
- [x] DKIM signing | ||
- [x] DKIM verification | ||
- [x] DMARC verification | ||
- [ ] ARC signing | ||
- [ ] ARC verification | ||
- [ ] MTA-STS resolver | ||
## Setup | ||
Install from dev channel | ||
Install from NPM | ||
``` | ||
$ npm install mailauth@dev | ||
$ npm install mailauth | ||
``` | ||
@@ -15,2 +23,4 @@ | ||
Validate DKIM signatures, SPF and DMARC for an email. | ||
```js | ||
@@ -21,6 +31,8 @@ const { authenticate } = require('mailauth'); | ||
{ | ||
ip: '217.146.67.33', | ||
helo: 'uvn-67-33.tll01.zonevs.eu', | ||
mta: 'mx.ethereal.email', | ||
sender: 'andris@ekiri.ee' | ||
// SMTP transmission options must be provided as | ||
// these are not parsed from the message | ||
ip: '217.146.67.33', // SMTP client IP | ||
helo: 'uvn-67-33.tll01.zonevs.eu', // EHLO/HELO hostname | ||
mta: 'mx.ethereal.email', // server processing this message, defaults to os.hostname() | ||
sender: 'andris@ekiri.ee' // MAIL FROM address | ||
} | ||
@@ -42,2 +54,3 @@ ); | ||
217.146.67.33 as permitted sender) smtp.mailfrom=andris@ekiri.ee; | ||
dmarc=none header.from=ekiri.ee | ||
From: ... | ||
@@ -44,0 +57,0 @@ ``` |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
334597
48
2515
0
0
137
6
8
+ Addedpsl@1.8.0
+ Added@hapi/address@4.1.0(transitive)
+ Added@hapi/formula@2.0.0(transitive)
+ Added@hapi/pinpoint@2.0.1(transitive)
+ Addedjoi@17.2.1(transitive)
+ Addednode-forge@0.10.0(transitive)
+ Addedpsl@1.8.0(transitive)
- Removed@sideway/address@4.1.5(transitive)
- Removed@sideway/formula@3.0.1(transitive)
- Removed@sideway/pinpoint@2.0.0(transitive)
- Removedjoi@17.13.3(transitive)
- Removednode-forge@0.9.1(transitive)
Updatedjoi@17.2.1
Updatednode-forge@0.10.0