From 11186f3fd6bdd44fb124c2af22fd0dda7e22cfd9 Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Tue, 3 Nov 2020 16:18:23 +0100 Subject: [PATCH 1/7] support skydb in hns --- docker/nginx/conf.d/client.conf | 37 +++++++++++++++++++++---- packages/handshake-api/src/index.js | 42 ++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/docker/nginx/conf.d/client.conf b/docker/nginx/conf.d/client.conf index a2448ee2..49c4eae5 100644 --- a/docker/nginx/conf.d/client.conf +++ b/docker/nginx/conf.d/client.conf @@ -151,12 +151,39 @@ server { -- example response: '{"skylink":"sia://XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"}' local hnsres_json = json.decode(hnsres_res.body) - -- try to match the skylink with sia:// prefix - local skylink, skylink_rest = string.match(hnsres_json.skylink, "sia://([^/?]+)(.*)") + if hnsres_json.skylink then + -- try to match the skylink with sia:// prefix + local skylink, skylink_rest = string.match(hnsres_json.skylink, "sia://([^/?]+)(.*)") - -- in case the skylink did not match, assume that there is no sia:// prefix and try to match again - if skylink == nil then - skylink, skylink_rest = string.match(hnsres_json.skylink, "/?([^/?]+)(.*)") + -- in case the skylink did not match, assume that there is no sia:// prefix and try to match again + if skylink == nil then + skylink, skylink_rest = string.match(hnsres_json.skylink, "/?([^/?]+)(.*)") + end + end + + if hnsres_json.registry then + local publickey = hnsres_json.registry.publickey + local datakey = hnsres_json.registry.datakey + + -- make a get request to /skynet/registry endpoint with the credentials from text record + local registry_res = ngx.location.capture("/skynet/registry?publickey=" .. publickey .. "&datakey=" .. datakey) + + ngx.header.content_type = 'text/plain' + ngx.print(registry_res.body) + + -- we want to fail with a generic 404 when /skynet/registry returns anything but 200 OK + if registry_res.status ~= ngx.HTTP_OK then + ngx.exit(ngx.HTTP_NOT_FOUND) + end + + -- since /skynet/registry endpoint response is a json, we need to decode it before we access it + local registry_json = json.decode(registry_res.body) + -- response will contain hex encoded, we need to decode it + local data = (registry_json.data:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) + + skylink = data end ngx.var.skylink = skylink diff --git a/packages/handshake-api/src/index.js b/packages/handshake-api/src/index.js index 8aedab06..cda9ed2f 100644 --- a/packages/handshake-api/src/index.js +++ b/packages/handshake-api/src/index.js @@ -6,7 +6,7 @@ const { NodeClient } = require("hs-client"); const host = process.env.HOSTNAME || "0.0.0.0"; const port = Number(process.env.PORT) || 3100; -const hsdNetworkType = process.env.HSD_NETWORK || "regtest"; +const hsdNetworkType = process.env.HSD_NETWORK || "main"; const hsdHost = process.env.HSD_HOST || "localhost"; const hsdPort = Number(process.env.HSD_PORT) || 12037; const hsdApiKey = process.env.HSD_API_KEY || "foo"; @@ -18,10 +18,11 @@ const clientOptions = { apiKey: hsdApiKey, }; const client = new NodeClient(clientOptions); -const cache = new NodeCache({ stdTTL: 300 }); // cache for 5 minutes +const cache = new NodeCache({ stdTTL: 1 }); // cache for 5 minutes // Match both `sia://HASH` and `HASH` links. const startsWithSkylinkRegExp = /^(sia:\/\/)?[a-zA-Z0-9_-]{46}/; +const registryEntryRegExp = /^skydb:\/\/(?[a-zA-Z0-9%]+)\/(?[a-zA-Z0-9%]+)$/; const getDomainRecords = async (name) => { if (cache.has(name)) return cache.get(name); @@ -36,18 +37,36 @@ const getDomainRecords = async (name) => { return records; }; -const findSkylinkRecord = (records) => { +const findSkynetCompatibleRecord = (records) => { // Find the last one, so people can update their domains in a non-destructive // way by simply adding a new link. This will also allow keeping links to // older versions for backwards compatibility. return records ?.slice() .reverse() - .find(({ txt }) => txt?.some((entry) => isValidSkylink(entry))); + .find(({ txt }) => txt?.some((entry) => isValidSkylink(entry) || isValidRegistryEntry(entry))); }; -const getSkylinkFromRecord = (record) => { - return record?.txt?.find((entry) => isValidSkylink(entry)); +const createResponseFromCompatibleRecord = (record) => { + const skylink = record?.txt?.find((entry) => isValidSkylink(entry)); + + if (skylink) return { skylink }; + + const entry = record?.txt?.find((entry) => isValidRegistryEntry(entry)); + + if (entry) { + const match = entry.match(registryEntryRegExp); + + if (match) + return { + registry: { + publickey: decodeURIComponent(match.groups.publickey), + datakey: decodeURIComponent(match.groups.datakey), + }, + }; + } + + throw new Error(`No skylink in record: ${JSON.stringify(record)}`); }; const resolveDomainHandler = async (req, res) => { @@ -56,11 +75,10 @@ const resolveDomainHandler = async (req, res) => { const records = await getDomainRecords(domain); if (!records) return res.status(404).send(`No records found for ${domain}`); - const record = findSkylinkRecord(records); - if (!record) throw new Error(`No skylink found in dns records of ${domain}`); + const record = findSkynetCompatibleRecord(records); + if (!record) throw new Error(`No skynet compatible records found in dns records of ${domain}`); - const skylink = getSkylinkFromRecord(record); - return res.json({ skylink }); + return res.json(createResponseFromCompatibleRecord(record)); } catch (error) { res.status(500).send(`Handshake error: ${error.message}`); } @@ -74,6 +92,10 @@ function isValidSkylink(link) { return Boolean(link.match(startsWithSkylinkRegExp)); } +function isValidRegistryEntry(value) { + return Boolean(value && value.match(registryEntryRegExp)); +} + const server = express(); server.get("/hnsres/:name", resolveDomainHandler); From 4dc3588f81b4ea0b331f0cb1a02b90ebf7be1b2f Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Tue, 3 Nov 2020 16:24:56 +0100 Subject: [PATCH 2/7] support skydb in hns --- docker/nginx/conf.d/client.conf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docker/nginx/conf.d/client.conf b/docker/nginx/conf.d/client.conf index 49c4eae5..5f3866a6 100644 --- a/docker/nginx/conf.d/client.conf +++ b/docker/nginx/conf.d/client.conf @@ -168,9 +168,6 @@ server { -- make a get request to /skynet/registry endpoint with the credentials from text record local registry_res = ngx.location.capture("/skynet/registry?publickey=" .. publickey .. "&datakey=" .. datakey) - ngx.header.content_type = 'text/plain' - ngx.print(registry_res.body) - -- we want to fail with a generic 404 when /skynet/registry returns anything but 200 OK if registry_res.status ~= ngx.HTTP_OK then ngx.exit(ngx.HTTP_NOT_FOUND) @@ -183,6 +180,10 @@ server { return string.char(tonumber(cc, 16)) end)) + ngx.header.content_type = 'text/plain' + ngx.print(data) + ngx.exit(ngx.HTTP_OK) + skylink = data end From 04ff998beb92514b2dd26066c5ba8c7867e2239a Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Tue, 3 Nov 2020 16:26:33 +0100 Subject: [PATCH 3/7] support skydb in hns --- docker/nginx/conf.d/client.conf | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docker/nginx/conf.d/client.conf b/docker/nginx/conf.d/client.conf index 5f3866a6..d71fee78 100644 --- a/docker/nginx/conf.d/client.conf +++ b/docker/nginx/conf.d/client.conf @@ -180,10 +180,6 @@ server { return string.char(tonumber(cc, 16)) end)) - ngx.header.content_type = 'text/plain' - ngx.print(data) - ngx.exit(ngx.HTTP_OK) - skylink = data end From a19a1ab6023f0f0ad0a63832517d76fd3482230f Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Tue, 3 Nov 2020 16:27:38 +0100 Subject: [PATCH 4/7] support skydb in hns --- packages/handshake-api/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/handshake-api/src/index.js b/packages/handshake-api/src/index.js index cda9ed2f..a50775f0 100644 --- a/packages/handshake-api/src/index.js +++ b/packages/handshake-api/src/index.js @@ -18,7 +18,7 @@ const clientOptions = { apiKey: hsdApiKey, }; const client = new NodeClient(clientOptions); -const cache = new NodeCache({ stdTTL: 1 }); // cache for 5 minutes +const cache = new NodeCache({ stdTTL: 300 }); // cache for 5 minutes // Match both `sia://HASH` and `HASH` links. const startsWithSkylinkRegExp = /^(sia:\/\/)?[a-zA-Z0-9_-]{46}/; From 84e54f33115457d600714af269a79a162005cf5f Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Tue, 3 Nov 2020 16:30:34 +0100 Subject: [PATCH 5/7] support skydb in hns --- packages/handshake-api/src/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/handshake-api/src/index.js b/packages/handshake-api/src/index.js index a50775f0..ac6de6ec 100644 --- a/packages/handshake-api/src/index.js +++ b/packages/handshake-api/src/index.js @@ -85,13 +85,11 @@ const resolveDomainHandler = async (req, res) => { }; // Checks if the given string is a valid Sia link. -function isValidSkylink(link) { - if (!link || link.length === 0) { - return false; - } - return Boolean(link.match(startsWithSkylinkRegExp)); +function isValidSkylink(value) { + return Boolean(value && value.match(startsWithSkylinkRegExp)); } +// Checks if given string is a valid skynet registry entry function isValidRegistryEntry(value) { return Boolean(value && value.match(registryEntryRegExp)); } From 9b09f9ba5cb2e0ed9332cd642ec69683e4e20830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20Wypch=C5=82o?= Date: Wed, 4 Nov 2020 11:54:38 +0100 Subject: [PATCH 6/7] Update docker/nginx/conf.d/client.conf comment copy --- docker/nginx/conf.d/client.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/nginx/conf.d/client.conf b/docker/nginx/conf.d/client.conf index d71fee78..f2a35c8b 100644 --- a/docker/nginx/conf.d/client.conf +++ b/docker/nginx/conf.d/client.conf @@ -175,7 +175,7 @@ server { -- since /skynet/registry endpoint response is a json, we need to decode it before we access it local registry_json = json.decode(registry_res.body) - -- response will contain hex encoded, we need to decode it + -- response will contain a hex encoded skylink, we need to decode it local data = (registry_json.data:gsub('..', function (cc) return string.char(tonumber(cc, 16)) end)) From 48b1f0d0673c927dd873af07191697dd6a6a39e4 Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Wed, 4 Nov 2020 12:04:24 +0100 Subject: [PATCH 7/7] tighten if-else and add empty skylink protection --- docker/nginx/conf.d/client.conf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docker/nginx/conf.d/client.conf b/docker/nginx/conf.d/client.conf index f2a35c8b..7ea0c288 100644 --- a/docker/nginx/conf.d/client.conf +++ b/docker/nginx/conf.d/client.conf @@ -159,9 +159,7 @@ server { if skylink == nil then skylink, skylink_rest = string.match(hnsres_json.skylink, "/?([^/?]+)(.*)") end - end - - if hnsres_json.registry then + elseif hnsres_json.registry then local publickey = hnsres_json.registry.publickey local datakey = hnsres_json.registry.datakey @@ -183,6 +181,11 @@ server { skylink = data end + -- fail with a generic 404 if skylink has not been extracted from a valid /hnsres response for some reason + if not skylink then + ngx.exit(ngx.HTTP_NOT_FOUND) + end + ngx.var.skylink = skylink if request_uri_rest == "/" and skylink_rest ~= "" and skylink_rest ~= "/" then ngx.var.rest = skylink_rest