100 lines
3.3 KiB
Nix
100 lines
3.3 KiB
Nix
|
|
{ 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
|
||
|
|
}
|
||
|
|
}
|
||
|
|
'';
|
||
|
|
}
|