Compare commits

...

3 commits

Author SHA1 Message Date
Talha Qamar 65947193b9 Added Handles 2025-03-06 02:50:11 +05:00
Talha Qamar cdf0b7bd29 Fixed password hashing logic error 2025-03-05 16:44:44 +05:00
Talha Qamar 8bb227f48e Removed user_db (i am v stupid) 2025-03-05 16:44:15 +05:00
8 changed files with 109 additions and 10 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
user_db.db3

View file

@ -9,6 +9,7 @@ pub struct Account {
creation_time: DateTime<Utc>,
// Donator role
premium: bool,
random: i64,
}
impl Account {
@ -17,12 +18,14 @@ impl Account {
user_id: UserID,
creation_time: DateTime<Utc>,
premium: bool,
random: i64,
) -> Self {
Self {
username,
user_id,
creation_time,
premium,
random,
}
}
@ -33,4 +36,8 @@ impl Account {
pub fn creation_time(&self) -> DateTime<Utc> {
self.creation_time
}
pub fn id(&self) -> UserID {
self.user_id
}
}

View file

@ -16,11 +16,23 @@ pub enum UserCreationError {
DBError(rusqlite::Error),
}
#[derive(Debug)]
pub enum HandleDBError {
HandleAlreadyExists,
DBError(rusqlite::Error),
}
impl From<rusqlite::Error> for UserCreationError {
fn from(value: rusqlite::Error) -> Self {
Self::DBError(value)
}
}
impl From<rusqlite::Error> for HandleDBError {
fn from(value: rusqlite::Error) -> Self {
Self::DBError(value)
}
}
impl std::error::Error for UserCreationError {}
impl Display for UserCreationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -35,6 +47,20 @@ impl Display for UserCreationError {
}
}
impl std::error::Error for HandleDBError {}
impl Display for HandleDBError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HandleDBError::HandleAlreadyExists => {
write!(f, "Handle already exists.")
}
HandleDBError::DBError(e) => {
write!(f, "DBError: {}", e)
}
}
}
}
impl Database {
pub fn new() -> Self {
let conn = Connection::open("user_db.db3").unwrap();
@ -44,7 +70,7 @@ impl Database {
// use the existing table instead
// NOTE: Look at the other possible errors here
let _val = conn.execute(
"CREATE TABLE users (
"CREATE TABLE user (
user_id INTEGER PRIMARY KEY,
username TINYTEXT NOT NULL,
password_hash TINYTEXT NOT NULL,
@ -55,19 +81,30 @@ impl Database {
(),
);
let _val = conn.execute(
"CREATE TABLE handle (
handle_id INTEGER PRIMARY KEY,
handle_val BIGINT UNSIGNED NOT NULL
CONSTRAINT fk_usr_handle FOREIGN KEY (user)
REFERENCES person (id)
)",
(),
);
Self { conn }
}
pub fn get_user(&self, username: &str) -> Result<Account> {
let (user_id, creation_time, premium): (UserID, DateTime<Utc>, bool) =
let (user_id, creation_time, premium, random): (UserID, DateTime<Utc>, bool, i64) =
self.conn.query_row(
"SELECT username, user_id, creation_time, is_premium FROM users WHERE username=?1",
"SELECT username, user_id, creation_time, is_premium, random_value FROM user WHERE username=?1",
[username],
|row| {
let user_id = row.get(1)?;
let creation_time = row.get(2)?;
let premium = row.get(3)?;
Ok((user_id, creation_time, premium))
let random = row.get(4)?;
Ok((user_id, creation_time, premium, random))
},
)?;
Ok(Account::new(
@ -75,6 +112,7 @@ impl Database {
user_id,
creation_time,
premium,
random,
))
}
@ -86,7 +124,7 @@ impl Database {
let num = rand::random::<u64>();
let password_hash = self.hash_password(password, creation_time, num);
self.conn.execute(
"INSERT INTO users (
"INSERT INTO user (
username,
password_hash,
creation_time,
@ -108,7 +146,7 @@ impl Database {
pub fn check_login(&self, username: &str, password: &str) -> bool {
let result = self.conn.query_row(
"SELECT creation_time, random_value, username FROM users WHERE username=?1",
"SELECT creation_time, random_value, username FROM user WHERE username=?1",
[username],
|row| {
let creation_time = row.get(0)?;
@ -121,7 +159,7 @@ impl Database {
}
let (creation_time, num) = result.unwrap();
let saved_password_hash: Result<Rc<str>> = self.conn.query_row(
"SELECT password_hash, username FROM users WHERE username=?1",
"SELECT password_hash, username FROM user WHERE username=?1",
[username],
|row| row.get::<usize, Rc<str>>(0),
);
@ -131,4 +169,28 @@ impl Database {
*saved_password_hash.unwrap() == self.hash_password(password, creation_time, num)
}
// HANDLE FUNCTIONS --------------------------------------------------
pub fn add_handle_to_db(&self, user: &Account, handle: u64) -> Result<(), HandleDBError> {
let saved_handle = self
.conn
.query_row(
"SELECT handle_val FROM handle WHERE handle_val=?1",
[handle],
|row| row.get::<usize, u64>(0),
)
.is_ok();
if saved_handle {
return Err(HandleDBError::HandleAlreadyExists);
}
self.conn.execute(
"INSERT INTO handle (
handle_val
fk_usr_handle
)
VALUES (?1, ?2)",
(handle, user.id()),
)?;
Ok(())
}
}

26
src/handle.rs Normal file
View file

@ -0,0 +1,26 @@
use crate::{
account::Account,
database::{Database, HandleDBError},
};
pub struct Handle(u64);
impl Handle {
pub fn new(user: &Account, db: Database) -> Result<Handle, HandleDBError> {
loop {
let num = rand::random::<u64>();
let res = db.add_handle_to_db(user, num);
match res {
Ok(_) => return Ok(Handle(num)),
Err(x) => match x {
HandleDBError::HandleAlreadyExists => continue,
HandleDBError::DBError(e) => return Err(HandleDBError::DBError(e)),
},
}
}
}
pub fn get(&self) -> u64 {
self.0
}
}

View file

@ -1 +0,0 @@

View file

@ -2,7 +2,7 @@ use routes::get_routes;
mod account;
mod database;
mod handlers;
mod handle;
mod routes;
#[tokio::main]

View file

@ -1,7 +1,7 @@
use chrono::{DateTime, Utc};
use warp::Filter;
use crate::database::Database;
use crate::{database::Database, handle::Handle};
pub fn get_routes() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
create_user().or(auth_user()).or(get_user())
@ -80,6 +80,7 @@ struct UserAuthRequest {
#[derive(serde::Serialize, serde::Deserialize)]
struct UserAuthResponse {
success: bool,
handle: Option<u64>,
message: String,
}
fn auth_user() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
@ -89,14 +90,17 @@ fn auth_user() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejectio
.map(|body: UserAuthRequest| {
let db = Database::new();
let reply = if db.check_login(&body.username, &body.password) {
let handle = Handle::new(&(db.get_user(&body.username).unwrap()), db).unwrap();
UserAuthResponse {
success: true,
message: "".to_string(),
handle: Some(handle.get()),
}
} else {
UserAuthResponse {
success: false,
message: "Username or Password is invalid".to_string(),
handle: None,
}
};
warp::reply::json(&reply)

Binary file not shown.