From 17f9687b4c08b775716c5473225c09157555c4b9 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Tue, 22 Apr 2025 12:23:46 +1200 Subject: [PATCH] Add configs for: banner_url, privacy_policy, terms_of_service (the latter 2 locally served) --- docs/CONFIG.md | 12 +++++++++ docs/DEPLOYING.md | 3 ++- sample/sample.config.toml | 2 ++ src/config.rs | 17 +++++++++++++ src/lib.rs | 4 +-- src/web/mod.rs | 30 +++++++++++++++++++++++ src/web/nip11.rs | 51 ++++++++++++++++++++++++++++++++++----- 7 files changed, 110 insertions(+), 9 deletions(-) diff --git a/docs/CONFIG.md b/docs/CONFIG.md index fe925ad..6a74899 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -94,10 +94,22 @@ This is an optional description for your relay, displayed in the NIP-11 response Default is "A default config of the Chorus relay". +### banner_url + +This is an optional URL for an graphical banner representing your relay, displayed in the NIP-11 response. + ### icon_url This is an optional URL for an graphical icon representing your relay, displayed in the NIP-11 response. +### privacy_policy + +This is an optional privacy policy as a blob of text (not a URL, not HTML). + +### terms_of_service + +This is an optional terms of service document as a blob of text (not a URL, not HTML). + ### contact This is an optional administrative contact for your relay, displayed in the NIP-11 response. diff --git a/docs/DEPLOYING.md b/docs/DEPLOYING.md index 97509b5..10595d9 100644 --- a/docs/DEPLOYING.md +++ b/docs/DEPLOYING.md @@ -83,7 +83,8 @@ Go ahead and edit that file to your liking. In particular: - Change the `ip_address` to your internet-accessible IP address (if you are running directly) or to 127.0.0.1 with a local port like 8080 (if you are proxying behind nginx) - Change the port if necessary -- Change the name, description, icon_url and contact (e.g. your email address) as desired +- Change the name, description, banner_url, icon_url, privacy_policy, terms_of_service and + contact (e.g. your email address) as desired - Set your contact_public_key_hex (it is an option, so use `Some()`) - Set hex keys of users for which this relay will act as a personal relay diff --git a/sample/sample.config.toml b/sample/sample.config.toml index 84fdd4c..2627043 100644 --- a/sample/sample.config.toml +++ b/sample/sample.config.toml @@ -10,6 +10,8 @@ certchain_pem_path = "tls/fullchain.pem" key_pem_path = "tls/privkey.pem" name = "Chorus Sample" description = "A sample run of the Chorus relay" +privacy_policy = "This relay guarantees nothing. Privacy is your concern, not ours." +terms_of_service = "This relay guarantees nothing. Use at your own risk." # icon_url = open_relay = false admin_hex_keys = [ diff --git a/src/config.rs b/src/config.rs index 81ef61a..55bed30 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,7 +19,10 @@ pub struct FriendlyConfig { pub key_pem_path: String, pub name: Option, pub description: Option, + pub banner_url: Option, pub icon_url: Option, + pub privacy_policy: Option, + pub terms_of_service: Option, pub contact: Option, #[serde(alias = "public_key_hex")] pub contact_public_key_hex: Option, @@ -60,7 +63,10 @@ impl Default for FriendlyConfig { key_pem_path: "/opt/chorus/etc/tls/privkey.pem".to_string(), name: Some("Chorus Default".to_string()), description: Some("A default config of the Chorus relay".to_string()), + banner_url: None, icon_url: None, + privacy_policy: None, + terms_of_service: None, contact: None, contact_public_key_hex: None, open_relay: false, @@ -102,7 +108,10 @@ impl FriendlyConfig { key_pem_path, name, description, + banner_url, icon_url, + privacy_policy, + terms_of_service, contact, contact_public_key_hex, open_relay, @@ -159,7 +168,10 @@ impl FriendlyConfig { key_pem_path, name, description, + banner_url, icon_url, + privacy_policy, + terms_of_service, contact, contact_public_key, open_relay, @@ -201,7 +213,10 @@ pub struct Config { pub key_pem_path: String, pub name: Option, pub description: Option, + pub banner_url: Option, pub icon_url: Option, + pub privacy_policy: Option, + pub terms_of_service: Option, pub contact: Option, pub contact_public_key: Option, pub open_relay: bool, @@ -238,6 +253,8 @@ impl Default for Config { } impl Config { + /// Get the URI for our server matching the inner Uri, overridden with either + /// our base_url parts or our hostname/port. pub fn uri_parts(&self, inner: Uri, http: bool) -> Result { let mut uri_parts = inner.into_parts(); diff --git a/src/lib.rs b/src/lib.rs index 28d4794..a69c977 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -180,9 +180,9 @@ async fn handle_http_request( } let mut web_socket_config = WebSocketConfig::default(); - web_socket_config.max_write_buffer_size = 1024 * 1024; // 1 MB + web_socket_config.max_write_buffer_size = 1024 * 1024; // 1 MB web_socket_config.max_message_size = Some(1024 * 1024); // 1 MB - web_socket_config.max_frame_size = Some(1024 * 1024); // 1 MB + web_socket_config.max_frame_size = Some(1024 * 1024); // 1 MB let (mut response, websocket) = hyper_tungstenite::upgrade(&mut request, Some(web_socket_config))?; diff --git a/src/web/mod.rs b/src/web/mod.rs index 056bd83..cfec110 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -53,6 +53,36 @@ pub async fn serve_http( let uri = request.uri().to_owned(); + if p == "/privacy-policy" { + let config = &*GLOBALS.config.read(); + if let Some(pp) = &config.privacy_policy { + let response = Response::builder() + .header("Access-Control-Allow-Origin", "*") + .header("Access-Control-Allow-Headers", "Authorization, *") + .header("Access-Control-Allow-Methods", "*") + .header("Allow", "OPTIONS, GET, HEAD") + .header("Content-Type", "text/plain") + .status(StatusCode::OK) + .body(Full::new(pp.clone().into()).map_err(|e| e.into()).boxed())?; + return Ok(response); + } + } + + if p == "/terms-of-service" { + let config = &*GLOBALS.config.read(); + if let Some(tos) = &config.terms_of_service { + let response = Response::builder() + .header("Access-Control-Allow-Origin", "*") + .header("Access-Control-Allow-Headers", "Authorization, *") + .header("Access-Control-Allow-Methods", "*") + .header("Allow", "OPTIONS, GET, HEAD") + .header("Content-Type", "text/plain") + .status(StatusCode::OK) + .body(Full::new(tos.clone().into()).map_err(|e| e.into()).boxed())?; + return Ok(response); + } + } + // Try blossom if enabled if GLOBALS.config.read().blossom_directory.is_some() { match blossom::handle(request).await { diff --git a/src/web/nip11.rs b/src/web/nip11.rs index c8e0cd2..2854179 100644 --- a/src/web/nip11.rs +++ b/src/web/nip11.rs @@ -5,6 +5,7 @@ use crate::ip::HashedPeer; use http_body_util::combinators::BoxBody; use http_body_util::{BodyExt, Full}; use hyper::body::Bytes; +use hyper::http::uri::Uri; use hyper::{Response, StatusCode}; pub async fn serve_nip11(peer: HashedPeer) -> Result>, Error> { @@ -80,18 +81,18 @@ fn build_rid(config: &Config) -> String { rid.push_str(description); rid.push('\"'); } + if let Some(banner_url) = &config.banner_url { + rid.push(','); + rid.push_str("\"banner\":\""); + rid.push_str(banner_url); + rid.push('\"'); + } if let Some(icon_url) = &config.icon_url { rid.push(','); rid.push_str("\"icon\":\""); rid.push_str(icon_url); rid.push('\"'); } - if let Some(contact) = &config.contact { - rid.push(','); - rid.push_str("\"contact\":\""); - rid.push_str(contact); - rid.push('\"'); - } if let Some(pubkey) = &config.contact_public_key { let mut pkh: [u8; 64] = [0; 64]; pubkey.write_hex(&mut pkh).unwrap(); @@ -100,6 +101,44 @@ fn build_rid(config: &Config) -> String { rid.push_str(unsafe { std::str::from_utf8_unchecked(pkh.as_slice()) }); rid.push('\"'); } + if let Some(contact) = &config.contact { + rid.push(','); + rid.push_str("\"contact\":\""); + rid.push_str(contact); + rid.push('\"'); + } + if config.privacy_policy.is_some() { + rid.push(','); + rid.push_str("\"privacy_policy\":\""); + let url = match config.uri_parts( + Uri::from_static("https://authority-will-be-replaced/privacy-policy"), + true, + ) { + Ok(parts) => match Uri::from_parts(parts) { + Ok(uri) => format!("{}", uri), + Err(_) => "".to_owned(), + }, + Err(_) => "".to_owned(), + }; + rid.push_str(&url); + rid.push('\"'); + } + if config.terms_of_service.is_some() { + rid.push(','); + rid.push_str("\"terms_of_service\":\""); + let url = match config.uri_parts( + Uri::from_static("https://authority-will-be-replaced/terms-of-service"), + true, + ) { + Ok(parts) => match Uri::from_parts(parts) { + Ok(uri) => format!("{}", uri), + Err(_) => "".to_owned(), + }, + Err(_) => "".to_owned(), + }; + rid.push_str(&url); + rid.push('\"'); + } // Limitation rid.push(',');