New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mailauth

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mailauth - npm Package Compare versions

Comparing version 1.0.16 to 1.0.17

3

lib/arc/index.js

@@ -55,3 +55,4 @@ 'use strict';

try {
publicKey = await getPublicKey('AS', queryDomain, resolver);
let res = await getPublicKey('AS', queryDomain, resolver);
publicKey = res?.publicKey;
} catch (err) {

@@ -58,0 +59,0 @@ err.queryDomain = queryDomain;

@@ -177,3 +177,3 @@ 'use strict';

let publicKey;
let publicKey, rr;
let status = {

@@ -206,3 +206,3 @@ result: 'neutral',

try {
publicKey = await getPublicKey(
let res = await getPublicKey(
signatureHeader.type,

@@ -213,2 +213,5 @@ `${signatureHeader.selector}._domainkey.${signatureHeader.signingDomain}`,

publicKey = res?.publicKey;
rr = res?.rr;
try {

@@ -231,2 +234,6 @@ status.result = crypto.verify(

} catch (err) {
if (err.rr) {
rr = err.rr;
}
switch (err.code) {

@@ -281,2 +288,6 @@ case 'ENOTFOUND':

if (rr) {
result.rr = rr;
}
switch (signatureHeader.type) {

@@ -283,0 +294,0 @@ case 'ARC':

@@ -69,2 +69,3 @@ 'use strict';

parsed.rr = txt;
parsed.isOrgRecord = isOrgRecord;

@@ -158,3 +159,4 @@

sp: dmarcRecord.sp || dmarcRecord.p,
pct: dmarcRecord.pct
pct: dmarcRecord.pct,
rr: dmarcRecord.rr
});

@@ -161,0 +163,0 @@ };

@@ -217,2 +217,6 @@ 'use strict';

if (result.rr) {
response.rr = result.rr;
}
response.status = status;

@@ -219,0 +223,0 @@ response.header = formatHeaders(response);

@@ -78,2 +78,3 @@ 'use strict';

let spfRecord;
let spfRr;

@@ -91,2 +92,3 @@ for (let row of responses) {

}
spfRr = row;
spfRecord = parts.slice(1);

@@ -102,251 +104,253 @@ }

// this check is only for passing test suite
for (let i = spfRecord.length - 1; i >= 0; i--) {
let part = spfRecord[i];
if (/^[^:/]+=/.test(part)) {
//modifier, not mechanism
let getResult = async () => {
// this check is only for passing test suite
for (let i = spfRecord.length - 1; i >= 0; i--) {
let part = spfRecord[i];
if (/^[^:/]+=/.test(part)) {
//modifier, not mechanism
if (!/^[a-z](a-z0-9-_\.)*/i.test(part)) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `invalid modifier ${part}` };
throw err;
if (!/^[a-z](a-z0-9-_\.)*/i.test(part)) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `invalid modifier ${part}` };
throw err;
}
let splitPos = part.indexOf('=');
let modifier = part.substr(0, splitPos).toLowerCase();
let value = part.substr(splitPos + 1);
value = macro(value, opts)
// remove trailing dot
.replace(/\.$/, '');
if (!value) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `Empty modifier value for ${modifier}` };
throw err;
} else if (modifier === 'redirect' && !/^([\x21-\x2D\x2f-\x7e]+\.)+[a-z]+[a-z\-0-9]*$/.test(value)) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `Invalid redirect target ${value}` };
throw err;
}
spfRecord.splice(i, 1);
spfRecord.push({ modifier, value });
continue;
}
let splitPos = part.indexOf('=');
let modifier = part.substr(0, splitPos).toLowerCase();
let value = part.substr(splitPos + 1);
let mechanism = part
.split(/[:/=]/)
.shift()
.toLowerCase()
.replace(/^[?\-~+]/, '');
value = macro(value, opts)
// remove trailing dot
.replace(/\.$/, '');
if (!value) {
if (!['all', 'include', 'a', 'mx', 'ip4', 'ip6', 'exists', 'ptr'].includes(mechanism)) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `Empty modifier value for ${modifier}` };
err.spfResult = { error: 'permerror', text: `Unknown mechanism ${mechanism}` };
throw err;
} else if (modifier === 'redirect' && !/^([\x21-\x2D\x2f-\x7e]+\.)+[a-z]+[a-z\-0-9]*$/.test(value)) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `Invalid redirect target ${value}` };
throw err;
}
spfRecord.splice(i, 1);
spfRecord.push({ modifier, value });
continue;
}
let mechanism = part
.split(/[:/=]/)
.shift()
.toLowerCase()
.replace(/^[?\-~+]/, '');
if (!['all', 'include', 'a', 'mx', 'ip4', 'ip6', 'exists', 'ptr'].includes(mechanism)) {
if (spfRecord.filter(p => p && p.modifier === 'redirect').length > 1) {
// too many redirects
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `Unknown mechanism ${mechanism}` };
err.spfResult = { error: 'permerror', text: `more than 1 redirect found` };
throw err;
}
}
if (spfRecord.filter(p => p && p.modifier === 'redirect').length > 1) {
// too many redirects
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `more than 1 redirect found` };
throw err;
}
for (let i = 0; i < spfRecord.length; i++) {
let part = spfRecord[i];
for (let i = 0; i < spfRecord.length; i++) {
let part = spfRecord[i];
if (typeof part === 'object' && part.modifier) {
let { modifier, value } = part;
if (typeof part === 'object' && part.modifier) {
let { modifier, value } = part;
switch (modifier) {
case 'redirect':
{
if (spfRecord.some(p => /^[?\-~+]?all$/i.test(p))) {
// ignore redirect if "all" condition is set
continue;
}
switch (modifier) {
case 'redirect':
{
if (spfRecord.some(p => /^[?\-~+]?all$/i.test(p))) {
// ignore redirect if "all" condition is set
continue;
}
try {
let subResult = await spfVerify(value, opts);
if (subResult) {
return subResult;
}
} catch (err) {
// kind of ignore
if (err.spfResult) {
if (err.spfResult.error === 'none') {
err.spfResult.error = 'permerror';
try {
let subResult = await spfVerify(value, opts);
if (subResult) {
return subResult;
}
throw err;
} catch (err) {
// kind of ignore
if (err.spfResult) {
if (err.spfResult.error === 'none') {
err.spfResult.error = 'permerror';
}
throw err;
}
}
}
}
break;
break;
case 'exp':
default:
// do nothing
case 'exp':
default:
// do nothing
}
continue;
}
continue;
}
let key = '';
let val = '';
let qualifier = '+'; // default is pass
let key = '';
let val = '';
let qualifier = '+'; // default is pass
let splitterPos = part.indexOf(':');
if (splitterPos === part.length - 1) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `unexpected empty value` };
throw err;
}
if (splitterPos >= 0) {
key = part.substr(0, splitterPos);
val = part.substr(splitterPos + 1);
} else {
let splitterPos = part.indexOf('/');
let splitterPos = part.indexOf(':');
if (splitterPos === part.length - 1) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `unexpected empty value` };
throw err;
}
if (splitterPos >= 0) {
key = part.substr(0, splitterPos);
val = part.substr(splitterPos); // keep the / for CIDR
val = part.substr(splitterPos + 1);
} else {
key = part;
let splitterPos = part.indexOf('/');
if (splitterPos >= 0) {
key = part.substr(0, splitterPos);
val = part.substr(splitterPos); // keep the / for CIDR
} else {
key = part;
}
}
}
if (/^[?\-~+]/.test(key)) {
qualifier = key.charAt(0);
key = key.substr(1);
}
if (/^[?\-~+]/.test(key)) {
qualifier = key.charAt(0);
key = key.substr(1);
}
let type = key.toLowerCase();
switch (type) {
case 'all':
if (val) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `unexpected extension for all` };
throw err;
}
return { type, qualifier };
case 'include':
{
try {
let redirect = macro(val, opts)
// remove trailing dot
.replace(/\.$/, '');
let sub = await spfVerify(redirect, opts);
if (sub && sub.qualifier === '+') {
// ignore other valid responses
return { type, val, include: sub, qualifier };
}
if (sub && sub.error) {
return sub;
}
} catch (err) {
// kind of ignore
if (err.spfResult) {
if (err.spfResult.error === 'none') {
err.spfResult.error = 'permerror';
}
return err.spfResult;
}
}
}
break;
case 'ip4':
case 'ip6':
{
let { domain: range, cidr4, cidr6 } = parseCidrValue(val);
if (!range) {
let type = key.toLowerCase();
switch (type) {
case 'all':
if (val) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `bare IP address` };
err.spfResult = { error: 'permerror', text: `unexpected extension for all` };
throw err;
}
return { type, qualifier };
let originalRange = range;
let mappingMatch = (range || '').toString().match(/^[:A-F]+:((\d+\.){3}\d+)$/i);
if (mappingMatch) {
range = mappingMatch[1];
case 'include':
{
try {
let redirect = macro(val, opts)
// remove trailing dot
.replace(/\.$/, '');
let sub = await spfVerify(redirect, opts);
if (sub && sub.qualifier === '+') {
// ignore other valid responses
return { type, val, include: sub, qualifier };
}
if (sub && sub.error) {
return sub;
}
} catch (err) {
// kind of ignore
if (err.spfResult) {
if (err.spfResult.error === 'none') {
err.spfResult.error = 'permerror';
}
return err.spfResult;
}
}
}
break;
if (net.isIP(range)) {
if (type === 'ip6' && net.isIPv6(opts.ip) && net.isIPv6(originalRange) && net.isIPv4(range) && cidr4 === '/0') {
// map all IPv6 addresses
return { type, val, qualifier };
}
// validate ipv4 range only, skip ipv6
if (cidr6 && net.isIPv4(range)) {
case 'ip4':
case 'ip6':
{
let { domain: range, cidr4, cidr6 } = parseCidrValue(val);
if (!range) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `invalid CIDR for IP` };
err.spfResult = { error: 'permerror', text: `bare IP address` };
throw err;
}
if (net.isIP(range) !== net.isIP(opts.ip) || net.isIP(range) !== Number(type.charAt(2))) {
// nothing to do here
break;
let originalRange = range;
let mappingMatch = (range || '').toString().match(/^[:A-F]+:((\d+\.){3}\d+)$/i);
if (mappingMatch) {
range = mappingMatch[1];
}
let cidr = net.isIPv6(range) ? cidr6 : cidr4;
if (matchIp(addr, range + cidr)) {
return { type, val, qualifier };
if (net.isIP(range)) {
if (type === 'ip6' && net.isIPv6(opts.ip) && net.isIPv6(originalRange) && net.isIPv4(range) && cidr4 === '/0') {
// map all IPv6 addresses
return { type, val, qualifier };
}
// validate ipv4 range only, skip ipv6
if (cidr6 && net.isIPv4(range)) {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `invalid CIDR for IP` };
throw err;
}
if (net.isIP(range) !== net.isIP(opts.ip) || net.isIP(range) !== Number(type.charAt(2))) {
// nothing to do here
break;
}
let cidr = net.isIPv6(range) ? cidr6 : cidr4;
if (matchIp(addr, range + cidr)) {
return { type, val, qualifier };
}
} else {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `invalid IP address` };
throw err;
}
} else {
let err = new Error('SPF failure');
err.spfResult = { error: 'permerror', text: `invalid IP address` };
throw err;
}
}
break;
break;
case 'a':
{
let { domain: a, cidr4, cidr6 } = parseCidrValue(val, domain);
let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
case 'a':
{
let { domain: a, cidr4, cidr6 } = parseCidrValue(val, domain);
let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
a = macro(a, opts);
a = macro(a, opts);
try {
a = punycode.toASCII(a);
} catch (err) {
// ignore punycode conversion errors
}
try {
a = punycode.toASCII(a);
} catch (err) {
// ignore punycode conversion errors
}
let responses = await resolver(a, net.isIPv6(opts.ip) ? 'AAAA' : 'A');
if (responses) {
for (let ip of responses) {
if (matchIp(addr, ip + cidr)) {
return { type, val: domain, qualifier };
let responses = await resolver(a, net.isIPv6(opts.ip) ? 'AAAA' : 'A');
if (responses) {
for (let ip of responses) {
if (matchIp(addr, ip + cidr)) {
return { type, val: domain, qualifier };
}
}
}
}
}
break;
break;
case 'mx':
{
let { domain: mxDomain, cidr4, cidr6 } = parseCidrValue(val, domain);
let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
case 'mx':
{
let { domain: mxDomain, cidr4, cidr6 } = parseCidrValue(val, domain);
let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
try {
mxDomain = punycode.toASCII(mxDomain);
} catch (err) {
// ignore punycode conversion errors
}
try {
mxDomain = punycode.toASCII(mxDomain);
} catch (err) {
// ignore punycode conversion errors
}
let mxList = await resolver(mxDomain, 'MX');
if (mxList) {
mxList = mxList.sort((a, b) => a.priority - b.priority);
for (let mx of mxList) {
if (mx.exchange) {
let responses = await resolver(mx.exchange, net.isIPv6(opts.ip) ? 'AAAA' : 'A');
if (responses) {
for (let a of responses) {
if (matchIp(addr, a + cidr)) {
return { type, val: mx.exchange, qualifier };
let mxList = await resolver(mxDomain, 'MX');
if (mxList) {
mxList = mxList.sort((a, b) => a.priority - b.priority);
for (let mx of mxList) {
if (mx.exchange) {
let responses = await resolver(mx.exchange, net.isIPv6(opts.ip) ? 'AAAA' : 'A');
if (responses) {
for (let a of responses) {
if (matchIp(addr, a + cidr)) {
return { type, val: mx.exchange, qualifier };
}
}

@@ -358,30 +362,43 @@ }

}
}
break;
break;
case 'exists':
{
let existDomain = macro(val, opts);
try {
existDomain = punycode.toASCII(existDomain);
} catch (err) {
// ignore punycode conversion errors
}
case 'exists':
{
let existDomain = macro(val, opts);
try {
existDomain = punycode.toASCII(existDomain);
} catch (err) {
// ignore punycode conversion errors
}
let responses = await resolver(existDomain, 'A');
if (responses && responses.length) {
return { type, val: existDomain, qualifier };
let responses = await resolver(existDomain, 'A');
if (responses && responses.length) {
return { type, val: existDomain, qualifier };
}
}
}
break;
break;
case 'ptr':
// ignore, not supported
break;
case 'ptr':
// ignore, not supported
break;
}
}
return false;
};
try {
let res = await getResult();
if (res && spfRr) {
res.rr = spfRr;
}
return res;
} catch (err) {
if (spfRr && err.spfResult) {
err.spfResult.rr = spfRr;
}
throw err;
}
return false;
};
module.exports = { spfVerify };

@@ -234,7 +234,7 @@ /* eslint no-control-regex: 0 */

const getPublicKey = async (type, rr, resolver) => {
const getPublicKey = async (type, name, resolver) => {
resolver = resolver || dns.resolve;
let list = await resolver(rr, 'TXT');
let row =
let list = await resolver(name, 'TXT');
let rr =
list &&

@@ -246,10 +246,11 @@ []

if (row) {
if (rr) {
// prefix value for parsing as there is no default value
let entry = parseDkimHeaders(`DNS: TXT;${row}`);
let entry = parseDkimHeaders(`DNS: TXT;${rr}`);
let pubKey = entry?.parsed?.p?.value;
if (!pubKey) {
let publicKey = entry?.parsed?.p?.value;
if (!publicKey) {
let err = new Error('Missing key value');
err.code = 'EINVALIDVAL';
err.rr = rr;
throw err;

@@ -261,7 +262,8 @@ }

err.code = 'EINVALIDVER';
err.rr = rr;
throw err;
}
pubKey = Buffer.from(`-----BEGIN PUBLIC KEY-----\n${pubKey}\n-----END PUBLIC KEY-----`);
let keyType = crypto.createPublicKey({ key: pubKey, format: 'pem' }).asymmetricKeyType;
publicKey = Buffer.from(`-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`);
let keyType = crypto.createPublicKey({ key: publicKey, format: 'pem' }).asymmetricKeyType;

@@ -271,2 +273,3 @@ if (!['rsa', 'ed25519'].includes(keyType) || (entry?.parsed?.k && entry?.parsed?.k?.value?.toLowerCase() !== keyType)) {

err.code = 'EINVALIDTYPE';
err.rr = rr;
throw err;

@@ -277,6 +280,7 @@ }

// check key length
const pubKeyData = pki.publicKeyFromPem(pubKey.toString());
const pubKeyData = pki.publicKeyFromPem(publicKey.toString());
if (pubKeyData.n.bitLength() < 1024) {
let err = new Error('Key too short');
err.code = 'ESHORTKEY';
err.rr = rr;
throw err;

@@ -286,3 +290,3 @@ }

return pubKey;
return { publicKey, rr };
}

@@ -289,0 +293,0 @@

{
"name": "mailauth",
"version": "1.0.16",
"version": "1.0.17",
"description": "Email authentication library for Node.js",

@@ -5,0 +5,0 @@ "main": "lib/mailauth.js",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc