From 9191168be199f4175a27d43502b46aa8fa32e247 Mon Sep 17 00:00:00 2001
From: Darius Auding <Darius.auding@gmx.de>
Date: Thu, 20 Jul 2023 17:19:46 +0200
Subject: [PATCH] Add HTTPS-REdirect from Port 8080 to 8443

---
 .../src/handling/response/build_and_write.rs  |  6 ++++
 core/http/src/setup.rs                        | 36 +++++++++++++------
 site/src/main.rs                              |  2 +-
 3 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/core/http/src/handling/response/build_and_write.rs b/core/http/src/handling/response/build_and_write.rs
index 67f87bb..3b6bd1b 100644
--- a/core/http/src/handling/response/build_and_write.rs
+++ b/core/http/src/handling/response/build_and_write.rs
@@ -38,4 +38,10 @@ impl Response {
         stream.write_all(&resp).await?;
         Ok(())
     }
+    
+    pub async fn write_unencrypted(self, mut stream: TcpStream) -> Result<()> {
+        let resp = self.build(None);
+        stream.write_all(&resp).await?;
+        Ok(())
+    }
 }
diff --git a/core/http/src/setup.rs b/core/http/src/setup.rs
index c1b3ced..4730fdb 100644
--- a/core/http/src/setup.rs
+++ b/core/http/src/setup.rs
@@ -9,7 +9,7 @@ use tokio_native_tls::{native_tls::{Identity, self}, TlsAcceptor};
 
 use crate::{
     handlers::handler::handle_connection,
-    handling::routes::{Route, Uri},
+    handling::{routes::{Route, Uri}, response::{Response, Status}},
 };
 
 #[derive(Clone)]
@@ -29,6 +29,7 @@ pub struct Config {
     mountpoints: Option<Vec<MountPoint<'static>>>,
     /// Contains a [tokio::net::TcpListener] that is bound for the server
     address: TcpListener,
+    to_secure_redirect: TcpListener,
     tls_acceptor: TlsAcceptor,
 }
 
@@ -93,10 +94,11 @@ impl<'a> Config {
     /// is no interrupt signal
     pub async fn launch(self) {
         println!(
-            "Server launched from http://{}",
-            self.address.local_addr().unwrap()
+            "Server launched from https://{} and http://{}",
+            self.address.local_addr().unwrap(), self.to_secure_redirect.local_addr().unwrap()
         );
         let mut sigint = signal(SignalKind::interrupt()).unwrap();
+        let location_string = format!("Location: https://{}", self.address.local_addr().unwrap());
         loop {
             select! {
                 _ = sigint.recv() => {
@@ -108,6 +110,15 @@ impl<'a> Config {
                     let tls_acceptor = self.tls_acceptor.clone();
                     tokio::spawn(async move { handle_connection(socket, mountpoints, tls_acceptor).await; });
                 }
+                Ok((socket, _)) = self.to_secure_redirect.accept() => {
+                    let redirect_response = Response {
+                        headers: vec![location_string.clone()],
+                        cookies: None,
+                        status: Some(Status::MovedPermanently),
+                        body: Box::new(""),
+                    };
+                    tokio::spawn(async move { let _ = redirect_response.write_unencrypted(socket).await; });
+                }
             }
         }
     }
@@ -122,22 +133,24 @@ impl<'a> Config {
 /// # Example
 /// ```
 /// async fn example() {
-///     let _ = http::build("127.0.0.1:8000");
+///     let _ = http::build("127.0.0.1:8080", "127.0.0.1:8443");
 /// }
 /// ```
 /// # Panics
 /// Panics if the IP is not bindable, or other forms of system errors or it's not a valid
 /// IP-Address
-pub async fn build(ip: &str) -> Config {
-    let listener = if let Ok(listener) = TcpListener::bind(ip).await {
-        listener
-    } else {
+pub async fn build(ip_http: &str, ip_secure: &str) -> Config {
+    let Ok(listener_secure) = TcpListener::bind(ip_secure).await  else {
         panic!("\x1b[31mCould't bind Listener to address\x1b[0m");
     };
-    let ip = ip.splitn(2, ':').collect::<Vec<&str>>();
+    let ip = ip_secure.splitn(2, ':').collect::<Vec<&str>>();
     if ip.len() != 2 {
         panic!("Invalid IP Address");
     }
+
+    let Ok(listener_http) = TcpListener::bind(ip_http).await  else {
+        panic!("\x1b[31mCould't bind Listener to address\x1b[0m");
+    };
     let identity = Identity::from_pkcs12(include_bytes!("certificates/identity.pfx"), "1234").unwrap();
 
     let port = ip[1];
@@ -148,11 +161,14 @@ pub async fn build(ip: &str) -> Config {
   >> \x1b[34mIp\x1b[0m: {ip}
   >> \x1b[34mPort\x1b[0m: {port}
   >> \x1b[34mWorkers\x1b[0m: {workers}
+\x1b[32m Security\x1b[0m
+  >> \x1b[32mHttp to Https Redirect: {ip_http} -> {ip_secure}\x1b[0m
 \x1b[35m🛪 Mountpoints\x1b[0m"
     );
     Config {
         mountpoints: None,
-        address: listener,
+        address: listener_secure,
+        to_secure_redirect: listener_http,
         tls_acceptor: native_tls::TlsAcceptor::builder(identity).build().unwrap().into()
     }
 }
diff --git a/site/src/main.rs b/site/src/main.rs
index 6938a3b..ffa61b1 100644
--- a/site/src/main.rs
+++ b/site/src/main.rs
@@ -104,7 +104,7 @@ async fn main() {
         rank: 0,
     };
 
-    http::build("127.0.0.1:8080")
+    http::build("127.0.0.1:8080", "127.0.0.1:8443")
         .await
         .mount("/", vec![fileserver, post_test, static_hi])
         .mount("/post/", vec![post_test])
-- 
GitLab