tangerine 1.4.1 → 1.4.3

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.
Files changed (2) hide show
  1. package/index.js +64 -9
  2. package/package.json +2 -1
package/index.js CHANGED
@@ -7,7 +7,7 @@ const { debuglog } = require('node:util');
7
7
  const { getEventListeners, setMaxListeners } = require('node:events');
8
8
  const { isIP, isIPv4, isIPv6 } = require('node:net');
9
9
 
10
- const { toASCII } = require('punycode/');
10
+ const autoBind = require('auto-bind');
11
11
  const getStream = require('get-stream');
12
12
  const ipaddr = require('ipaddr.js');
13
13
  const mergeOptions = require('merge-options');
@@ -18,6 +18,8 @@ const packet = require('dns-packet');
18
18
  const semver = require('semver');
19
19
  const structuredClone = require('@ungap/structured-clone').default;
20
20
  const { getService } = require('port-numbers');
21
+ // eslint-disable-next-line import/order
22
+ const { toASCII } = require('punycode/');
21
23
 
22
24
  const pkg = require('./package.json');
23
25
 
@@ -363,6 +365,13 @@ class Tangerine extends dns.promises.Resolver {
363
365
 
364
366
  // manage set of abort controllers
365
367
  this.abortControllers = new Set();
368
+
369
+ //
370
+ // NOTE: bind methods so we don't have to programmatically call `.bind`
371
+ // (e.g. `getDmarcRecord(name, resolver.resolve.bind(resolver))`)
372
+ // (alternative to `autoBind(this)` is `this[method] = this[method].bind(this)`)
373
+ //
374
+ autoBind(this);
366
375
  }
367
376
 
368
377
  setLocalAddress(ipv4, ipv6) {
@@ -1234,7 +1243,7 @@ class Tangerine extends dns.promises.Resolver {
1234
1243
  data = await this.options.cache.get(key);
1235
1244
  // safeguard in case cache pollution
1236
1245
  if (data && typeof data === 'object') {
1237
- debug('cache retrieved', data);
1246
+ debug('cache retrieved', key);
1238
1247
  const now = Date.now();
1239
1248
  // safeguard in case cache pollution
1240
1249
  if (
@@ -1243,6 +1252,7 @@ class Tangerine extends dns.promises.Resolver {
1243
1252
  !Number.isFinite(data.ttl) ||
1244
1253
  data.ttl < 1
1245
1254
  ) {
1255
+ debug('cache expired', key);
1246
1256
  data = undefined;
1247
1257
  } else if (options?.ttl) {
1248
1258
  // clone the data so that we don't mutate cache (e.g. if it's in-memory)
@@ -1262,6 +1272,7 @@ class Tangerine extends dns.promises.Resolver {
1262
1272
 
1263
1273
  // eslint-disable-next-line max-depth
1264
1274
  if (data.answers[i].ttl <= 0) {
1275
+ debug('answer cache expired', key);
1265
1276
  data = undefined;
1266
1277
  break;
1267
1278
  }
@@ -1508,13 +1519,57 @@ class Tangerine extends dns.promises.Resolver {
1508
1519
 
1509
1520
  case 'TXT': {
1510
1521
  // text records `dnsPromises.resolveTxt()`
1511
- return result.answers.flatMap((a) => [
1512
- Buffer.isBuffer(a.data)
1513
- ? a.data.toString()
1514
- : Array.isArray(a.data)
1515
- ? a.data.map((d) => (Buffer.isBuffer(d) ? d.toString() : d))
1516
- : a.data
1517
- ]);
1522
+ return result.answers.flatMap((a) => {
1523
+ //
1524
+ // NOTE: we need to support buffer conversion
1525
+ // (e.g. JSON.stringify from most cache stores will convert this as such below)
1526
+ //
1527
+ // a {
1528
+ // name: 'forwardemail.net',
1529
+ // type: 'TXT',
1530
+ // ttl: 3600,
1531
+ // class: 'IN',
1532
+ // flush: false,
1533
+ // data: [ { type: 'Buffer', data: [Array] } ]
1534
+ // }
1535
+ //
1536
+ // (or)
1537
+ //
1538
+ // a {
1539
+ // name: 'forwardemail.net',
1540
+ // type: 'TXT',
1541
+ // ttl: 3600,
1542
+ // class: 'IN',
1543
+ // flush: false,
1544
+ // data: { type: 'Buffer', data: [Array] }
1545
+ // }
1546
+ //
1547
+ if (Array.isArray(a.data)) {
1548
+ a.data = a.data.map((d) => {
1549
+ if (
1550
+ typeof d === 'object' &&
1551
+ d.type === 'Buffer' &&
1552
+ Array.isArray(d.data)
1553
+ )
1554
+ return Buffer.from(d.data);
1555
+ return d;
1556
+ });
1557
+ } else if (
1558
+ typeof a.data === 'object' &&
1559
+ a.data.type === 'Buffer' &&
1560
+ Array.isArray(a.data.data)
1561
+ ) {
1562
+ a.data = Buffer.from(a.data.data);
1563
+ }
1564
+
1565
+ return [
1566
+ Buffer.isBuffer(a.data)
1567
+ ? a.data.toString()
1568
+ : Array.isArray(a.data)
1569
+ ? a.data.map((d) => (Buffer.isBuffer(d) ? d.toString() : d))
1570
+ : a.data
1571
+ ];
1572
+ });
1518
1573
  }
1519
1574
 
1520
1575
  default: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tangerine",
3
3
  "description": "Tangerine is the best Node.js drop-in replacement for dns.promises.Resolver using DNS over HTTPS (\"DoH\") via undici with built-in retries, timeouts, smart server rotation, AbortControllers, and caching support for multiple backends (with TTL and purge support).",
4
- "version": "1.4.1",
4
+ "version": "1.4.3",
5
5
  "author": "Forward Email (https://forwardemail.net)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/forwardemail/tangerine/issues"
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "dependencies": {
13
13
  "@ungap/structured-clone": "^1.0.2",
14
+ "auto-bind": "4",
14
15
  "dns-packet": "^5.4.0",
15
16
  "dohdec": "^5.0.3",
16
17
  "get-stream": "6",