Add NIP-05 identifier server for otherwhere.app
Dynamic lookup from nostr-rs-relay SQLite DB; runs as nostr-rs-relay user. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
288ce840ad
commit
d4b9b209c7
2 changed files with 100 additions and 0 deletions
|
|
@ -56,6 +56,7 @@
|
||||||
./modules/services/static-sites
|
./modules/services/static-sites
|
||||||
./modules/services/webhook-deploy.nix
|
./modules/services/webhook-deploy.nix
|
||||||
./modules/services/jirorian.nix
|
./modules/services/jirorian.nix
|
||||||
|
./modules/services/nip05.nix
|
||||||
./modules/users/tobias.nix
|
./modules/users/tobias.nix
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
99
modules/services/nip05.nix
Normal file
99
modules/services/nip05.nix
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
domains = [ "otherwhere.app" "www.otherwhere.app" ];
|
||||||
|
port = 8892;
|
||||||
|
relayUrl = "wss://relay.otherwhere.app/";
|
||||||
|
dbPath = "/var/lib/nostr-rs-relay/nostr.db";
|
||||||
|
|
||||||
|
script = pkgs.writeText "nip05-server.py" ''
|
||||||
|
import json, sqlite3
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
from urllib.parse import urlparse, parse_qs
|
||||||
|
|
||||||
|
DB_PATH = "${dbPath}"
|
||||||
|
RELAY_URL = "${relayUrl}"
|
||||||
|
PORT = ${toString port}
|
||||||
|
|
||||||
|
class NIP05Handler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
parsed = urlparse(self.path)
|
||||||
|
if parsed.path != "/.well-known/nostr.json":
|
||||||
|
self.send_response(404)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
params = parse_qs(parsed.query)
|
||||||
|
name_filter = params.get("name", [None])[0]
|
||||||
|
if name_filter:
|
||||||
|
name_filter = name_filter.strip().lower()
|
||||||
|
|
||||||
|
try:
|
||||||
|
con = sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True)
|
||||||
|
rows = con.execute("""
|
||||||
|
SELECT pub_key, content FROM event
|
||||||
|
WHERE kind = 0 AND (hidden IS NULL OR hidden = 0)
|
||||||
|
GROUP BY pub_key
|
||||||
|
HAVING created_at = MAX(created_at)
|
||||||
|
""").fetchall()
|
||||||
|
con.close()
|
||||||
|
except Exception:
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
|
names = {}
|
||||||
|
relays = {}
|
||||||
|
for pub_key, content in rows:
|
||||||
|
try:
|
||||||
|
meta = json.loads(content)
|
||||||
|
name = meta.get("name", "").strip().lower()
|
||||||
|
if not name:
|
||||||
|
continue
|
||||||
|
if name_filter and name != name_filter:
|
||||||
|
continue
|
||||||
|
names[name] = pub_key
|
||||||
|
relays[pub_key] = [RELAY_URL]
|
||||||
|
except (json.JSONDecodeError, AttributeError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
body = json.dumps({"names": names, "relays": relays}).encode()
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/json")
|
||||||
|
self.send_header("Access-Control-Allow-Origin", "*")
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def log_message(self, fmt, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
HTTPServer(("127.0.0.1", PORT), NIP05Handler).serve_forever()
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.nip05 = {
|
||||||
|
description = "NIP-05 identifier server";
|
||||||
|
after = [ "network.target" "nostr-rs-relay.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "nostr-rs-relay";
|
||||||
|
Group = "nostr-rs-relay";
|
||||||
|
ExecStart = "${pkgs.python3}/bin/python3 ${script}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc."caddy/Caddyfile.d/nip05.caddyfile".text = ''
|
||||||
|
${lib.concatStringsSep ", " domains} {
|
||||||
|
handle /.well-known/nostr.json {
|
||||||
|
reverse_proxy localhost:${toString port}
|
||||||
|
}
|
||||||
|
handle {
|
||||||
|
header Content-Type "text/html; charset=utf-8"
|
||||||
|
respond `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>otherwhere.app</title></head><body><p>otherwhere.app</p></body></html>` 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue