From bcf3000bcc0a1d458ac56941c0aa5f9d367d7073 Mon Sep 17 00:00:00 2001 From: AINDUSTRIES Date: Wed, 25 Sep 2024 23:13:15 +0200 Subject: [PATCH] token cookie, register --- .../20240921193253_create_auth_table.sql | 3 +- src/main.rs | 55 ++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/migrations/20240921193253_create_auth_table.sql b/migrations/20240921193253_create_auth_table.sql index 6df0ec6..d0d0d70 100644 --- a/migrations/20240921193253_create_auth_table.sql +++ b/migrations/20240921193253_create_auth_table.sql @@ -4,5 +4,6 @@ id INTEGER PRIMARY KEY NOT NULL, username TEXT NOT NULL, saltyhash text NOT NULL, permissions INTEGER DEFAULT 0, -token TEXT NOT NULL +token TEXT NOT NULL, +UNIQUE(id, username) ) \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d149ee8..ec46d27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use bytes::Buf; use bytes::Bytes; -use chrono::{DateTime, Utc}; +use chrono::{DateTime, Days, Utc}; use futures; use http_body_util::{BodyExt, Full}; use hyper::body::{Body, Incoming}; @@ -20,7 +20,7 @@ use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::SystemTime; use tokio::net::TcpListener; -use rand::distributions::Standard; +use rand::distributions::{DistString, Alphanumeric}; use argon2::{ password_hash::{ rand_core::OsRng, @@ -206,7 +206,7 @@ async fn post(req: Request, db: Arc>) -> Result { - not_found().await + register(req, db).await }, _ => { not_found().await @@ -243,10 +243,13 @@ async fn post_vote(req: Request, db: Arc>) -> Result async fn login(req: Request, db: Arc>) -> Result>, Error> { let body = req.into_body().collect().await; let data: Result = from_reader(body?.aggregate().reader()); - if data.is_err() { + if data.is_err(){ return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()); } let data = data.unwrap(); + if !check_username(&data.username) { + return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()); + } let pool = db.clone().lock().unwrap().clone(); let mut conn = pool.acquire().await.unwrap(); let result = sqlx::query!(r#"SELECT * FROM users WHERE username=?1"#, data.username).fetch_optional(&mut *conn).await; @@ -256,7 +259,10 @@ async fn login(req: Request, db: Arc>) -> Result { - Ok(Response::builder().header("Set-Cookie", format!("token={}", user.token)).body(Full::new(Bytes::from("Ok"))).unwrap()) + let date: DateTime = DateTime::from(SystemTime::now()); + let date = date.checked_add_days(Days::new(7)).unwrap(); + println!("{}", date.to_rfc2822()); + Ok(Response::builder().header("Set-Cookie", format!("token={}; Expires={}; Secure; HttpOnly; SameSite=Strict", user.token, date.to_rfc2822())).body(Full::new(Bytes::from("Ok"))).unwrap()) }, Err(_) => { Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()) @@ -266,12 +272,47 @@ async fn login(req: Request, db: Arc>) -> Result { Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()) } - Err(e) => { Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(Full::new(Bytes::from("Bad Request"))).unwrap()) } + Err(_) => { Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(Full::new(Bytes::from("Server Error"))).unwrap()) } } } async fn register(req: Request, db: Arc>) -> Result>, Error> { - todo!() + let body = req.into_body().collect().await; + let data: Result = from_reader(body?.aggregate().reader()); + if data.is_err() { + return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()); + } + let data = data.unwrap(); + if !check_username(&data.username) { + return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()); + } + let pool = db.clone().lock().unwrap().clone(); + let mut conn = pool.acquire().await.unwrap(); + let exists = sqlx::query!(r#"SELECT id FROM users WHERE username=?1"#, data.username).fetch_optional(&mut *conn).await; + if exists.unwrap().is_some() { + return Ok(Response::builder().status(StatusCode::BAD_REQUEST).body(Full::new(Bytes::from("Bad Request"))).unwrap()); + } + let argon2 = Argon2::default(); + let hash = argon2.hash_password(data.password.as_bytes(), &SaltString::generate(&mut OsRng)).unwrap().to_string(); + let token = Alphanumeric.sample_string(&mut OsRng, 256); + println!("{}", token); + let result = sqlx::query!(r#"INSERT INTO users ( username, saltyhash, permissions, token) VALUES ( ?1, ?2, ?3, ?4 )"#, data.username, hash, 0, token).execute(&mut *conn).await; + match result { + Ok(_) => Ok(Response::builder().body(Full::new(Bytes::from(""))).unwrap()), + Err(_) => { Ok(Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(Full::new(Bytes::from("Server Error"))).unwrap()) } + } +} + +fn check_username(username: &String) -> bool { + if username.len() > 21 { + return false; + } + for x in username.chars() { + if !x.is_ascii_alphanumeric() { + return false; + } + } + true } async fn not_found() -> Result>, Error> {