From 34e5bbff21b486bcaf17ed1f3b79a585c05f3e4e Mon Sep 17 00:00:00 2001 From: Martin Heidegger Date: Thu, 15 Apr 2021 01:26:08 +0900 Subject: [PATCH] Adding a new "hyper" protocol --- README.md | 3 +- docs/protocol.md | 8 ++++ protocols.js | 26 +++++++++++ test/integration.test.js | 5 ++- test/protocols.test.js | 94 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 99244c2..4cc3184 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # hyper-dns Advanced resolving of decentralized web links using different name systems such as DNS Txt entries and `.well-known` https lookups locations. -It implements various naming systems such as [dat][] or [cabal][] but is extensible to support other systems as well. +It implements various naming systems such as [dat][], [hyper][] and [cabal][] but is extensible to support other systems as well. +[hyper]: https://hypercore-protocol.org/ [dat]: https://www.datprotocol.com/deps/0005-dns/ [cabal]: https://cabal.chat/ [ara]: https://ara.one/ diff --git a/docs/protocol.md b/docs/protocol.md index ad619ea..40a975e 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -120,6 +120,14 @@ const { cabal } = require('hyper-dns').protocols The [cabal chat](https://cabal.chat/) protocol works the same way as `dat` does but has a different lookups for DNS entries (cabalkey=) and uses the `/.well-known/cabal` lookup. +### hyper + +```javascript +const { hyper } = require('hyper-dns').protocols +``` + +The second version of the `dat` protocol that should be outphasing the first version over long time. + ### See a missing protocol? If you have an implementation that should really find its way into `hyper-dns`: feel free to open a Pull Request and suggest it as default for a protocol! diff --git a/protocols.js b/protocols.js index 3c6a23e..97c003e 100644 --- a/protocols.js +++ b/protocols.js @@ -10,6 +10,32 @@ module.exports = Object.freeze({ } return await context.fetchWellKnown(name, 'dat', /^\s*(?:(?:dat):)?(?:\/\/)?(?[0-9a-f]{64})\s*$/i, 6) }, + async hyper (context, name) { + let record = context.matchRegex(name, /^(?[0-9a-f]{64})$/i) + if (record !== undefined) { + return record + } + if (!context.isLocal(name)) { + const domain = `hyper-dns.${name}` + record = await context.getDNSTxtRecord(domain, /^\s*"?(?:hyperkey)=(?(?:[0-9a-f]{64}|well-known))"?\s*$/i) + if (record === undefined) { + return + } + if (record.key !== 'well-known') { + return record + } + } + const wk = await context.fetchWellKnown(name, 'hyper', /^\s*(?:(?:hyper):)?(?:\/\/)?(?[0-9a-f]{64})\s*$/i, 6) + if (wk === undefined) { + return + } + if (typeof wk.ttl !== 'number') { + wk.ttl = record.ttl + } else if (typeof record.ttl === 'number') { + wk.ttl = Math.min(wk.ttl, record.ttl) + } + return wk + }, async cabal (context, name) { let record = context.matchRegex(name, /^(?[0-9a-f]{64})$/i) if (record !== undefined) { diff --git a/test/integration.test.js b/test/integration.test.js index b745cc3..ffb5e99 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -19,9 +19,10 @@ test(`Successful test against ${ecosystem}`, async t => { t.deepEquals( results, { - dat: key, + ara: null, cabal: null, - ara: null + dat: key, + hyper: null } ) }) diff --git a/test/protocols.test.js b/test/protocols.test.js index 94209eb..f171e6b 100644 --- a/test/protocols.test.js +++ b/test/protocols.test.js @@ -48,6 +48,100 @@ const { matchRegex } = require('../resolve-context.js') }) })() +;(() => { + const { hyper } = protocols + const key = '100c77d788fdaf07b89b28e9d276e47f2e44011f4adb981921056e1b3b40e99e' + test('hyper: local urls', async t => { + t.deepEquals( + await hyper({ matchRegex }, key), + { key, ttl: null } + ) + }) + test('hyper: looking for dns records', async t => { + const name = 'dat-ecosystem.org' + t.plan(4) + t.deepEquals( + await hyper({ + matchRegex, + isLocal: (name) => { + t.equals(name, 'dat-ecosystem.org') + return false + }, + async getDNSTxtRecord (domain, regex) { + t.equals(domain, `hyper-dns.${name}`) + t.match(`hyperkey=${key}`, regex) + return { key, ttl: 10 } + } + }, name), + { key, ttl: 10 } + ) + }) + test('hyper: allowing for miss of dns records', async t => { + const name = 'dat-ecosystem.org' + t.deepEquals( + await hyper({ + matchRegex, + isLocal: () => false, + async getDNSTxtRecord () {} + }, name), + undefined + ) + }) + test('hyper: looking for well-known record', async t => { + const name = 'dat-ecosystem.org' + t.deepEquals( + await hyper({ + matchRegex, + isLocal: () => false, + async getDNSTxtRecord (_domain, regex) { + t.match('hyperkey=well-known', regex) + return { key: 'well-known', ttl: 2 } + }, + async fetchWellKnown (domain, schema, regex, redirects) { + t.equals(redirects, 6) + t.equals(domain, name) + t.equals(schema, 'hyper') + t.match(key, regex) + t.match(`hyper:${key}`, regex) + t.match(`hyper://${key}`, regex) + return { key, ttl: 10 } + } + }, name), + { key, ttl: 2 } + ) + }) + test('hyper: looking for well-known may miss', async t => { + const name = 'dat-ecosystem.org' + t.deepEquals( + await hyper({ + matchRegex, + isLocal: () => false, + async getDNSTxtRecord () { + return { key: 'well-known', ttl: 2 } + }, + async fetchWellKnown () {} + }, name), + undefined + ) + }) + test('hyper: looking for well-known uses ttl of dns record if missing', async t => { + const name = 'dat-ecosystem.org' + t.deepEquals( + await hyper({ + matchRegex, + isLocal: () => false, + async getDNSTxtRecord () { + return { key: 'well-known', ttl: 2 } + }, + async fetchWellKnown () { + return { key, ttl: null } + } + }, name), + { key, ttl: 2 } + ) + }) +})() + ;(() => { const { cabal } = protocols const key = '100c77d788fdaf07b89b28e9d276e47f2e44011f4adb981921056e1b3b40e99e'