add skynet-sponsor-key dnslink functionality
This commit is contained in:
parent
51952c88ed
commit
cfe4ca0d87
|
@ -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)
|
||||||
|
|
|
@ -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 });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Reference in New Issue