From 0c68399210546d3440bec34702e45acc9425aa5b Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Jul 2025 12:35:03 +0200 Subject: [PATCH] chore: clean up, rename types.rs to server.rs --- config.yaml | 2 +- src/config.rs | 21 ++++++++- src/db.rs | 5 ++- src/main.rs | 20 ++++++--- src/{types.rs => server.rs} | 4 +- src/services.rs | 4 +- src/services/api.rs | 88 +++++++++++++++++++++++++++---------- src/services/controller.rs | 5 +-- src/services/proxy.rs | 2 +- 9 files changed, 110 insertions(+), 41 deletions(-) rename src/{types.rs => server.rs} (95%) diff --git a/config.yaml b/config.yaml index b3d0032..602b3e2 100644 --- a/config.yaml +++ b/config.yaml @@ -17,4 +17,4 @@ hosts: # ignore this it doesn't function clients: - name: 'eu-central-1' # Example Client right here (the client in this case would be for example the stereo.cat backend) - secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123 + hashed_secret: '$2b$12$5wH/0p702PPqVp7fCpVS4.1GA2/wAbk89w2nMjwuS8439OhjCUGbK' # password123 diff --git a/src/config.rs b/src/config.rs index 1e055a0..719f3c9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -27,7 +27,26 @@ pub struct Api { #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Client { pub name: String, - pub secret: String, + pub hashed_secret: String, +} + +impl Client { + pub async fn verify(us: String, config: Config) -> bool { + // us stands for user:secret btw + let us_split: Vec<&str> = us.split(':').collect(); + + let name = us_split.first().unwrap(); + let secret = us_split.last().unwrap(); + + let client: Client = config + .clients + .into_iter() + .filter(|x| x.name.eq(name)) + .nth(0) + .unwrap(); + + return bcrypt::verify(secret, client.hashed_secret.as_str()).unwrap(); + } } #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] diff --git a/src/db.rs b/src/db.rs index b880979..86c691d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,4 +1,7 @@ -use std::{error::Error, net::{IpAddr, SocketAddr}}; +use std::{ + error::Error, + net::{IpAddr, SocketAddr}, +}; use tokio_postgres::{Client, Socket, tls::MakeTlsConnect}; diff --git a/src/main.rs b/src/main.rs index 9c9cf9e..42844c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod config; mod db; +mod server; mod services; -mod types; use std::{env, sync::Arc}; @@ -11,16 +11,20 @@ use db::BoxyDatabase; use log::{error, info}; use nanoid::nanoid; use ring::rand::SystemRandom; +use server::Server; use services::{api::ApiService, controller::ControllerService}; use tokio::{fs::File, io::AsyncReadExt, sync::Mutex}; use tokio_postgres::{NoTls, tls::NoTlsError}; -use types::Server; + +const VERSION: &str = "v0.1a"; #[tokio::main] async fn main() -> Result<(), Box> { - pretty_env_logger::formatted_builder() - .filter(None, log::LevelFilter::Info) - .init(); + if env::var("RUST_LOG").is_err() { + unsafe { env::set_var("RUST_LOG", "info") }; + } + + pretty_env_logger::init(); let args: Vec = env::args().collect(); @@ -37,6 +41,10 @@ async fn main() -> Result<(), Box> { return Ok(()); } + "version" => { + info!("Version: {}", VERSION); + return Ok(()); + } _ => {} } } @@ -64,7 +72,7 @@ async fn main() -> Result<(), Box> { let api_svc = ApiService { database: database_shared.clone(), config: config.clone(), - _address: None + _address: None, }; let svc = ControllerService { diff --git a/src/types.rs b/src/server.rs similarity index 95% rename from src/types.rs rename to src/server.rs index c96f5ae..f35f836 100644 --- a/src/types.rs +++ b/src/server.rs @@ -25,7 +25,7 @@ pub struct Server { } pub trait TcpIntercept { - fn handle(&mut self, stream: &TcpStream); + fn stream(&mut self, stream: &TcpStream); } impl Server @@ -43,7 +43,7 @@ where let (stream, _) = self.listener.accept().await.unwrap(); let mut svc_clone = self.service.clone(); - svc_clone.handle(&stream); + svc_clone.stream(&stream); let io = TokioIo::new(stream); tokio::task::spawn(async move { diff --git a/src/services.rs b/src/services.rs index e8b28e6..168dbf8 100644 --- a/src/services.rs +++ b/src/services.rs @@ -1,3 +1,3 @@ -pub mod proxy; -pub mod controller; pub mod api; +pub mod controller; +pub mod proxy; diff --git a/src/services/api.rs b/src/services/api.rs index b8a107a..a3dce19 100644 --- a/src/services/api.rs +++ b/src/services/api.rs @@ -1,16 +1,20 @@ -use std::{hash, net::{IpAddr, SocketAddr}, pin::Pin, sync::Arc}; +use std::{net::IpAddr, pin::Pin, sync::Arc}; use base64::{Engine, prelude::BASE64_STANDARD}; -use bcrypt::DEFAULT_COST; +use bcrypt::bcrypt; use http_body_util::{BodyExt, Full}; use hyper::{ - body::{Bytes, Incoming}, service::Service, Method, Request, Response, StatusCode, Uri + Method, Request, Response, StatusCode, + body::{Bytes, Incoming}, + service::Service, }; -use log::{info, trace}; +use log::{debug, info, warn}; use tokio::{net::TcpStream, sync::Mutex}; use crate::{ - config::{Client, Config}, db::{BoxyDatabase, Endpoint}, types::{GeneralBody, GeneralResponse, TcpIntercept} + config::{Client, Config}, + db::{BoxyDatabase, Endpoint}, + server::{GeneralBody, GeneralResponse, TcpIntercept}, }; #[derive(Debug, Clone)] @@ -20,7 +24,7 @@ pub struct ApiService { pub _address: Option, } -async fn default_response() -> Response>> { +async fn default_response() -> GeneralResponse { Response::builder() .status(404) .body(GeneralBody::Right(Full::from(Bytes::from( @@ -29,7 +33,7 @@ async fn default_response() -> Response Response>> { +async fn custom_resp(e: StatusCode, m: &'static str) -> GeneralResponse { Response::builder() .status(e) .body(GeneralBody::Right(Full::from(Bytes::from(m)))) @@ -37,7 +41,7 @@ async fn custom_resp(e: StatusCode, m: String) -> Response> for ApiService { let database = self.database.clone(); let config = self.config.clone(); let address = self._address.clone().unwrap(); + Box::pin(async move { match *req.method() { Method::POST => match req.uri().path() { "/register" => { - let encoded_header = req.headers().get(hyper::header::AUTHORIZATION).unwrap().to_str().unwrap(); - - let auth_string = String::from_utf8(BASE64_STANDARD.decode(&encoded_header[6..]).unwrap()).unwrap(); - - let auth_string_split: Vec<&str> = auth_string.split(':').collect(); + debug!("new api register request from {}", address); - let name = auth_string_split.first().unwrap(); - let secret = auth_string_split.get(1).unwrap(); + let encoded_header = req + .headers() + .get(hyper::header::AUTHORIZATION) + .unwrap() + .to_str() + .unwrap(); - let matched_clients: Vec<&Client> = config.clients.iter().filter(|x| x.name.eq(name)).collect(); + debug!("authorization header: {}", encoded_header); - let client = matched_clients.first().unwrap(); + let auth_string = String::from_utf8( + BASE64_STANDARD.decode(&encoded_header[6..]).unwrap(), + ) + .unwrap(); - if !bcrypt::verify(secret, client.secret.as_str()).unwrap() { - return Ok(custom_resp(StatusCode::UNAUTHORIZED, "Invalid credentials.".to_string()).await); + debug!("decoded auth string: {}", auth_string); + + if !Client::verify(auth_string.clone(), config).await { + warn!( + "Authentication for string {} from {} failed.", + auth_string, address + ); + + return Ok(custom_resp( + StatusCode::UNAUTHORIZED, + "Invalid credentials.", + ) + .await); } - let body = String::from_utf8(req.collect().await.unwrap().to_bytes().iter().cloned().collect::>()).unwrap(); + let body = String::from_utf8( + req.collect() + .await + .unwrap() + .to_bytes() + .iter() + .cloned() + .collect::>(), + ) + .unwrap(); let json = json::parse(body.as_str()).unwrap(); - info!("body: {}", body); + debug!("body: {}", body); - let mut endpoint = Endpoint::new(None, address, json["port"].as_u16().unwrap(), json["callback"].as_str().unwrap_or("/").to_string()).await; + let mut endpoint = Endpoint::new( + None, + address, + json["port"].as_u16().unwrap(), + json["callback"].as_str().unwrap_or("/").to_string(), + ) + .await; - endpoint.register(*database.lock().await, json["hostname"].as_str().unwrap().to_string()).await.unwrap(); + endpoint + .register( + *database.lock().await, + json["hostname"].as_str().unwrap().to_string(), + ) + .await + .unwrap(); - Ok(custom_resp(StatusCode::OK, "yay".to_string()).await) + Ok(custom_resp(StatusCode::OK, "").await) } _ => Ok(default_response().await), }, diff --git a/src/services/controller.rs b/src/services/controller.rs index eee4b1c..b892b20 100644 --- a/src/services/controller.rs +++ b/src/services/controller.rs @@ -12,7 +12,7 @@ use tokio::sync::Mutex; use crate::{ config::{self, Client, Config, Host}, db::{BoxyDatabase, Endpoint}, - types::{GeneralBody, GeneralResponse, TcpIntercept}, + server::{GeneralBody, GeneralResponse, TcpIntercept}, }; use super::proxy::ProxyService; @@ -23,8 +23,7 @@ pub struct ControllerService { } impl TcpIntercept for ControllerService { - fn handle(&mut self, stream: &tokio::net::TcpStream) { - } + fn stream(&mut self, _: &tokio::net::TcpStream) {} } impl Service> for ControllerService { diff --git a/src/services/proxy.rs b/src/services/proxy.rs index c0e7e7d..e4641e1 100644 --- a/src/services/proxy.rs +++ b/src/services/proxy.rs @@ -5,7 +5,7 @@ use hyper_util::rt::TokioIo; use log::error; use tokio::net::TcpStream; -use crate::types::{GeneralResponse, to_general_response}; +use crate::server::{GeneralResponse, to_general_response}; #[derive(Debug, Clone)] pub struct ProxyService {