feat: added tcp

sorry Judah
This commit is contained in:
Andrew Rioux
2025-02-12 17:49:31 -05:00
parent e388b2eefa
commit f9ff9f266a
37 changed files with 1939 additions and 902 deletions
+68 -68
View File
@@ -1,7 +1,13 @@
use leptos::prelude::ServerFnError;
use leptos::{prelude::expect_context, server_fn::error::NoCustomError};
use leptos_axum::{extract, ResponseOptions};
use leptos::prelude::ServerFnError;
use pbkdf2::{Pbkdf2, password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, rand_core::{OsRng, RngCore}, SaltString}};
use pbkdf2::{
password_hash::{
rand_core::{OsRng, RngCore},
PasswordHash, PasswordHasher, PasswordVerifier, SaltString,
},
Pbkdf2,
};
use sqlx::SqlitePool;
use crate::error::Error;
@@ -11,7 +17,7 @@ pub struct User {
pub user_id: i64,
pub user_name: String,
password_hash: String,
pub last_active: Option<i64>
pub last_active: Option<i64>,
}
impl std::fmt::Debug for User {
@@ -29,12 +35,13 @@ async fn hash_password(pass: &[u8]) -> Result<String, Error> {
let pass = pass.to_owned();
let salt = SaltString::generate(&mut OsRng);
move ||
Pbkdf2.hash_password(
&*pass,
&salt,
).map(|hash| hash.serialize().as_str().to_string())
}).await??)
move || {
Pbkdf2
.hash_password(&*pass, &salt)
.map(|hash| hash.serialize().as_str().to_string())
}
})
.await??)
}
async fn verify_password(pass: &str, hash: &str) -> Result<bool, Error> {
@@ -42,46 +49,49 @@ async fn verify_password(pass: &str, hash: &str) -> Result<bool, Error> {
let pass = pass.to_owned();
let hash = hash.to_owned();
move ||
move || {
PasswordHash::new(&*hash)
.map(|parsed| Pbkdf2.verify_password(
&pass.as_bytes(),
&parsed
).is_ok())
}).await??)
.map(|parsed| Pbkdf2.verify_password(&pass.as_bytes(), &parsed).is_ok())
}
})
.await??)
}
pub async fn reset_password<'a, E>(pool: E, id: i16, password: String) -> Result<(), crate::error::Error>
pub async fn reset_password<'a, E>(
pool: E,
id: i16,
password: String,
) -> Result<(), crate::error::Error>
where
E: sqlx::SqliteExecutor<'a>
E: sqlx::SqliteExecutor<'a>,
{
let password_string = hash_password(
password.as_bytes()
).await?;
let password_string = hash_password(password.as_bytes()).await?;
sqlx::query!(
"UPDATE users SET password_hash = ? WHERE user_id = ?",
password_string,
id
)
.execute(pool)
.await?;
.execute(pool)
.await?;
Ok(())
}
pub async fn create_user<'a, E>(acq: E, name: String, password: String) -> Result<(), crate::error::Error>
pub async fn create_user<'a, E>(
acq: E,
name: String,
password: String,
) -> Result<(), crate::error::Error>
where
E: sqlx::Acquire<'a, Database = sqlx::Sqlite>
E: sqlx::Acquire<'a, Database = sqlx::Sqlite>,
{
let mut tx = acq.begin().await?;
let previous_user_check = sqlx::query_scalar!(
"SELECT COUNT(*) FROM users WHERE user_name = ?",
name
)
.fetch_one(&mut *tx)
.await?;
let previous_user_check =
sqlx::query_scalar!("SELECT COUNT(*) FROM users WHERE user_name = ?", name)
.fetch_one(&mut *tx)
.await?;
if previous_user_check > 0 {
return Err(Error::UserCreate("User already exists".to_string()));
@@ -93,9 +103,9 @@ where
r#"INSERT INTO users (user_name, password_hash) VALUES (?, "")"#,
name
)
.execute(&mut *tx)
.await?
.last_insert_rowid();
.execute(&mut *tx)
.await?
.last_insert_rowid();
reset_password(&mut *tx, new_id as i16, password).await?;
@@ -108,37 +118,30 @@ const SESSION_ID_KEY: &'static str = "session_id";
const SESSION_AGE: i64 = 30 * 60;
pub async fn create_auth_session(username: String, password: String) -> Result<(), ServerFnError> {
use axum_extra::extract::cookie::{Cookie, SameSite};
use axum::http::{header, HeaderValue};
use axum_extra::extract::cookie::{Cookie, SameSite};
let db = expect_context::<SqlitePool>();
let resp = expect_context::<ResponseOptions>();
let user: Option<User> = sqlx::query_as!(
User,
"SELECT * FROM users WHERE user_name = ?",
username
)
.fetch_optional(&db)
.await?;
let user: Option<User> =
sqlx::query_as!(User, "SELECT * FROM users WHERE user_name = ?", username)
.fetch_optional(&db)
.await?;
let Some(user) = user else {
return Err(ServerFnError::<NoCustomError>::ServerError("Invalid credentials".to_string()));
return Err(ServerFnError::<NoCustomError>::ServerError(
"Invalid credentials".to_string(),
));
};
let good_hash = verify_password(
&password,
&user.password_hash
).await?;
let good_hash = verify_password(&password, &user.password_hash).await?;
if good_hash {
let now = chrono::Utc::now().timestamp();
let expires = now + SESSION_AGE;
sqlx::query!(
"UPDATE users SET last_active = ?",
now
)
sqlx::query!("UPDATE users SET last_active = ?", now)
.execute(&db)
.await?;
@@ -146,7 +149,8 @@ pub async fn create_auth_session(username: String, password: String) -> Result<(
let mut key = [0u8; 32];
OsRng.fill_bytes(&mut key);
hex::encode(&key[..])
}).await?;
})
.await?;
sqlx::query!(
"INSERT INTO sessions (session_id, user_id, expires) VALUES (?, ?, ?)",
@@ -154,8 +158,8 @@ pub async fn create_auth_session(username: String, password: String) -> Result<(
user.user_id,
expires
)
.execute(&db)
.await?;
.execute(&db)
.await?;
let cookie = Cookie::build((SESSION_ID_KEY, &session_id))
.http_only(true)
@@ -168,7 +172,9 @@ pub async fn create_auth_session(username: String, password: String) -> Result<(
Ok(())
} else {
Err(ServerFnError::<NoCustomError>::ServerError("Invalid credentials".to_string()))
Err(ServerFnError::<NoCustomError>::ServerError(
"Invalid credentials".to_string(),
))
}
}
@@ -184,10 +190,7 @@ pub async fn destroy_auth_session() -> Result<(), ServerFnError> {
let session_id = cookie.value();
sqlx::query!(
"DELETE FROM sessions WHERE session_id = ?",
session_id
)
sqlx::query!("DELETE FROM sessions WHERE session_id = ?", session_id)
.execute(&db)
.await?;
@@ -217,8 +220,8 @@ pub async fn get_auth_session() -> Result<Option<User>, ServerFnError> {
session_id,
now
)
.fetch_optional(&db)
.await?;
.fetch_optional(&db)
.await?;
if let Some(u) = &user {
let now = chrono::Utc::now().timestamp();
@@ -229,22 +232,19 @@ pub async fn get_auth_session() -> Result<Option<User>, ServerFnError> {
now,
u.user_id
)
.execute(&db)
.await?;
.execute(&db)
.await?;
sqlx::query!(
"UPDATE sessions SET expires = ? WHERE session_id = ?",
expires,
session_id
)
.execute(&db)
.await?;
.execute(&db)
.await?;
}
sqlx::query!(
"DELETE FROM sessions WHERE expires < ?",
now
)
sqlx::query!("DELETE FROM sessions WHERE expires < ?", now)
.execute(&db)
.await?;