feat: added tcp
sorry Judah
This commit is contained in:
@@ -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?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user