From dc50f621e05c966dd8b4681e550eaa778165a706 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Fri, 10 Jun 2022 16:12:30 +0200 Subject: [PATCH] update user --- src/api/auth.rs | 2 +- src/api/handles.rs | 15 ++++++++++++--- src/api/models.rs | 6 +++++- src/api/routes.rs | 39 +++++++++++++++++++++++++++++++++------ src/api/utils.rs | 4 ++-- 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/api/auth.rs b/src/api/auth.rs index 79a86fd2..9c2f902d 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::api::utils::GlobalSettings; // Token lifetime and Secret key are hardcoded for clarity -const JWT_EXPIRATION_MINUTES: i64 = 15; +const JWT_EXPIRATION_MINUTES: i64 = 60; #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Claims { diff --git a/src/api/handles.rs b/src/api/handles.rs index a4f107ed..db54cc9f 100644 --- a/src/api/handles.rs +++ b/src/api/handles.rs @@ -109,7 +109,7 @@ pub async fn db_connection() -> Result, sqlx::Error> { Ok(conn) } -pub async fn get_global() -> Result { +pub async fn db_global() -> Result { let conn = db_connection().await?; let query = "SELECT secret FROM global WHERE id = 1"; let result: GlobalSettings = sqlx::query_as(query).fetch_one(&conn).await?; @@ -118,7 +118,7 @@ pub async fn get_global() -> Result { Ok(result) } -pub async fn get_role(id: &i64) -> Result { +pub async fn db_role(id: &i64) -> Result { let conn = db_connection().await?; let query = "SELECT name FROM roles WHERE id = $1"; let result: Role = sqlx::query_as(query).bind(id).fetch_one(&conn).await?; @@ -150,7 +150,7 @@ pub async fn add_user( Ok(result) } -pub async fn get_login(user: &str) -> Result { +pub async fn db_login(user: &str) -> Result { let conn = db_connection().await?; let query = "SELECT id, email, username, password, salt, role_id FROM user WHERE username = $1"; let result: User = sqlx::query_as(query).bind(user).fetch_one(&conn).await?; @@ -158,3 +158,12 @@ pub async fn get_login(user: &str) -> Result { Ok(result) } + +pub async fn db_update_user(id: i64, fields: String) -> Result { + let conn = db_connection().await?; + let query = format!("UPDATE user SET {fields} WHERE id = $1"); + let result: SqliteQueryResult = sqlx::query(&query).bind(id).execute(&conn).await?; + conn.close().await; + + Ok(result) +} diff --git a/src/api/models.rs b/src/api/models.rs index 51133052..8b781f61 100644 --- a/src/api/models.rs +++ b/src/api/models.rs @@ -9,7 +9,7 @@ pub struct User { pub email: Option, pub username: String, #[sqlx(default)] - #[serde(skip_serializing)] + #[serde(skip_serializing, default = "empty_string")] pub password: String, #[sqlx(default)] #[serde(skip_serializing)] @@ -21,6 +21,10 @@ pub struct User { pub token: Option, } +fn empty_string() -> String { + "".to_string() +} + #[derive(Debug, Deserialize, Serialize, Clone)] pub struct LoginUser { pub id: i64, diff --git a/src/api/routes.rs b/src/api/routes.rs index 441ad993..41a0e4f3 100644 --- a/src/api/routes.rs +++ b/src/api/routes.rs @@ -1,13 +1,16 @@ use actix_web::{get, http::StatusCode, post, put, web, Responder}; use actix_web_grants::proc_macro::has_permissions; -use argon2::{password_hash::PasswordHash, Argon2, PasswordVerifier}; +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, SaltString}, + Argon2, PasswordHasher, PasswordVerifier, +}; use serde::Serialize; use simplelog::*; use crate::api::{ auth::{create_jwt, Claims}, errors::ServiceError, - handles::{get_login, get_role}, + handles::{db_login, db_role, db_update_user}, models::{LoginUser, User}, }; @@ -34,8 +37,32 @@ async fn update_user( data: web::Json, ) -> Result { if user_id.into_inner() == user.id { - println!("{data:?}"); - return Ok("Update allow!"); + let mut fields = String::new(); + + if let Some(email) = data.email.clone() { + fields.push_str(format!("email = '{email}'").as_str()); + } + + if !data.password.is_empty() { + if !fields.is_empty() { + fields.push_str(", "); + } + + let salt = SaltString::generate(&mut OsRng); + let argon2 = Argon2::default(); + + let password_hash = argon2 + .hash_password(data.password.clone().as_bytes(), &salt) + .unwrap(); + + fields.push_str(format!("password = '{}', salt = '{salt}'", password_hash).as_str()); + } + + if db_update_user(user.id, fields).await.is_ok() { + return Ok("Update Success"); + }; + + return Err(ServiceError::InternalServerError); } Err(ServiceError::Unauthorized) @@ -45,7 +72,7 @@ async fn update_user( /// http://127.0.0.1:8080/auth/login/ #[post("/auth/login/")] pub async fn login(credentials: web::Json) -> impl Responder { - match get_login(&credentials.username).await { + match db_login(&credentials.username).await { Ok(mut user) => { let pass = user.password.clone(); user.password = "".into(); @@ -56,7 +83,7 @@ pub async fn login(credentials: web::Json) -> impl Responder { .verify_password(credentials.password.as_bytes(), &hash) .is_ok() { - let role = get_role(&user.role_id.unwrap_or_default()) + let role = db_role(&user.role_id.unwrap_or_default()) .await .unwrap_or_else(|_| "guest".to_string()); let claims = Claims::new(user.id, user.username.clone(), vec![role.clone()]); diff --git a/src/api/utils.rs b/src/api/utils.rs index 1e652cac..93e6aaca 100644 --- a/src/api/utils.rs +++ b/src/api/utils.rs @@ -7,7 +7,7 @@ use simplelog::*; use crate::api::{ args_parse::Args, - handles::{add_user, db_init, get_global}, + handles::{add_user, db_global, db_init}, }; #[derive(Debug, sqlx::FromRow)] @@ -17,7 +17,7 @@ pub struct GlobalSettings { impl GlobalSettings { async fn new() -> Self { - let global_settings = get_global(); + let global_settings = db_global(); match global_settings.await { Ok(g) => g,