|
1 | 1 | 'use strict'
|
2 | 2 |
|
3 | 3 | const dns = require('dns')
|
| 4 | +const _ = require('lodash') |
| 5 | +const errcode = require('err-code') |
4 | 6 |
|
5 | 7 | module.exports = (domain, opts, callback) => {
|
6 |
| - dns.resolveTxt(domain, (err, records) => { |
7 |
| - if (err) { |
8 |
| - return callback(err, null) |
9 |
| - } |
| 8 | + resolveDnslink(domain) |
| 9 | + .catch(err => { |
| 10 | + // If the code is not ENOTFOUND or ERR_DNSLINK_NOT_FOUND then throw the error |
| 11 | + if (err.code !== 'ENOTFOUND' && err.code !== 'ERR_DNSLINK_NOT_FOUND') throw err |
10 | 12 |
|
11 |
| - // TODO: implement recursive option |
12 |
| - |
13 |
| - for (const record of records) { |
14 |
| - if (record[0].startsWith('dnslink=')) { |
15 |
| - return callback(null, record[0].substr(8, record[0].length - 1)) |
| 13 | + if (domain.startsWith('_dnslink.')) { |
| 14 | + // The supplied domain contains a _dnslink component |
| 15 | + // Check the non-_dnslink domain |
| 16 | + const rootDomain = domain.replace('_dnslink.', '') |
| 17 | + return resolveDnslink(rootDomain) |
16 | 18 | }
|
17 |
| - } |
| 19 | + // Check the _dnslink subdomain |
| 20 | + const _dnslinkDomain = `_dnslink.${domain}` |
| 21 | + // If this throws then we propagate the error |
| 22 | + return resolveDnslink(_dnslinkDomain) |
| 23 | + }) |
| 24 | + .then(dnslinkRecord => { |
| 25 | + callback(null, dnslinkRecord.replace('dnslink=', '')) |
| 26 | + }) |
| 27 | + .catch(callback) |
| 28 | +} |
18 | 29 |
|
19 |
| - callback(new Error('domain does not have a txt dnslink entry')) |
| 30 | +function resolveDnslink (domain) { |
| 31 | + const DNSLINK_REGEX = /^dnslink=.+$/ |
| 32 | + return new Promise((resolve, reject) => { |
| 33 | + dns.resolveTxt(domain, (err, records) => { |
| 34 | + if (err) return reject(err) |
| 35 | + resolve(records) |
| 36 | + }) |
20 | 37 | })
|
| 38 | + .then(records => { |
| 39 | + return _.chain(records).flatten().filter(record => { |
| 40 | + return DNSLINK_REGEX.test(record) |
| 41 | + }).value() |
| 42 | + }) |
| 43 | + .then(dnslinkRecords => { |
| 44 | + // we now have dns text entries as an array of strings |
| 45 | + // only records passing the DNSLINK_REGEX text are included |
| 46 | + if (dnslinkRecords.length === 0) { |
| 47 | + throw errcode(`No dnslink records found for domain: ${domain}`, 'ERR_DNSLINK_NOT_FOUND') |
| 48 | + } |
| 49 | + return dnslinkRecords[0] |
| 50 | + }) |
21 | 51 | }
|
0 commit comments