diff --git a/config.toml b/config.toml index dbb8c09..085790f 100644 --- a/config.toml +++ b/config.toml @@ -148,6 +148,8 @@ reject_future_seconds = 1800 #] # Enable NIP-42 authentication #nip42_auth = false +# Send DMs events (kind 4) only to their authenticated recipients +#nip42_dms = false [verified_users] # NIP-05 verification of users. Can be "enabled" to require NIP-05 diff --git a/src/config.rs b/src/config.rs index b40423b..9ac0398 100644 --- a/src/config.rs +++ b/src/config.rs @@ -80,6 +80,7 @@ pub struct Limits { pub struct Authorization { pub pubkey_whitelist: Option>, // If present, only allow these pubkeys to publish events pub nip42_auth: bool, // if true enables NIP-42 authentication + pub nip42_dms: bool, // if true send DMs only to their authenticated recipients } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -285,6 +286,7 @@ impl Default for Settings { authorization: Authorization { pubkey_whitelist: None, // Allow any address to publish nip42_auth: false, // Disable NIP-42 authentication + nip42_dms: false, // Send DMs to everybody }, pay_to_relay: PayToRelay { enabled: false, diff --git a/src/server.rs b/src/server.rs index 47088a5..cfc5a5c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1029,6 +1029,31 @@ fn make_notice_message(notice: &Notice) -> Message { Message::text(json.to_string()) } +fn allowed_to_send(event_str: &String, conn: &conn::ClientConn, settings: &Settings) -> bool { + // TODO: pass in kind so that we can avoid deserialization for most events + if settings.authorization.nip42_dms { + match serde_json::from_str::(event_str) { + Ok(event) => { + if event.kind == 4 { + match (conn.auth_pubkey(), event.tag_values_by_name("p").first()) { + (Some(auth_pubkey), Some(recipient_pubkey)) => { + recipient_pubkey == auth_pubkey || &event.pubkey == auth_pubkey + }, + (_, _) => { + false + }, + } + } else { + true + } + }, + Err(_) => false + } + } else { + true + } +} + struct ClientInfo { remote_ip: String, user_agent: Option, @@ -1151,11 +1176,13 @@ async fn nostr_server( let send_str = format!("[\"EOSE\",\"{subesc}\"]"); ws_stream.send(Message::Text(send_str)).await.ok(); } else { - client_received_event_count += 1; - metrics.sent_events.with_label_values(&["db"]).inc(); - // send a result - let send_str = format!("[\"EVENT\",\"{}\",{}]", subesc, &query_result.event); - ws_stream.send(Message::Text(send_str)).await.ok(); + if allowed_to_send(&query_result.event, &conn, &settings) { + metrics.sent_events.with_label_values(&["db"]).inc(); + client_received_event_count += 1; + // send a result + let send_str = format!("[\"EVENT\",\"{}\",{}]", subesc, &query_result.event); + ws_stream.send(Message::Text(send_str)).await.ok(); + } } }, // TODO: consider logging the LaggedRecv error @@ -1169,13 +1196,15 @@ async fn nostr_server( // TODO: serialize at broadcast time, instead of // once for each consumer. if let Ok(event_str) = serde_json::to_string(&global_event) { - trace!("sub match for client: {}, sub: {:?}, event: {:?}", + if allowed_to_send(&event_str, &conn, &settings) { + // create an event response and send it + trace!("sub match for client: {}, sub: {:?}, event: {:?}", cid, s, global_event.get_event_id_prefix()); - // create an event response and send it - let subesc = s.replace('"', ""); - metrics.sent_events.with_label_values(&["realtime"]).inc(); - ws_stream.send(Message::Text(format!("[\"EVENT\",\"{subesc}\",{event_str}]"))).await.ok(); + let subesc = s.replace('"', ""); + metrics.sent_events.with_label_values(&["realtime"]).inc(); + ws_stream.send(Message::Text(format!("[\"EVENT\",\"{subesc}\",{event_str}]"))).await.ok(); + } } else { warn!("could not serialize event: {:?}", global_event.get_event_id_prefix()); }