From a30f14a0d4de17dbb1cf77b83f1a38aa5380153a Mon Sep 17 00:00:00 2001 From: "Mohamad.Elsena" Date: Thu, 2 Jan 2025 14:33:49 +0100 Subject: [PATCH] added - better error msgs - default user --- backend/src/db.rs | 70 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/backend/src/db.rs b/backend/src/db.rs index 1ba665a..879c995 100644 --- a/backend/src/db.rs +++ b/backend/src/db.rs @@ -1,7 +1,10 @@ -use rusqlite::{params, Connection, OptionalExtension, Result}; +use anyhow::{Context, Result as AnyhowResult}; +use bcrypt::{hash, verify, DEFAULT_COST}; // Add bcrypt dependency for password hashing +use rusqlite::{params, Connection, OptionalExtension}; +use uuid::Uuid; // UUID for generating unique IDs // Import anyhow -pub fn init_db() -> Result { - let conn = Connection::open("form_data.db")?; +pub fn init_db() -> AnyhowResult { + let conn = Connection::open("form_data.db").context("Failed to open the database")?; conn.execute( "CREATE TABLE IF NOT EXISTS forms ( @@ -35,15 +38,51 @@ pub fn init_db() -> Result { [], )?; + // Setup initial admin after creating the tables + setup_initial_admin(&conn)?; + Ok(conn) } +pub fn setup_initial_admin(conn: &Connection) -> AnyhowResult<()> { + add_admin_user(conn)?; + Ok(()) +} + +pub fn add_admin_user(conn: &Connection) -> AnyhowResult<()> { + // Check if admin user already exists + let mut stmt = conn + .prepare("SELECT id FROM users WHERE username = ?1") + .context("Failed to prepare query for checking admin user")?; + if stmt.exists(params!["admin"])? { + return Ok(()); + } + + // Generate a UUID for the admin user + let admin_id = Uuid::new_v4().to_string(); + + // Hash the password before storing it + let hashed_password = hash("admin", DEFAULT_COST).context("Failed to hash password")?; + + // Add admin user with hashed password + conn.execute( + "INSERT INTO users (id, username, password) VALUES (?1, ?2, ?3)", + params![admin_id, "admin", hashed_password], + ) + .context("Failed to insert admin user into the database")?; + + Ok(()) +} + // Add a function to validate a token -pub fn validate_token(conn: &Connection, token: &str) -> Result> { - let mut stmt = conn.prepare("SELECT id FROM users WHERE token = ?1")?; +pub fn validate_token(conn: &Connection, token: &str) -> AnyhowResult> { + let mut stmt = conn + .prepare("SELECT id FROM users WHERE token = ?1") + .context("Failed to prepare query for validating token")?; let user_id: Option = stmt .query_row(params![token], |row| row.get(0)) - .optional()?; + .optional() + .context("Failed to retrieve user ID for the given token")?; Ok(user_id) } @@ -52,16 +91,20 @@ pub fn authenticate_user( conn: &Connection, username: &str, password: &str, -) -> Result> { - let mut stmt = conn.prepare("SELECT id, password FROM users WHERE username = ?1")?; - let mut rows = stmt.query(params![username])?; +) -> AnyhowResult> { + let mut stmt = conn + .prepare("SELECT id, password FROM users WHERE username = ?1") + .context("Failed to prepare query for authenticating user")?; + let mut rows = stmt + .query(params![username]) + .context("Failed to execute query for authenticating user")?; if let Some(row) = rows.next()? { let user_id: String = row.get(0)?; let stored_password: String = row.get(1)?; - // Replace this with a secure password hashing and verification mechanism - if stored_password == password { + // Use bcrypt to verify the hashed password + if verify(password, &stored_password).context("Failed to verify password")? { return Ok(Some(user_id)); } } @@ -69,10 +112,11 @@ pub fn authenticate_user( } // Add a function to generate and save a token for a user -pub fn generate_token_for_user(conn: &Connection, user_id: &str, token: &str) -> Result<()> { +pub fn generate_token_for_user(conn: &Connection, user_id: &str, token: &str) -> AnyhowResult<()> { conn.execute( "UPDATE users SET token = ?1 WHERE id = ?2", params![token, user_id], - )?; + ) + .context("Failed to update token for user")?; Ok(()) }