From a3ae67a2c429f908ea08079306456178b504f9ea Mon Sep 17 00:00:00 2001 From: Yonle Date: Sun, 28 Apr 2024 21:20:25 +0700 Subject: [PATCH] bouncer: improve NIP-42 compatibilities Signed-off-by: Yonle --- auth.js | 9 +++++---- bouncer.js | 13 +++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/auth.js b/auth.js index ad8dcd0..ae5b34d 100644 --- a/auth.js +++ b/auth.js @@ -3,12 +3,13 @@ const { validateEvent, verifyEvent } = require("nostr-tools"); const { authorized_keys, private_keys } = require(process.env.BOSTR_CONFIG_PATH || "./config"); module.exports = (authKey, data, ws, req) => { + if (!(authorized_keys?.length || Object.keys(private_keys).length)) return; // do nothing if (!validateEvent(data) || !verifyEvent(data)) { ws.send(JSON.stringify(["NOTICE", "error: invalid challenge response."])); return false; } - if ((authorized_keys?.length || Object.keys(private_keys).length) && !authorized_keys?.includes(data.pubkey) && !(private_keys && private_keys[data.pubkey])) { + if (!authorized_keys?.includes(data.pubkey) && !private_keys[data.pubkey]) { ws.send(JSON.stringify(["OK", data.id, false, "unauthorized."])); return false; } @@ -18,14 +19,14 @@ module.exports = (authKey, data, ws, req) => { return false; } - const tags = new Map(data.tags); + const tags = Object.fromEntries(data.tags); - if (!tags.get("relay").includes(req.headers.host)) { + if (!tags.relay?.includes(req.headers.host)) { ws.send(JSON.stringify(["OK", data.id, false, "unmatched relay url."])); return false; }; - if (tags.get("challenge") !== authKey) { + if (tags.challenge !== authKey) { ws.send(JSON.stringify(["OK", data.id, false, "unmatched challenge string."])); return false; } diff --git a/bouncer.js b/bouncer.js index d4dcaf1..85ee049 100644 --- a/bouncer.js +++ b/bouncer.js @@ -202,10 +202,18 @@ function handleConnection(ws, req, onClose) { ws.send(JSON.stringify(["CLOSED", origID, ""])); break; case "AUTH": - if (authorized) return; if (auth(authKey, data[1], ws, req)) { + authKey = Date.now() + Math.random().toString(36); ws.pubkey = data[1].pubkey; console.log(process.pid, "---", ws.ip, "successfully authorized as", ws.pubkey, private_keys[ws.pubkey] ? "(admin)" : "(user)"); + if (private_keys[ws.pubkey]) { + for (const relay of userRelays.get(ws.id)) { + for (const challenge of relay.pendingNIP42) { + nip42(relay, client.pubkey, private_keys[ws.pubkey], challenge); + relay.pendingNIP42.delete(challenge); + } + } + } if (authorized) return; authorized = true; lastEvent = Date.now(); @@ -323,6 +331,7 @@ function newConn(addr, id, reconn_t = 0) { relay.isCache = relay_type(addr) === "cache_relay"; relay.isLoadBalancer = relay_type(addr) === "loadbalancer"; relay.ratelimit = 0; + relay.pendingNIP42 = new Set(); relay.on('open', _ => { if (!csess.has(id)) return relay.terminate(); const client = csess.get(id); @@ -414,7 +423,7 @@ function newConn(addr, id, reconn_t = 0) { } break; case "AUTH": - if (!private_keys || typeof(data[1]) !== "string" || !client.pubkey) return; + if (!private_keys || typeof(data[1]) !== "string" || !client.pubkey) return relay.pendingNIP42.add(data[1]); nip42(relay, client.pubkey, private_keys[client.pubkey], data[1]); break;