Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add utility functions to use the DNS resolver contract #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
"@ethvault/iframe-provider": "0.1.9",
"base58check": "^2.0.0",
"bech32": "^1.1.3",
"bns": "^0.14.0",
"bs58": "^4.0.1",
"bufio": "^1.0.7",
"cross-fetch": "^3.0.2",
"dns-packet": "^5.2.1",
"eth-ens-namehash": "^2.0.8",
Expand Down
6 changes: 6 additions & 0 deletions src/contracts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { abi as ensContract } from '@ensdomains/contracts/abis/ens/ENS.json'
import { abi as reverseRegistrarContract } from '@ensdomains/contracts/abis/ens/ReverseRegistrar.json'
import { abi as oldResolverContract } from '@ensdomains/contracts/abis/ens-022/PublicResolver.json'
import { abi as resolverContract } from '@ensdomains/contracts/abis/resolver/Resolver.json'
import { abi as dnsResolverContract } from '@ensdomains/contracts/abis/resolver/DNSResolver.json'
import { abi as testRegistrarContract } from '@ensdomains/contracts/abis/ens/TestRegistrar.json'
import { abi as dnsRegistrarContract } from '@ensdomains/contracts/abis/dnsregistrar/DNSRegistrar.json'
import { abi as legacyAuctionRegistrarContract } from '@ensdomains/contracts/abis/ens/HashRegistrar'
Expand All @@ -19,6 +20,10 @@ function getResolverContract({ address, provider }) {
return new Contract(address, resolverContract, provider)
}

function getDNSResolverContract({ address, provider }) {
return new Contract(address, dnsResolverContract, provider)
}

function getOldResolverContract({ address, provider }) {
return new Contract(address, oldResolverContract, provider)
}
Expand Down Expand Up @@ -60,6 +65,7 @@ export {
getReverseRegistrarContract,
getENSContract,
getResolverContract,
getDNSResolverContract,
getOldResolverContract,
getDnsRegistrarContract,
getPermanentRegistrarContract,
Expand Down
132 changes: 131 additions & 1 deletion src/ens.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
import { normalize } from 'eth-ens-namehash'
import { formatsByName } from '@ensdomains/address-encoder'
import { abi as ensContract } from '@ensdomains/contracts/abis/ens/ENS.json'

import bns from 'bns'
import {BufferReader, BufferWriter} from 'bufio'
import { decryptHashes } from './preimage'

import {
Expand All @@ -30,6 +31,7 @@ import {
getReverseRegistrarContract,
getENSContract,
getResolverContract,
getDNSResolverContract,
getOldResolverContract
} from './contracts'

Expand All @@ -54,6 +56,58 @@ function getLabelhash(label) {
return labelhash(label)
}

function hashDNSName(name) {
const dnsName = bns.encoding.packName(bns.util.fqdn(name));
return utils.keccak256(dnsName);
}

// Parse a DNS record in text format and writes to a buffer
// Accepts rrs with empty rdata (ttl will always be 0 if rdata is empty):
// name.eth. 200 IN A 127.0.0.1
// name.eth. 0 IN A
function writeDNSRecordFromZone(bw, rr) {
try {
const record = bns.wire.Record.fromString(rr);
bw.writeBytes(record.encode());
} catch (e) {
// this record may have empty rdata
// [owner_name] [ttl] [class] [type] [rdata]
const parts = rr.trim().split(/[\s]+/)
if (parts.length !== 4) {
// doesn't seem like a valid record
throw new Error('unable to parse record');
}

const rname = parts[0];
if(!bns.util.isFQDN(rname)) {
throw new Error('owner name must be a fully qualified domain name');
}

const rtype = bns.wire.stringToType(parts[3]);
const rclass = bns.wire.stringToClass(parts[2]);

// manually encode the record
// since bns errors on empty rdata
bw.writeBytes(bns.encoding.packName(rname));
bw.writeU16BE(rtype);
bw.writeU16BE(rclass);
bw.writeU32BE(0); // zero TTL
bw.writeU16BE(0); // zero RDLENGTH
}
}

function decodeDNSRecords(data) {
const br = new BufferReader(data)
const records = []

while(br.left() > 0) {
let str = bns.wire.Record.read(br).toString()
records.push(str)
}

return records
}

export class ENS {
constructor({ networkId, registryAddress, provider }) {
this.registryAddress = registryAddress
Expand Down Expand Up @@ -228,6 +282,42 @@ export class ENS {
}
}

async getDNSRecordsZoneFormat(nodeName, dnsName, dnsType) {
const data = await this.getRawDNSRecords(nodeName, dnsName, dnsType);
return decodeDNSRecords(data);
}

async getRawDNSRecords(nodeName, dnsName, dnsType) {
const resolverAddr = await this.getResolver(nodeName)
return this.getRawDNSRecordsWithResolver(nodeName, dnsName, dnsType, resolverAddr)
}

async getRawDNSRecordsWithResolver(nodeName, dnsName, dnsType, resolverAddr) {
if (parseInt(resolverAddr, 16) === 0) {
return []
}

const type = bns.wire.stringToType(dnsType)
const namehash = getNamehash(bns.util.trimFQDN(nodeName))

try {
const provider = await getProvider()
const Resolver = getDNSResolverContract({
address: resolverAddr,
provider
})

const data = await Resolver.dnsRecord(namehash, hashDNSName(dnsName), type)
return Buffer.from(data.substr(2), 'hex')
} catch (e) {
console.warn(
'Error getting dns record on the dns resolver contract, are you sure the resolver address is a resolver contract?', e
)
return []
}

}

async getName(address) {
const reverseNode = `${address.slice(2)}.addr.reverse`
const resolverAddr = await this.getResolver(reverseNode)
Expand Down Expand Up @@ -492,6 +582,46 @@ export class ENS {
return Resolver.setText(namehash, key, recordValue)
}

// Sets DNS records from an array of rrs in zone format
//
// rrs example: [
// hello.eth. 300 IN A 127.0.0.1
// hello.eth. 300 IN A 127.0.0.2
// hello.eth. 300 IN TXT
// _443._tcp.hello.eth. 300 IN TLSA 3 1 1 [HASH]
// ]
//
// This will:
// 1. Add two A records
// 2. Remove any TXT records from hello.eth.
// 3. Add a TLSA record
async setDNSRecordsFromZone(name, rrs) {
const bw = new BufferWriter();
for (const rr of rrs) {
writeDNSRecordFromZone(bw, rr);
}

const data = bw.render();
return this.setRawDNSRecords(name, data);
}

async setRawDNSRecords(name, data) {
const resolverAddr = await this.getResolver(name)
return this.setRawDNSRecordsWithResolver(name, data, resolverAddr)
}

async setRawDNSRecordsWithResolver(name, data, resolverAddr) {
const namehash = getNamehash(name)
const provider = await getProvider()
const ResolverWithoutSigner = getDNSResolverContract({
address: resolverAddr,
provider
})
const signer = await getSigner()
const Resolver = ResolverWithoutSigner.connect(signer)
return Resolver.setDNSRecords(namehash, data)
}

async createSubdomain(name) {
const account = await getAccount()
const publicResolverAddress = process.env.REACT_APP_TLD_RESOLVER ||
Expand Down
84 changes: 84 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2607,11 +2607,31 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"

bcrypto@~5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/bcrypto/-/bcrypto-5.4.0.tgz#4046f0c44a4b301eff84de593b4f86fce8d91db2"
integrity sha512-KDX2CR29o6ZoqpQndcCxFZAtYA1jDMnXU3jmCfzP44g++Cu7AHHtZN/JbrN/MXAg9SLvtQ8XISG+eVD9zH1+Jg==
dependencies:
bufio "~1.0.7"
loady "~0.0.5"

bech32@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.3.tgz#bd47a8986bbb3eec34a56a097a84b8d3e9a2dfcd"
integrity sha512-yuVFUvrNcoJi0sv5phmqc6P+Fl1HjRDRNOOkHY2X/3LBy2bIGNSFx4fZ95HMaXHupuS7cZR15AsvtmCIF4UEyg==

bfile@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/bfile/-/bfile-0.2.2.tgz#b0c205cee1ff22a9525304ec51f09195a7afa077"
integrity sha512-X205SsJ7zFAnjeJ/pBLqDqF10x/4Su3pBy8UdVKw4hdGJk7t5pLoRi+uG4rPaDAClGbrEfT/06PGUbYiMYKzTg==

bheep@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/bheep/-/bheep-0.1.5.tgz#ed6a3da7857c8ebe71d71de9571ddd8f42340889"
integrity sha512-0KR5Zi8hgJBKL35+aYzndCTtgSGakOMxrYw2uszd5UmXTIfx3+drPGoETlVbQ6arTdAzSoQYA1j35vbaWpQXBg==
dependencies:
bsert "~0.0.10"

big-integer@1.6.36:
version "1.6.36"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.36.tgz#78631076265d4ae3555c04f85e7d9d2f3a071a36"
Expand Down Expand Up @@ -2644,6 +2664,14 @@ bindings@^1.2.1, bindings@^1.5.0:
dependencies:
file-uri-to-path "1.0.0"

binet@~0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/binet/-/binet-0.3.6.tgz#82d9462fa601759956a1f1f1f0f10a5760445f85"
integrity sha512-6pm+Gc3uNiiJZEv0k8JDWqQlo9ki/o9UNAkLmr0EGm7hI5MboOJVIOlO1nw3YuDkLHWN78OPsaC4JhRkn2jMLw==
dependencies:
bs32 "~0.1.5"
bsert "~0.0.10"

bip39@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.5.0.tgz#51cbd5179460504a63ea3c000db3f787ca051235"
Expand Down Expand Up @@ -2695,6 +2723,23 @@ bn.js@^4.11.9:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==

bns@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/bns/-/bns-0.14.0.tgz#538d0d91ec8272c32c774b82827699f2db168173"
integrity sha512-lqxDpj9gX7OtihwAzMhlMk0w38ObZu+aRSF9fzG/wUfF6RfocFSFDGHA+KVbLNXudiTStzhWVGc8cJmcL4IHYw==
dependencies:
bcrypto "~5.4.0"
bfile "~0.2.2"
bheep "~0.1.5"
binet "~0.3.6"
bs32 "~0.1.6"
bsert "~0.0.10"
btcp "~0.1.5"
budp "~0.1.6"
bufio "~1.0.7"
optionalDependencies:
unbound "~0.4.3"

body-parser@1.19.0, body-parser@^1.16.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
Expand Down Expand Up @@ -2838,6 +2883,13 @@ browserslist@^4.6.0, browserslist@^4.7.2:
electron-to-chromium "^1.3.295"
node-releases "^1.1.38"

bs32@~0.1.5, bs32@~0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/bs32/-/bs32-0.1.6.tgz#2710cb70da3f55447138181fa645e2c54b1ef6d0"
integrity sha512-usjDesQqZ8ihHXOnOEQuAdymBHnJEfSd+aELFSg1jN/V3iAf12HrylHlRJwIt6DTMmXpBDQ+YBg3Q3DIYdhRgQ==
dependencies:
bsert "~0.0.10"

bs58@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d"
Expand Down Expand Up @@ -2873,6 +2925,21 @@ bser@^2.0.0:
dependencies:
node-int64 "^0.4.0"

bsert@~0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/bsert/-/bsert-0.0.10.tgz#231ac82873a1418c6ade301ab5cd9ae385895597"
integrity sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q==

btcp@~0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/btcp/-/btcp-0.1.5.tgz#f76262415a0f6eaa592cdbb91c8b18386530ac28"
integrity sha512-tkrtMDxeJorn5p0KxaLXELneT8AbfZMpOFeoKYZ5qCCMMSluNuwut7pGccLC5YOJqmuk0DR774vNVQLC9sNq/A==

budp@~0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/budp/-/budp-0.1.6.tgz#bbe166cc4842cf8d96754ee29afb1af56f6757c8"
integrity sha512-o+a8NPq3DhV91j4nInjht2md6mbU1XL+7ciPltP66rw5uD3KP1m5r8lA94LZVaPKcFdJ0l2HVVzRNxnY26Pefg==

buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
Expand Down Expand Up @@ -2947,6 +3014,11 @@ bufferutil@^4.0.1:
dependencies:
node-gyp-build "^4.2.0"

bufio@^1.0.7, bufio@~1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.0.7.tgz#b7f63a1369a0829ed64cc14edf0573b3e382a33e"
integrity sha512-bd1dDQhiC+bEbEfg56IdBv7faWa6OipMs/AFFFvtFnB3wAYjlwQpQRZ0pm6ZkgtfL0pILRXhKxOiQj6UzoMR7A==

bytes@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
Expand Down Expand Up @@ -7313,6 +7385,11 @@ load-json-file@^4.0.0:
pify "^3.0.0"
strip-bom "^3.0.0"

loady@~0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/loady/-/loady-0.0.5.tgz#b17adb52d2fb7e743f107b0928ba0b591da5d881"
integrity sha512-uxKD2HIj042/HBx77NBcmEPsD+hxCgAtjEWlYNScuUjIsh/62Uyu39GOR68TBR68v+jqDL9zfftCWoUo4y03sQ==

locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
Expand Down Expand Up @@ -10415,6 +10492,13 @@ ultron@~1.1.0:
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==

unbound@~0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/unbound/-/unbound-0.4.3.tgz#ca4e9a3c8b678df431ec576385acc8bff9aa439a"
integrity sha512-2ISqZLXtzp1l9f1V8Yr6S+zuhXxEwE1CjKHjXULFDHJcfhc9Gm3mn19hdPp4rlNGEdCivKYGKjYe3WRGnafYdA==
dependencies:
loady "~0.0.5"

unbzip2-stream@^1.0.9:
version "1.3.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a"
Expand Down