Merge pull request #9 from scsibug/master

Fork Sync: Update from parent repository
This commit is contained in:
PascalR 2023-08-13 22:39:39 +02:00 committed by GitHub
commit 60ccbea0a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 852 additions and 679 deletions

1433
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nostr-rs-relay" name = "nostr-rs-relay"
version = "0.8.9" version = "0.8.12"
edition = "2021" edition = "2021"
authors = ["Greg Heartsfield <scsibug@imap.cc>"] authors = ["Greg Heartsfield <scsibug@imap.cc>"]
description = "A relay implementation for the Nostr protocol" description = "A relay implementation for the Nostr protocol"
@ -57,6 +57,7 @@ qrcode = { version = "0.12.0", default-features = false, features = ["svg"] }
nostr = { version = "0.18.0", default-features = false, features = ["base", "nip04", "nip19"] } nostr = { version = "0.18.0", default-features = false, features = ["base", "nip04", "nip19"] }
[target.'cfg(not(target_env = "msvc"))'.dependencies] [target.'cfg(not(target_env = "msvc"))'.dependencies]
tikv-jemallocator = "0.5" tikv-jemallocator = "0.5"
log = "0.4"
[dev-dependencies] [dev-dependencies]
anyhow = "1" anyhow = "1"

View File

@ -160,7 +160,7 @@ reject_future_seconds = 1800
#] #]
# Enable NIP-42 authentication # Enable NIP-42 authentication
#nip42_auth = false #nip42_auth = false
# Send DMs events (kind 4) only to their authenticated recipients # Send DMs (kind 4 and 44) and gift wraps (kind 1059) only to their authenticated recipients
#nip42_dms = false #nip42_dms = false
[verified_users] [verified_users]

View File

@ -1,6 +1,6 @@
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure() tonic_build::configure()
.build_server(false) .build_server(true)
.protoc_arg("--experimental_allow_proto3_optional") .protoc_arg("--experimental_allow_proto3_optional")
.compile(&["../../proto/nauthz.proto"], &["../../proto"])?; .compile(&["../../proto/nauthz.proto"], &["../../proto"])?;
Ok(()) Ok(())

View File

@ -156,7 +156,7 @@ impl ClientConn {
self.auth = Challenge(Uuid::new_v4().to_string()); self.auth = Challenge(Uuid::new_v4().to_string());
} }
pub fn authenticate(&mut self, event: &Event, relay_url: &String) -> Result<()> { pub fn authenticate(&mut self, event: &Event, relay_url: &str) -> Result<()> {
match &self.auth { match &self.auth {
Challenge(_) => (), Challenge(_) => (),
AuthPubkey(_) => { AuthPubkey(_) => {
@ -181,15 +181,15 @@ impl ClientConn {
return Err(Error::AuthFailure); return Err(Error::AuthFailure);
} }
let mut challenge: Option<&String> = None; let mut challenge: Option<&str> = None;
let mut relay: Option<&String> = None; let mut relay: Option<&str> = None;
for tag in &event.tags { for tag in &event.tags {
if tag.len() == 2 && tag.get(0) == Some(&"challenge".into()) { if tag.len() == 2 && tag.get(0) == Some(&"challenge".into()) {
challenge = tag.get(1); challenge = tag.get(1).map(|x| x.as_str());
} }
if tag.len() == 2 && tag.get(0) == Some(&"relay".into()) { if tag.len() == 2 && tag.get(0) == Some(&"relay".into()) {
relay = tag.get(1); relay = tag.get(1).map(|x| x.as_str());
} }
} }

View File

@ -11,6 +11,7 @@ use crate::repo::NostrRepo;
use crate::server::NostrMetrics; use crate::server::NostrMetrics;
use governor::clock::Clock; use governor::clock::Clock;
use governor::{Quota, RateLimiter}; use governor::{Quota, RateLimiter};
use log::LevelFilter;
use nostr::key::FromPkStr; use nostr::key::FromPkStr;
use nostr::key::Keys; use nostr::key::Keys;
use r2d2; use r2d2;
@ -20,7 +21,6 @@ use sqlx::ConnectOptions;
use std::sync::Arc; use std::sync::Arc;
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tracing::log::LevelFilter;
use tracing::{debug, info, trace, warn}; use tracing::{debug, info, trace, warn};
pub type SqlitePool = r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>; pub type SqlitePool = r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>;

View File

@ -63,7 +63,7 @@ pub struct RelayInfo {
/// Convert an Info configuration into public Relay Info /// Convert an Info configuration into public Relay Info
impl From<Settings> for RelayInfo { impl From<Settings> for RelayInfo {
fn from(c: Settings) -> Self { fn from(c: Settings) -> Self {
let mut supported_nips = vec![1, 2, 9, 11, 12, 15, 16, 20, 22, 33, 40, 42]; let mut supported_nips = vec![1, 2, 9, 11, 12, 15, 16, 20, 22, 33, 40];
if c.authorization.nip42_auth { if c.authorization.nip42_auth {
supported_nips.push(42); supported_nips.push(42);

View File

@ -41,7 +41,7 @@ impl std::convert::From<Nip05Name> for nauthz_grpc::event_request::Nip05Name {
} }
// conversion of event tags into gprc struct // conversion of event tags into gprc struct
fn tags_to_protobuf(tags: &Vec<Vec<String>>) -> Vec<TagEntry> { fn tags_to_protobuf(tags: &[Vec<String>]) -> Vec<TagEntry> {
tags.iter() tags.iter()
.map(|x| TagEntry { values: x.clone() }) .map(|x| TagEntry { values: x.clone() })
.collect() .collect()

View File

@ -21,8 +21,7 @@ use crate::utils::{self, is_hex, is_lower_hex};
use nostr::key::Keys; use nostr::key::Keys;
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tokio::sync::oneshot::Receiver; use tokio::sync::oneshot::Receiver;
use tracing::log::trace; use tracing::{debug, error, info, trace, warn};
use tracing::{debug, error, info, warn};
pub type PostgresPool = sqlx::pool::Pool<Postgres>; pub type PostgresPool = sqlx::pool::Pool<Postgres>;

View File

@ -1009,7 +1009,7 @@ fn query_from_filter(f: &ReqFilter) -> (String, Vec<Box<dyn ToSql>>, Option<Stri
params.push(Box::new(lower)); params.push(Box::new(lower));
} }
None => { None => {
info!("Could not parse hex range from author {:?}", auth); trace!("Could not parse hex range from author {:?}", auth);
} }
} }
} }
@ -1072,8 +1072,6 @@ fn query_from_filter(f: &ReqFilter) -> (String, Vec<Box<dyn ToSql>>, Option<Stri
// find evidence of the target tag name/value existing for this event. // find evidence of the target tag name/value existing for this event.
// Query for Kind/Since/Until additionally, to reduce the number of tags that come back. // Query for Kind/Since/Until additionally, to reduce the number of tags that come back.
let kind_clause; let kind_clause;
let since_clause;
let until_clause;
if let Some(ks) = &f.kinds { if let Some(ks) = &f.kinds {
// kind is number, no escaping needed // kind is number, no escaping needed
let str_kinds: Vec<String> = let str_kinds: Vec<String> =
@ -1082,16 +1080,16 @@ fn query_from_filter(f: &ReqFilter) -> (String, Vec<Box<dyn ToSql>>, Option<Stri
} else { } else {
kind_clause = String::new(); kind_clause = String::new();
}; };
if f.since.is_some() { let since_clause = if f.since.is_some() {
since_clause = format!("AND created_at >= {}", f.since.unwrap()); format!("AND created_at >= {}", f.since.unwrap())
} else { } else {
since_clause = String::new(); String::new()
}; };
// Query for timestamp // Query for timestamp
if f.until.is_some() { let until_clause = if f.until.is_some() {
until_clause = format!("AND created_at <= {}", f.until.unwrap()); format!("AND created_at <= {}", f.until.unwrap())
} else { } else {
until_clause = String::new(); String::new()
}; };
let tag_clause = format!( let tag_clause = format!(

View File

@ -30,6 +30,8 @@ use hyper::upgrade::Upgraded;
use hyper::{ use hyper::{
header, server::conn::AddrStream, upgrade, Body, Request, Response, Server, StatusCode, header, server::conn::AddrStream, upgrade, Body, Request, Response, Server, StatusCode,
}; };
use nostr::key::FromPkStr;
use nostr::key::Keys;
use prometheus::IntCounterVec; use prometheus::IntCounterVec;
use prometheus::IntGauge; use prometheus::IntGauge;
use prometheus::{Encoder, Histogram, HistogramOpts, IntCounter, Opts, Registry, TextEncoder}; use prometheus::{Encoder, Histogram, HistogramOpts, IntCounter, Opts, Registry, TextEncoder};
@ -60,8 +62,6 @@ use tungstenite::error::Error as WsError;
use tungstenite::handshake; use tungstenite::handshake;
use tungstenite::protocol::Message; use tungstenite::protocol::Message;
use tungstenite::protocol::WebSocketConfig; use tungstenite::protocol::WebSocketConfig;
use nostr::key::FromPkStr;
use nostr::key::Keys;
/// Handle arbitrary HTTP requests, including for `WebSocket` upgrades. /// Handle arbitrary HTTP requests, including for `WebSocket` upgrades.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -1029,25 +1029,23 @@ fn make_notice_message(notice: &Notice) -> Message {
Message::text(json.to_string()) Message::text(json.to_string())
} }
fn allowed_to_send(event_str: &String, conn: &conn::ClientConn, settings: &Settings) -> bool { fn allowed_to_send(event_str: &str, conn: &conn::ClientConn, settings: &Settings) -> bool {
// TODO: pass in kind so that we can avoid deserialization for most events // TODO: pass in kind so that we can avoid deserialization for most events
if settings.authorization.nip42_dms { if settings.authorization.nip42_dms {
match serde_json::from_str::<Event>(event_str) { match serde_json::from_str::<Event>(event_str) {
Ok(event) => { Ok(event) => {
if event.kind == 4 { if event.kind == 4 || event.kind == 44 || event.kind == 1059 {
match (conn.auth_pubkey(), event.tag_values_by_name("p").first()) { match (conn.auth_pubkey(), event.tag_values_by_name("p").first()) {
(Some(auth_pubkey), Some(recipient_pubkey)) => { (Some(auth_pubkey), Some(recipient_pubkey)) => {
recipient_pubkey == auth_pubkey || &event.pubkey == auth_pubkey recipient_pubkey == auth_pubkey || &event.pubkey == auth_pubkey
}, }
(_, _) => { (_, _) => false,
false
},
} }
} else { } else {
true true
} }
}, }
Err(_) => false Err(_) => false,
} }
} else { } else {
true true

View File

@ -37,7 +37,7 @@ pub fn is_lower_hex(s: &str) -> bool {
}) })
} }
pub fn host_str(url: &String) -> Option<String> { pub fn host_str(url: &str) -> Option<String> {
Url::parse(url) Url::parse(url)
.ok() .ok()
.and_then(|u| u.host_str().map(|s| s.to_string())) .and_then(|u| u.host_str().map(|s| s.to_string()))

View File

@ -1,8 +1,10 @@
use anyhow::Result; use anyhow::Result;
use futures::SinkExt;
use futures::StreamExt;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use tokio_tungstenite::connect_async;
use tracing::info;
mod common; mod common;
#[tokio::test] #[tokio::test]
@ -45,3 +47,33 @@ async fn relay_home_page() -> Result<()> {
let _res = relay.shutdown_tx.send(()); let _res = relay.shutdown_tx.send(());
Ok(()) Ok(())
} }
//#[tokio::test]
// Still inwork
async fn publish_test() -> Result<()> {
// get a relay and wait for startup
let relay = common::start_relay()?;
common::wait_for_healthy_relay(&relay).await?;
// open a non-secure websocket connection.
let (mut ws, _res) = connect_async(format!("ws://localhost:{}", relay.port)).await?;
// send a simple pre-made message
let simple_event = r#"["EVENT", {"content": "hello world","created_at": 1691239763,
"id":"f3ce6798d70e358213ebbeba4886bbdfacf1ecfd4f65ee5323ef5f404de32b86",
"kind": 1,
"pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"sig": "30ca29e8581eeee75bf838171dec818af5e6de2b74f5337de940f5cc91186534c0b20d6cf7ad1043a2c51dbd60b979447720a471d346322103c83f6cb66e4e98",
"tags": []}]"#;
ws.send(simple_event.into()).await?;
// get response from server, confirm it is an array with first element "OK"
let event_confirm = ws.next().await;
ws.close(None).await?;
info!("event confirmed: {:?}", event_confirm);
// open a new connection, and wait for some time to get the event.
let (mut sub_ws, _res) = connect_async(format!("ws://localhost:{}", relay.port)).await?;
let event_sub = r#"["REQ", "simple", {}]"#;
sub_ws.send(event_sub.into()).await?;
// read from subscription
let _ws_next = sub_ws.next().await;
let _res = relay.shutdown_tx.send(());
Ok(())
}