Merge pull request #1975 from SkynetLabs/dnslink-sponsor

add skynet-sponsor-key functionality
This commit is contained in:
Karol Wypchło 2022-04-12 13:02:22 +02:00 committed by GitHub
commit 9b4f39e1c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 8 deletions

View File

@ -5,6 +5,7 @@ location / {
set $path $uri; set $path $uri;
rewrite_by_lua_block { rewrite_by_lua_block {
local cjson = require("cjson")
local cache = ngx.shared.dnslink local cache = ngx.shared.dnslink
local cache_value = cache:get(ngx.var.host) local cache_value = cache:get(ngx.var.host)
@ -28,13 +29,23 @@ location / {
ngx.exit(ngx.status) ngx.exit(ngx.status)
end end
else else
ngx.var.skylink = res.body local resolved = cjson.decode(res.body)
ngx.var.skylink = resolved.skylink
if resolved.sponsor then
ngx.req.set_header("Skynet-Api-Key", resolved.sponsor)
end
local cache_ttl = 300 -- 5 minutes cache expire time local cache_ttl = 300 -- 5 minutes cache expire time
cache:set(ngx.var.host, ngx.var.skylink, cache_ttl) cache:set(ngx.var.host, res.body, cache_ttl)
end end
else else
ngx.var.skylink = cache_value local resolved = cjson.decode(cache_value)
ngx.var.skylink = resolved.skylink
if resolved.sponsor then
ngx.req.set_header("Skynet-Api-Key", resolved.sponsor)
end
end end
ngx.var.skylink = require("skynet.skylink").parse(ngx.var.skylink) ngx.var.skylink = require("skynet.skylink").parse(ngx.var.skylink)

View File

@ -8,12 +8,14 @@ const port = Number(process.env.DNSLINK_API_PORT) || 3100;
const server = express(); const server = express();
const dnslinkNamespace = "skynet-ns"; const dnslinkNamespace = "skynet-ns";
const sponsorNamespace = "skynet-sponsor-key";
const dnslinkRegExp = new RegExp(`^dnslink=/${dnslinkNamespace}/.+$`); const dnslinkRegExp = new RegExp(`^dnslink=/${dnslinkNamespace}/.+$`);
const sponsorRegExp = new RegExp(`^${sponsorNamespace}=[a-zA-Z0-9]+$`);
const dnslinkSkylinkRegExp = new RegExp(`^dnslink=/${dnslinkNamespace}/([a-zA-Z0-9_-]{46}|[a-z0-9]{55})`); const dnslinkSkylinkRegExp = new RegExp(`^dnslink=/${dnslinkNamespace}/([a-zA-Z0-9_-]{46}|[a-z0-9]{55})`);
const hint = `valid example: dnslink=/${dnslinkNamespace}/3ACpC9Umme41zlWUgMQh1fw0sNwgWwyfDDhRQ9Sppz9hjQ`; const hint = `valid example: dnslink=/${dnslinkNamespace}/3ACpC9Umme41zlWUgMQh1fw0sNwgWwyfDDhRQ9Sppz9hjQ`;
server.get("/dnslink/:name", async (req, res) => { server.get("/dnslink/:name", async (req, res) => {
const success = (skylink) => res.send(skylink); const success = (response) => res.json(response);
const failure = (message) => res.status(400).send(message); const failure = (message) => res.status(400).send(message);
if (!isValidDomain(req.params.name)) { if (!isValidDomain(req.params.name)) {
@ -22,7 +24,7 @@ server.get("/dnslink/:name", async (req, res) => {
const lookup = `_dnslink.${req.params.name}`; const lookup = `_dnslink.${req.params.name}`;
dns.resolveTxt(lookup, (error, records) => { dns.resolveTxt(lookup, (error, addresses) => {
if (error) { if (error) {
if (error.code === "ENOTFOUND") { if (error.code === "ENOTFOUND") {
return failure(`ENOTFOUND: ${lookup} TXT record doesn't exist`); return failure(`ENOTFOUND: ${lookup} TXT record doesn't exist`);
@ -35,11 +37,12 @@ server.get("/dnslink/:name", async (req, res) => {
return failure(`Failed to fetch ${lookup} TXT record: ${error.message}`); return failure(`Failed to fetch ${lookup} TXT record: ${error.message}`);
} }
if (records.length === 0) { if (addresses.length === 0) {
return failure(`No TXT record found for ${lookup}`); return failure(`No TXT record found for ${lookup}`);
} }
const dnslinks = records.flat().filter((record) => dnslinkRegExp.test(record)); const records = addresses.flat();
const dnslinks = records.filter((record) => dnslinkRegExp.test(record));
if (dnslinks.length === 0) { if (dnslinks.length === 0) {
return failure(`TXT records for ${lookup} found but none of them contained valid skynet dnslink - ${hint}`); return failure(`TXT records for ${lookup} found but none of them contained valid skynet dnslink - ${hint}`);
@ -58,9 +61,25 @@ server.get("/dnslink/:name", async (req, res) => {
const skylink = matchSkylink[1]; const skylink = matchSkylink[1];
// check if _dnslink records contain skynet-sponsor-key entries
const sponsors = records.filter((record) => sponsorRegExp.test(record));
if (sponsors.length > 1) {
return failure(`Multiple TXT records with valid sponsor key found for ${lookup}, only one allowed`);
}
if (sponsors.length === 1) {
// extract just the key part from the record
const sponsor = sponsors[0].substring(sponsors[0].indexOf("=") + 1);
console.log(`${req.params.name} => ${skylink} | sponsor: ${sponsor}`);
return success({ skylink, sponsor });
}
console.log(`${req.params.name} => ${skylink}`); console.log(`${req.params.name} => ${skylink}`);
return success(skylink); return success({ skylink });
}); });
}); });