use hyper::{body, header::HeaderValue, Body, Method, Request, Response, StatusCode}; use std::convert::Infallible; use crate::lox_context; use crate::lox_context::LoxServerContext; // Lox Request handling logic for each Lox request/protocol pub async fn handle( cloned_context: LoxServerContext, req: Request, ) -> Result, Infallible> { println!("Request: {:?}", req); match req.method() { &Method::OPTIONS => Ok(Response::builder() .header("Access-Control-Allow-Origin", HeaderValue::from_static("*")) .header("Access-Control-Allow-Headers", "accept, content-type") .header("Access-Control-Allow-Methods", "POST") .status(200) .body(Body::from("Allow POST")) .unwrap()), _ => match (req.method(), req.uri().path()) { (&Method::POST, "/invite") => { Ok::<_, Infallible>(lox_context::generate_invite(cloned_context)) } (&Method::POST, "/reachability") => { Ok::<_, Infallible>(lox_context::send_reachability_cred(cloned_context)) } (&Method::POST, "/pubkeys") => { Ok::<_, Infallible>(lox_context::send_keys(cloned_context)) } (&Method::POST, "/openreq") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_open_cred(bytes, cloned_context) }), (&Method::POST, "/trustpromo") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_trust_promo(bytes, cloned_context) }), (&Method::POST, "/trustmig") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_trust_migration(bytes, cloned_context) }), (&Method::POST, "/levelup") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_level_up(bytes, cloned_context) }), (&Method::POST, "/issueinvite") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_issue_invite(bytes, cloned_context) }), (&Method::POST, "/redeem") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_redeem_invite(bytes, cloned_context) }), (&Method::POST, "/checkblockage") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); // TEST ONLY: Block all existing bridges and add new ones for migration lox_context::verify_and_send_check_blockage(bytes, cloned_context) }), (&Method::POST, "/blockagemigration") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); lox_context::verify_and_send_blockage_migration(bytes, cloned_context) }), _ => { // Return 404 not found response. Ok(Response::builder() .status(StatusCode::NOT_FOUND) .body(Body::from("Not found")) .unwrap()) } }, } } #[cfg(test)] mod tests { use super::*; use lox::{BridgeAuth, BridgeDb}; use std::sync::{Arc, Mutex}; trait LoxClient { fn invite(&self) -> Request; fn reachability(&self) -> Request; fn pubkeys(&self) -> Request; } struct LoxClientMock {} impl LoxClient for LoxClientMock { fn invite(&self) -> Request { let req = Request::builder() .method("POST") .uri("http://localhost/invite") .body(Body::empty()) .unwrap(); req } fn reachability(&self) -> Request { let req = Request::builder() .method("POST") .uri("http://localhost/reachability") .body(Body::empty()) .unwrap(); req } fn pubkeys(&self) -> Request { let req = Request::builder() .method("POST") .uri("http://localhost/pubkeys") .body(Body::empty()) .unwrap(); req } } struct TestHarness { context: LoxServerContext, } impl TestHarness { fn new() -> Self { let mut bridgedb = BridgeDb::new(); let mut lox_auth = BridgeAuth::new(bridgedb.pubkey); // Make 3 x num_buckets open invitation bridges, in sets of 3 for _ in 0..5 { let bucket = [ lox_context::random(), lox_context::random(), lox_context::random(), ]; lox_auth.add_openinv_bridges(bucket, &mut bridgedb); } // Add hot_spare more hot spare buckets for _ in 0..5 { let bucket = [ lox_context::random(), lox_context::random(), lox_context::random(), ]; lox_auth.add_spare_bucket(bucket); } // Create the encrypted bridge table lox_auth.enc_bridge_table(); let context = lox_context::LoxServerContext { db: Arc::new(Mutex::new(bridgedb)), ba: Arc::new(Mutex::new(lox_auth)), extra_bridges: Arc::new(Mutex::new(Vec::new())), unreplaced_bridges: Arc::new(Mutex::new(Vec::new())), }; Self { context } } } #[tokio::test] async fn test_handle() { let th = TestHarness::new(); let lc = LoxClientMock {}; // Test Invite let invite_request = lc.invite(); let response = handle(th.context.clone(), invite_request).await.unwrap(); println!("Server response?: {:?}", response); assert_eq!(response.status(), StatusCode::OK); // Test Reachability let reachability_request = lc.reachability(); let reachability_response = handle(th.context.clone(), reachability_request) .await .unwrap(); println!("Server response?: {:?}", reachability_response); assert_eq!(reachability_response.status(), StatusCode::OK); // Test Pubkeys let pubkey_request = lc.pubkeys(); let pubkey_response = handle(th.context.clone(), pubkey_request).await.unwrap(); println!("Server response?: {:?}", pubkey_response); assert_eq!(pubkey_response.status(), StatusCode::OK); } }