From 3558e7d3d00ae980c2de0a314969155ea2450939 Mon Sep 17 00:00:00 2001 From: AINDUSTRIES Date: Mon, 10 Mar 2025 22:41:33 +0100 Subject: [PATCH] Started working on user authentication --- ...b3d302d083ec5333f3a5ce04113c38a041100.json | 44 +++++++++++++++++ Cargo.toml | 7 ++- database.db | Bin 0 -> 53248 bytes migrations/20250310175116_tables.sql | 41 ++++++++++++++++ src/main.rs | 25 +++++++++- src/users.rs | 46 ++++++++++++++++++ 6 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 .sqlx/query-606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100.json create mode 100644 database.db create mode 100644 migrations/20250310175116_tables.sql create mode 100644 src/users.rs diff --git a/.sqlx/query-606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100.json b/.sqlx/query-606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100.json new file mode 100644 index 0000000..0451596 --- /dev/null +++ b/.sqlx/query-606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100.json @@ -0,0 +1,44 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM users WHERE username = $1", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "uuid", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "username", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "hash", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "email", + "ordinal": 4, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "606364c79e0990deb07dfbe6c32b3d302d083ec5333f3a5ce04113c38a041100" +} diff --git a/Cargo.toml b/Cargo.toml index 648f0fd..7d4e87a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,13 @@ [package] name = "api-server" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] actix-web = "4.9.0" serde = "1.0.218" serde_json = "1.0.140" -sqlx = "0.8.3" \ No newline at end of file +sqlx = { version = "0.8.3", features = ["sqlite", "sqlx-macros"] } +jsonwebtoken = "9.3.1" +uuid = "1.15.1" +argon2 = "0.6.0-pre.1" \ No newline at end of file diff --git a/database.db b/database.db new file mode 100644 index 0000000000000000000000000000000000000000..e0802006e4a361016451c8f65b53163ced87dea5 GIT binary patch literal 53248 zcmeI(&2Jk;7{K9OC$?k9`4E>C2c!v+l2{@rZWO6hP_V-$vg+8WKSW!EmW{J*7Hp?@ z?UEF6h$&nOXAl=8gy6!73laxTocaeKaYvkykWi1E9mny9>e535X!Tp!-u2AvdfsQo zuMYB_x8-( zLoE?YX|wm|ew_Jg_U**yGY8WzCHCU_^lU5@`*qyOlp}xu0tg_000RFDfs^N_qlRJV zoyC^DS97Yi=XmNNu~{_JWmA;XnVcz9kywcfvFz?Ii)_AZZkt81Tg>jHi`T^!^Sa0v z$|7IM<-`kqt9ILOS2nMeMJ1oTS~1V+RdvIzJEzsX^HjN8w{MMB#FNQH#CXNfHMgT$o*at(^tH|{+xXWTmvIhk@8EHn z$f?_IZKOiJqb8s9j#B;Z4!jrcB=xAVx~ks`t5_|Ww~nm3d#h=;+{1=9`aCowFj}jo zfDm`&7|4@FCc7A&C$bRxGI=-M+x`o5bMIij5yEZAtXQi#`<7py-7!n$^v>>C zW)`oTTj@%!EH*1enNP~rS(EP7y>_+gc%H}<3OO^KKRd5mTRm{9?|SXJ$m9x{kviwd zskZ%ISuMBj^t#{cTs-+|C}NaW$4#eE3@bHSG9f=pr~J=T{}+6H?i)?s*bqPf0R#|0 z009ILKmY**5J2ER6u6;B!_ThAYLm~r^ZR}GQ}ykLcVX?q#_HPoYHCfSE?!ElUD~+# zN9OBquY7R#yN}=BeEFy7-g6JCKYVd>>C3l1yL?=lfAC@PM*iCI&%1AQe*0u^DPr&b z75el0U*a+@eeQ2f-q;X8009ILKmY**5I_I{1Q0+VPy(@uaIE`fg8Bph`9K9nFbE)k z00IagfB*srAbfB*srAb std::io::Result<()> { + let pool = SqlitePool::connect("sqlite:database.db").await.expect("Could not connect to db"); + let app_state = Data::new(AppState { database: pool }); + HttpServer::new(move || { + App::new() + .service(login) + .app_data(app_state.clone()) + }).bind(("127.0.0.1", 8000))?.run().await } diff --git a/src/users.rs b/src/users.rs new file mode 100644 index 0000000..329588a --- /dev/null +++ b/src/users.rs @@ -0,0 +1,46 @@ +use actix_web::web::Data; +use actix_web::{post, HttpResponse, Responder}; +use argon2::password_hash::{SaltString, rand_core::OsRng, PasswordHash, PasswordVerifier, PasswordHasher}; +use argon2::Argon2; +use sqlx::{query, query_as}; +use crate::AppState; + +struct UserLogin { + username: String, + password: String, +} + +struct User { + id: i64, + uuid: String, + username: String, + hash: String, + email: String, +} + +#[post("/login")] +async fn login(user_login: Data, app_state: Data) -> impl Responder { + // Verify that the password is correct + let argon2 = Argon2::default(); + let user = query_as!(User, "SELECT * FROM users WHERE username = $1", user_login.username).fetch_one(&app_state.database).await; + if user.is_err() { + return HttpResponse::BadRequest(); + } + let user = user.unwrap(); + let hash = PasswordHash::new(&user.hash); + if hash.is_err() { + return HttpResponse::BadRequest(); + } + if argon2.verify_password(user_login.password.as_bytes(), &hash.unwrap()).is_err() { + return HttpResponse::BadRequest(); + } + // Create the JWT + + // Send the JWT as cookie + HttpResponse::Ok() +} + +#[post("/logout")] +async fn logout(_token: Data) -> impl Responder { + HttpResponse::Ok() +} \ No newline at end of file