diff --git a/Cargo.lock b/Cargo.lock index 1f502c4..983c08d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ name = "ptth_relay" version = "2.0.0" dependencies = [ + "anyhow", "base64", "blake3", "chrono", @@ -1562,6 +1563,7 @@ dependencies = [ "rusty_ulid", "serde", "serde_json", + "serde_urlencoded", "thiserror", "tokio", "tokio-stream", diff --git a/crates/ptth_relay/Cargo.toml b/crates/ptth_relay/Cargo.toml index fc39059..6dde336 100644 --- a/crates/ptth_relay/Cargo.toml +++ b/crates/ptth_relay/Cargo.toml @@ -11,6 +11,7 @@ repository = "https://github.com/ReactorScram/ptth" [dependencies] +anyhow = "1.0.38" base64 = "0.13.0" blake3 = "0.3.7" chrono = { version = "0.4.19", features = ["serde"] } @@ -27,6 +28,7 @@ rmp-serde = "0.14.4" rusty_ulid = "0.10.1" serde = { version = "1.0.117", features = ["derive"] } serde_json = "1.0.60" +serde_urlencoded = "0.7.0" thiserror = "1.0.22" tokio = { version = "1.4.0", features = [] } tokio-stream = "0.1.3" diff --git a/crates/ptth_relay/src/lib.rs b/crates/ptth_relay/src/lib.rs index fb35c6a..e01f6fa 100644 --- a/crates/ptth_relay/src/lib.rs +++ b/crates/ptth_relay/src/lib.rs @@ -22,7 +22,6 @@ use std::{ borrow::Cow, - collections::HashSet, convert::Infallible, net::SocketAddr, path::{Path, PathBuf}, @@ -30,6 +29,7 @@ use std::{ time::Duration, }; +use anyhow::bail; use chrono::{ DateTime, SecondsFormat, @@ -77,6 +77,10 @@ pub use config::{ }; pub use errors::*; pub use relay_state::Relay; +use relay_state::{ + AuditData, + AuditEvent, +}; use relay_state::{ RejectedServer, @@ -98,6 +102,12 @@ fn error_reply (status: StatusCode, b: &str) .body (format! ("{}\n", b).into ()) } +fn get_user_name (req: &http::request::Parts) +-> Option +{ + req.headers.get ("X-Email").map (|x| Some (x.to_str ().ok ()?.to_string ())).flatten () +} + /// Clients will come here to start requests, and always park for at least /// a short amount of time. @@ -109,10 +119,6 @@ async fn handle_http_request ( ) -> Result , RequestError> { - use crate::relay_state::{ - AuditData, - AuditEvent, - }; use RequestError::*; let req_method = req.method.clone (); @@ -124,7 +130,7 @@ async fn handle_http_request ( } } - let user = req.headers.get ("X-Email").map (|x| Some (x.to_str ().ok ()?.to_string ())).flatten (); + let user = get_user_name (&req); let req = match http_serde::RequestParts::from_hyper (req.method, uri.clone (), req.headers) { Ok (x) => x, @@ -522,6 +528,45 @@ async fn handle_gen_scraper_key (_state: Arc ) .body (Body::from (body)) } +async fn handle_register_server (req: Request , state: Arc ) +-> Result <(), anyhow::Error> +{ + let (parts, body) = req.into_parts (); + let user = get_user_name (&parts); + + let form_data = read_body_limited (body, 1_024).await?; + let reg: relay_state::Registration = serde_urlencoded::from_bytes (&form_data)?; + + state.audit_log.push (AuditEvent::new (AuditData::RegisterServer { + user, + reg: reg.clone (), + })).await; + + { + let mut me_config = state.me_config.write ().await; + + //me_config.servers. + } + + Ok (()) +} + +async fn read_body_limited (mut body: Body, limit: usize) -> anyhow::Result > +{ + let mut buffer = vec! []; + while let Some (chunk) = body.next ().await { + let chunk = chunk?; + + if buffer.len () + chunk.len () > limit { + bail! ("Body was bigger than limit"); + } + + buffer.extend_from_slice (&chunk); + } + + Ok (buffer) +} + #[instrument (level = "trace", skip (req, state, handlebars))] async fn handle_all ( req: Request , @@ -589,6 +634,15 @@ async fn handle_all ( }, ErrorMethodNotAllowed => error_reply (StatusCode::METHOD_NOT_ALLOWED, "Method not allowed. Are you POST-ing to a GET-only url, or vice versa?")?, ErrorRoutingFailed => error_reply (StatusCode::OK, "URL routing failed")?, + RegisterServer => { + match handle_register_server (req, state).await { + Ok (_) => Response::builder () + .status (StatusCode::TEMPORARY_REDIRECT) + .header ("location", "unregistered_servers") + .body (Body::from ("Success. Redirecting..."))?, + Err (e) => error_reply (StatusCode::BAD_REQUEST, &format! ("{:?}", e))?, + } + } Root => { let s = handlebars.render ("root", &())?; ok_reply (s)? @@ -675,11 +729,6 @@ pub async fn run_relay ( ) -> Result <(), RelayError> { - use crate::relay_state::{ - AuditData, - AuditEvent, - }; - let handlebars = Arc::new (load_templates (asset_root)?); if let Some (x) = git_version::read ().await { diff --git a/crates/ptth_relay/src/relay_state.rs b/crates/ptth_relay/src/relay_state.rs index e639a5c..90e3925 100644 --- a/crates/ptth_relay/src/relay_state.rs +++ b/crates/ptth_relay/src/relay_state.rs @@ -7,6 +7,7 @@ use std::{ use chrono::{DateTime, Utc}; use dashmap::DashMap; +use serde::Deserialize; use tokio::sync::{ Mutex, RwLock, @@ -116,6 +117,10 @@ pub struct AuditEvent { #[derive (Clone, Debug)] pub enum AuditData { + RegisterServer { + user: Option , + reg: Registration, + }, RelayStart, WebClientGet { user: Option , @@ -125,6 +130,12 @@ pub enum AuditData { }, } +#[derive (Clone, Debug, Deserialize)] +pub struct Registration { + name: String, + tripcode: String, +} + impl AuditEvent { pub fn new (data: AuditData) -> Self { Self { diff --git a/crates/ptth_relay/src/routing.rs b/crates/ptth_relay/src/routing.rs index 60b72b4..87f8ce7 100644 --- a/crates/ptth_relay/src/routing.rs +++ b/crates/ptth_relay/src/routing.rs @@ -20,6 +20,7 @@ pub enum Route <'a> { ErrorCantPost, ErrorMethodNotAllowed, ErrorRoutingFailed, + RegisterServer, Root, Scraper { rest: &'a str, @@ -45,6 +46,9 @@ pub fn route_url <'a> (method: &Method, path: &'a str) -> Route <'a> { else if path == "/frontend/debug/toggle" { Route::DebugToggle } + else if path == "/frontend/register" { + Route::RegisterServer + } else { Route::ErrorCantPost } diff --git a/handlebars/relay/unregistered_servers.hbs b/handlebars/relay/unregistered_servers.hbs index 2d97a4e..a0dec22 100644 --- a/handlebars/relay/unregistered_servers.hbs +++ b/handlebars/relay/unregistered_servers.hbs @@ -29,6 +29,7 @@ AIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA" rel="icon" type="image/x-icon" /> border-collapse: collapse; } .padded { + display: block; padding: 20px; } .submit { @@ -61,11 +62,13 @@ AIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA" rel="icon" type="image/x-icon" /> {{this.name}} {{this.tripcode}} -
+ {{this.last_seen}}