diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 77e5748..d6a3b7c 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -27,5 +27,4 @@ jobs: cargo fmt --all --check - name: Check run: | - cargo clippy --release --features https -- -D warnings cargo clippy -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index ed74032..c2a0ce5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,28 +121,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-extra" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d" -dependencies = [ - "axum", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "serde", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-server" version = "0.7.2" @@ -170,10 +148,8 @@ name = "backend" version = "0.1.0" dependencies = [ "axum", - "axum-extra", "axum-server", "dotenvy", - "rustls", "serde", "serde_json", "tokio", @@ -768,7 +744,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ "aws-lc-rs", - "log", "once_cell", "rustls-pki-types", "rustls-webpki", diff --git a/Cargo.toml b/Cargo.toml index 0c7c7b2..e5df41d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,15 +3,10 @@ name = "backend" version = "0.1.0" edition = "2024" -[features] -https = ["dep:rustls", "dep:axum-extra"] - [dependencies] axum = "0.8.4" -axum-extra = { version = "0.10.1", optional = true } axum-server = { version = "0.7.2", features = ["tls-rustls"] } dotenvy = "0.15.7" -rustls = { version = "0.23.31", optional = true } serde = { version = "1.0.221", features = ["derive"] } serde_json = "1.0.145" tokio = { version = "1.47.1", features = ["rt-multi-thread"] } diff --git a/src/main.rs b/src/main.rs index e4cae46..eca8727 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,30 +1,12 @@ -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use std::{ + env::VarError, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, +}; use crate::app::new_app; -// enforce https on release to make sure no one forgets to use https -#[cfg(all(not(debug_assertions), not(feature = "https")))] -compile_error!("Feature `https` must be enabled on release."); - mod app; -#[allow(dead_code)] -struct Ports { - http: u16, - https: u16, -} - -#[cfg(not(debug_assertions))] -const PORTS: Ports = Ports { - http: 80, - https: 443, -}; -#[cfg(debug_assertions)] -const PORTS: Ports = Ports { - http: 8080, - https: 4430, -}; - #[cfg(debug_assertions)] const ADDR: Ipv4Addr = Ipv4Addr::LOCALHOST; #[cfg(not(debug_assertions))] @@ -33,95 +15,23 @@ const ADDR: Ipv4Addr = Ipv4Addr::UNSPECIFIED; #[tokio::main] async fn main() { let _ = dotenvy::dotenv_override(); // it doesn't matter if there isnt a .env - #[cfg(not(feature = "https"))] - http_main().await; - #[cfg(feature = "https")] - https_main().await; -} - -#[cfg(not(feature = "https"))] -async fn http_main() { - let app = new_app(); - - axum_server::bind(SocketAddr::V4(SocketAddrV4::new(ADDR, PORTS.http))) - .serve(app.into_make_service()) - .await - .unwrap(); -} - -#[cfg(feature = "https")] -async fn https_main() { - use axum_server::tls_rustls::RustlsConfig; - - // configure certificate and private key used by https - let config = RustlsConfig::from_pem_file( - dotenvy::var("HTTPS_CERT_PATH").expect("Environment variable `HTTPS_CERT_PATH` not found.\nCreate it in a .env within the cwd or in the environment"), - dotenvy::var("HTTPS_KEY_PATH").expect("Environment variable `HTTPS_KEY_PATH` not found.\nCreate it in a .env within the cwd or in the environment"), - ) - .await - .unwrap(); - - tokio::spawn(redirect_http_to_https(PORTS)); - let app = new_app(); - // run https server - axum_server::bind_rustls(SocketAddr::V4(SocketAddrV4::new(ADDR, PORTS.https)), config) - .serve(app.into_make_service()) - .await - .unwrap(); -} - -#[cfg(feature = "https")] -async fn redirect_http_to_https(ports: Ports) { - use axum::{ - BoxError, - handler::HandlerWithoutStateExt, - http::{Uri, uri::Authority}, - }; - use axum_extra::extract::Host; - - fn make_https(host: &str, uri: Uri, https_port: u16) -> Result { - let mut parts = uri.into_parts(); - - parts.scheme = Some(axum::http::uri::Scheme::HTTPS); - - if parts.path_and_query.is_none() { - parts.path_and_query = Some("/".parse().unwrap()); - } - - let authority: Authority = host.parse()?; - let bare_host = match authority.port() { - Some(port_struct) => authority - .as_str() - .strip_suffix(port_struct.as_str()) - .unwrap() - .strip_suffix(':') - .unwrap(), // if authority.port() is Some(port) then we can be sure authority ends with :{port} - None => authority.as_str(), - }; - - parts.authority = Some(format!("{bare_host}:{https_port}").parse()?); - - Ok(Uri::from_parts(parts)?) - } - - let redirect = move |Host(host): Host, uri: Uri| async move { - use axum::response::Redirect; - - match make_https(&host, uri, ports.https) { - Ok(uri) => Ok(Redirect::permanent(&uri.to_string())), - Err(_) => { - use axum::http::StatusCode; - - Err(StatusCode::BAD_REQUEST) + let port = dotenvy::var("HTTP_PORT") + .map(|x| x.parse().unwrap()) + .unwrap_or_else(|err| match &err { + dotenvy::Error::EnvVar(VarError::NotPresent) => { + if cfg!(debug_assertions) { + 8080 + } else { + 80 + } } - } - }; + _ => panic!("{err}"), + }); - let addr = SocketAddr::V4(SocketAddrV4::new(ADDR, ports.http)); - let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); - axum::serve(listener, redirect.into_make_service()) + axum_server::bind(SocketAddr::V4(SocketAddrV4::new(ADDR, port))) + .serve(app.into_make_service()) .await .unwrap(); }