enable nip42 function for public bouncer.

Signed-off-by: Yonle <yonle@lecturify.net>
This commit is contained in:
Yonle
2023-11-20 21:21:22 +07:00
parent 8a189bcd2e
commit b8c720aa8a
3 changed files with 25 additions and 15 deletions

12
auth.js
View File

@@ -1,6 +1,7 @@
const { validateEvent, verifySignature } = require("nostr-tools"); const { validateEvent, verifySignature } = require("nostr-tools");
const { authorized_keys, private_keys } = require("./config");
module.exports = (authKey, authorized, authorized_keys, data, ws, req) => { module.exports = (authKey, data, ws, req) => {
if (!validateEvent(data)) { if (!validateEvent(data)) {
ws.send(JSON.stringify(["NOTICE", "error: invalid challenge response."])); ws.send(JSON.stringify(["NOTICE", "error: invalid challenge response."]));
return false; return false;
@@ -11,7 +12,7 @@ module.exports = (authKey, authorized, authorized_keys, data, ws, req) => {
return false; return false;
} }
if (!authorized_keys.includes(data.pubkey)) { if (!authorized_keys?.includes(data.pubkey) && !(private_keys && private_keys[data.pubkey])) {
ws.send(JSON.stringify(["OK", data.id, false, "unauthorized."])); ws.send(JSON.stringify(["OK", data.id, false, "unauthorized."]));
return false; return false;
} }
@@ -21,11 +22,6 @@ module.exports = (authKey, authorized, authorized_keys, data, ws, req) => {
return false; return false;
} }
if (authorized) {
ws.send(JSON.stringify(["OK", data.id, false, "already authorized."]));
return false;
}
const tags = new Map(data.tags); const tags = new Map(data.tags);
if (!tags.get("relay").includes(req.headers.host)) { if (!tags.get("relay").includes(req.headers.host)) {
ws.send(JSON.stringify(["OK", data.id, false, "unmatched relay url."])); ws.send(JSON.stringify(["OK", data.id, false, "unmatched relay url."]));
@@ -37,6 +33,6 @@ module.exports = (authKey, authorized, authorized_keys, data, ws, req) => {
return false; return false;
} }
ws.send(JSON.stringify(["OK", data.id, true, `Welcome ${data.pubkey}`])); ws.send(JSON.stringify(["OK", data.id, true, `Hello ${data.pubkey}`]));
return true; return true;
} }

View File

@@ -26,6 +26,15 @@ module.exports = (ws, req) => {
authKey = Date.now() + Math.random().toString(36); authKey = Date.now() + Math.random().toString(36);
authorized = false; authorized = false;
ws.send(JSON.stringify(["AUTH", authKey])); ws.send(JSON.stringify(["AUTH", authKey]));
} else if (private_keys !== {}) {
// If there is no whitelist, Then we ask to client what is their public key.
// We will enable NIP-42 function for this session if user pubkey was available & valid in <private_keys>.
// There is no need to limit this session. We only ask who is this user.
// If it was the users listed at <private_keys> in config.js, Then the user could use NIP-42 protected relays.
authKey = Date.now() + Math.random().toString(36);
ws.send(JSON.stringify(["AUTH", authKey]));
} }
console.log(process.pid, `->- ${req.headers["x-forwarded-for"]?.split(",")[0] || req.socket.address()?.address} connected as ${ws.id}`); console.log(process.pid, `->- ${req.headers["x-forwarded-for"]?.split(",")[0] || req.socket.address()?.address} connected as ${ws.id}`);
@@ -69,10 +78,12 @@ module.exports = (ws, req) => {
bc(data, ws.id); bc(data, ws.id);
break; break;
case "AUTH": case "AUTH":
if (auth(authKey, authorized, authorized_keys, data[1], ws, req)) { if (auth(authKey, data[1], ws, req)) {
ws.pubkey = data[1].pubkey; ws.pubkey = data[1].pubkey;
authorized = true; console.log(process.pid, "---", ws.id, "succesfully authorized as", ws.pubkey, private_keys[ws.pubkey] ? "(admin)" : "(user)");
if (authorized) return;
relays.forEach(_ => newConn(_, ws.id)); relays.forEach(_ => newConn(_, ws.id));
authorized = true;
} }
break; break;
default: default:

View File

@@ -16,7 +16,7 @@ module.exports = {
// Time before reconnect to relays in miliseconds. // Time before reconnect to relays in miliseconds.
reconnect_time: 5000, reconnect_time: 5000,
// For personal usage. This is a whitelist of users public keys that could use this bouncer. // A whitelist of users public keys who could use this bouncer.
// Leaving this empty will allows everyone to use this bouncer. // Leaving this empty will allows everyone to use this bouncer.
// NOTE: - Require NIP-42 compatible nostr client // NOTE: - Require NIP-42 compatible nostr client
authorized_keys: [ authorized_keys: [
@@ -25,10 +25,13 @@ module.exports = {
// .... // ....
], ],
// For personal usage. Used for authenticating NIP-42 relays to access certain events (such as kind 4, etc). // Used for accessing NIP-42 protected events from certain relays.
// It could be your key. Leaving this empty completely disables NIP-42 function. // It could be your key. Leaving this empty completely disables NIP-42 function.
// NOTE: - NIP-42 (auth) is ONLY supported with provided <private_keys> //
// - To use one of the following privatekeys, NIP-42 compatible nostr client is required. // You could use this function even as a public bouncer.
// There are no security risk as it utilize NIP-42 to recognize client public key.
//
// NOTE: - Require NIP-42 compatible nostr client
private_keys: { private_keys: {
// "pubkey-in-hex": "privatekey", // "pubkey-in-hex": "privatekey",
// "pubkey-in-hex": "nsec ...." // "pubkey-in-hex": "nsec ...."
@@ -49,7 +52,7 @@ module.exports = {
// Some nostr client may read the following for compatibility check. // Some nostr client may read the following for compatibility check.
// You may change the supported_nips to match with what your relays supported. // You may change the supported_nips to match with what your relays supported.
"supported_nips": [1,2,9,11,12,15,16,20,22,33,40,42,50], "supported_nips": [1,2,9,11,12,15,16,20,22,33,40,42,50],
"version": "1.0.0" "version": require("./package.json").version
}, },
// Nostr relays to bounce [Required] // Nostr relays to bounce [Required]