Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing authorized_keys function for non-NIP-42 supported clients #8

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add write policy without requiring NIP-42, add verifying signature on…
… post and add gitignore
  • Loading branch information
ftkro committed Dec 30, 2023
commit 748967d25adaaed4964083a67e14b43f534d2f3c
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/config.js
.idea/**
node_modules/**
package-lock.json
.yarn/**
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
[Dd]esktop.ini
[._]*.sw[a-p]
[._]sw[a-p]
.DS_Store
.AppleDouble
.LSOverride
._*
15 changes: 10 additions & 5 deletions bouncer.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const WebSocket = require("ws");
const { validateEvent, nip19 } = require("nostr-tools");
const { verifySignature, validateEvent, nip19 } = require("nostr-tools");
const auth = require("./auth.js");
const nip42 = require("./nip42.js");

let { relays, tmp_store, log_about_relays, authorized_keys, private_keys, reconnect_time, wait_eose, pause_on_limit, eose_timeout, max_eose_score, cache_relays } = require("./config");
let { relays, log_about_relays, authorized_keys, writable_keys, private_keys, reconnect_time, wait_eose, pause_on_limit, eose_timeout, max_eose_score, cache_relays } = require("./config");

const socks = new Set();
const csess = new Map();

authorized_keys = authorized_keys?.map(i => i.startsWith("npub") ? nip19.decode(i).data : i);
writable_keys = writable_keys?.map(i => i.startsWith("npub") ? nip19.decode(i).data : i);

// CL MaxEoseScore: Set <max_eose_score> as 0 if configured relays is under of the expected number from <max_eose_score>
if (relays.length < max_eose_score) max_eose_score = 0;
Expand All @@ -18,6 +19,7 @@ cache_relays = cache_relays?.map(i => i.endsWith("/") ? i : i + "/");
// CL - User socket
module.exports = (ws, req) => {
let authKey = null;
let isPersonalRelay = false;
let authorized = true;

ws.id = process.pid + Math.floor(Math.random() * 1000) + "_" + csess.size;
Expand All @@ -30,11 +32,12 @@ module.exports = (ws, req) => {
ws.reconnectTimeout = new Set(); // relays timeout() before reconnection. Only use after client disconnected.

if (authorized_keys?.length) {
isPersonalRelay = true;
authKey = Date.now() + Math.random().toString(36);
authorized = false;
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.
// If there is no whitelist, Then we ask 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.
Expand All @@ -50,15 +53,17 @@ module.exports = (ws, req) => {
data = JSON.parse(data);
} catch {
return ws.send(
JSON.stringify(["NOTICE", "error: bad JSON."])
JSON.stringify(["NOTICE", "error: bad JSON."])
)
}

switch (data[0]) {
case "EVENT":
if (!authorized) return;
if (!validateEvent(data[1])) return ws.send(JSON.stringify(["NOTICE", "error: invalid event"]));
if (data[1].kind == 22242) return ws.send(JSON.stringify(["OK", data[1]?.id, false, "rejected: kind 22242"]));
if (!verifySignature(data[1])) return ws.send(JSON.stringify(["NOTICE", "error: invalid signature"]));
if (data[1].kind === 22242) return ws.send(JSON.stringify(["OK", data[1]?.id, false, "rejected: kind 22242"]));
if (!isPersonalRelay && writable_keys.length !== 0 && !writable_keys.includes(data[1]?.pubkey)) return ws.send(JSON.stringify(["OK", data[1]?.id, false, "blocked: user must be added to the allowlist"]));
ws.my_events.add(data[1]);
direct_bc(data, ws.id);
cache_bc(data, ws.id);
Expand Down
13 changes: 12 additions & 1 deletion config.js.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
// 0 will make bostr run clusters with available parallelism / CPU cores.
clusters: 0,

// Log about bouncer connection with relays?
// Log about bouncer connection with relays?
log_about_relays: false,

// Time before reconnect to relays in milliseconds.
Expand Down Expand Up @@ -42,13 +42,24 @@ module.exports = {

// A whitelist of users public keys who could use this bouncer.
// Leaving this empty will allows everyone to use this bouncer.
// Adding the value to here will result bypassing writable_keys function.
// NOTE: - Require NIP-42 compatible nostr client
authorized_keys: [
// "pubkey-in-hex",
// "npub ....",
// ....
],

// A whitelist of users public keys who could write events to this bouncer.
// Leaving this empty will allows everyone to write events to this bouncer unless you set authorized_keys.
// If the value set in authorized_keys, This list will be ignored.
// This does not require NIP-42 compatible nostr client because it will check from events data.
writable_keys: [
// "pubkey-in-hex",
// "npub ....",
// ....
],

// Used for accessing NIP-42 protected events from certain relays.
// It could be your key. Leaving this empty completely disables NIP-42 function.
//
Expand Down