From 96b3ae1297eae564647c534ed2880607d8b442ef Mon Sep 17 00:00:00 2001
From: SinTan1729 <sayantan.santra689@gmail.com>
Date: Sat, 8 Apr 2023 15:36:33 -0500
Subject: [PATCH] Password login enabled

---
 Dockerfile            |  1 -
 actix/src/auth.rs     | 36 +++++++++++++++++++++++++++++++-----
 actix/src/database.rs |  1 +
 actix/src/main.rs     | 12 +++++++++---
 4 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index 1c5934b..4787d46 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -23,6 +23,5 @@ WORKDIR /opt
 
 COPY --from=build /simply-shorten/target/release/simply-shorten /opt/simply-shorten
 COPY --from=build /simply-shorten/resources /opt/resources
-COPY ./urls.sqlite /opt/urls.sqlite
 
 CMD ["./simply-shorten"]
diff --git a/actix/src/auth.rs b/actix/src/auth.rs
index 0bf495d..0e501cb 100644
--- a/actix/src/auth.rs
+++ b/actix/src/auth.rs
@@ -1,7 +1,8 @@
 use actix_session::Session;
+use std::time::SystemTime;
 
 pub fn validate(session: Session) -> bool {
-    let token = session.get::<i32>("session-token");
+    let token = session.get::<String>("session-token");
     if token.is_err() {
         false
     } else if !check(token.unwrap()) {
@@ -11,12 +12,37 @@ pub fn validate(session: Session) -> bool {
     }
 }
 
-fn check(token: Option<i32>) -> bool {
+fn check(token: Option<String>) -> bool {
     if token.is_none() {
         false
-    } else if token.unwrap() != 123 {
-        false
     } else {
-        true
+        let token_body = token.unwrap();
+        let token_parts: Vec<&str> = token_body.split(";").collect();
+        if token_parts.len() < 2 {
+            false
+        } else {
+            let token_text = token_parts[0];
+            let token_time = token_parts[1].parse::<u64>().unwrap_or(0);
+            let time_now = SystemTime::now()
+                .duration_since(SystemTime::UNIX_EPOCH)
+                .expect("Time went backwards!")
+                .as_secs();
+            println!("{:#?}", token_parts);
+            if token_text == "valid-session-token" && time_now < token_time + 1209600 {
+                // There are 1209600 seconds in 14 days
+                true
+            } else {
+                false
+            }
+        }
     }
 }
+
+pub fn gen_token() -> String {
+    let token_text = "valid-session-token".to_string();
+    let time = SystemTime::now()
+        .duration_since(SystemTime::UNIX_EPOCH)
+        .expect("Time went backwards!")
+        .as_secs();
+    format!("{token_text};{time}")
+}
diff --git a/actix/src/database.rs b/actix/src/database.rs
index 7935290..3239217 100644
--- a/actix/src/database.rs
+++ b/actix/src/database.rs
@@ -58,6 +58,7 @@ pub fn delete_link(shortlink: String, db: &Connection) -> () {
 
 pub fn open_db(path: String) -> Connection {
     let db = Connection::open(path).expect("Unable to open database!");
+    // Create table if it doesn't exist
     db.execute(
         "CREATE TABLE IF NOT EXISTS urls (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
diff --git a/actix/src/main.rs b/actix/src/main.rs
index 085ba9d..7c6fc5d 100644
--- a/actix/src/main.rs
+++ b/actix/src/main.rs
@@ -78,8 +78,9 @@ async fn link_handler(shortlink: web::Path<String>, data: web::Data<AppState>) -
 // Handle login
 #[post("/api/login")]
 async fn login(req: String, session: Session) -> HttpResponse {
-    if req == "ssssss".to_string() {
-        session.insert("session-token", 123).unwrap();
+    if req == env::var("password").unwrap_or(req.clone()) {
+        // If no password was provided, match any password
+        session.insert("session-token", auth::gen_token()).unwrap();
         HttpResponse::Ok().body("Correct password!")
     } else {
         eprintln!("Failed login attempt!");
@@ -104,15 +105,20 @@ async fn delete_link(
 
 #[actix_web::main]
 async fn main() -> std::io::Result<()> {
+    // Generate session key in runtime so that restarts invalidates older logins
     let secret_key = Key::generate();
+    let db_location = env::var("db_url").unwrap_or("/opt/urls.sqlite".to_string());
+
+    // Actually start the server
     HttpServer::new(move || {
         App::new()
             .wrap(SessionMiddleware::new(
                 CookieSessionStore::default(),
                 secret_key.clone(),
             ))
+            // Maintain a single instance of database throughout
             .app_data(web::Data::new(AppState {
-                db: database::open_db(env::var("db_url").unwrap_or("./urls.sqlite".to_string())),
+                db: database::open_db(env::var("db_url").unwrap_or(db_location.clone())),
             }))
             .wrap(middleware::Compress::default())
             .service(link_handler)