This commit is contained in:
2025-09-07 00:12:52 +03:00
parent 81e68770c6
commit 111bcedf2c
7 changed files with 256 additions and 17 deletions

View File

@@ -1,17 +1,82 @@
use axum::{
body::Body,
extract::State,
http::{HeaderMap, HeaderValue, StatusCode},
response::{IntoResponse, Response},
use argon2::{
Argon2, Params,
password_hash::{PasswordHasher, SaltString, rand_core::OsRng},
};
use axum::{
extract::{Json, State},
http::{Response, StatusCode},
};
use base64::{Engine as _, engine::general_purpose};
use serde::Deserialize;
use time::{Duration, OffsetDateTime};
use crate::db::Database;
pub async fn route(State(db): State<Database>) -> Response {
#[derive(Debug, Clone, Deserialize)]
pub struct ReqBody {
email: String,
username: String,
password: String,
}
pub async fn route(State(db): State<Database>, Json(body): Json<ReqBody>) -> Response<String> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::new(
argon2::Algorithm::Argon2id,
argon2::Version::V0x13,
Params::DEFAULT,
);
let hash = argon2
.hash_password(body.password.as_bytes(), salt.as_salt())
.unwrap()
.to_string();
let mut user = crate::db::tables::user::User::default();
user.username = body.username;
user.email = body.email;
user.pw_salt = salt.to_string();
user.pw_hash = hash;
if let Err(e) = user.insert_new(&db.pool()).await {
return Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("ERROR: Failed to create user: {e}"))
.unwrap();
}
let Ok(user) = crate::db::tables::user::User::get_by_username(&db.pool(), user.username).await
else {
return Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(String::from("ERROR: Failed to get created user"))
.unwrap();
};
let session_key = {
let mut buf = [0u8; 32];
rand::fill(&mut buf);
general_purpose::STANDARD.encode(&buf)
};
let mut session = crate::db::tables::sessions::Session::default();
session.user_id = user.id;
session.session_key = session_key;
session.expires = OffsetDateTime::now_utc()
.saturating_add(Duration::days(30))
.unix_timestamp();
if let Err(e) = session.insert_new(db.pool()).await {
return Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(format!("ERROR: Failed to create session for user: {e}",))
.unwrap();
};
Response::builder()
.header("Location", "/")
.header("Set-Cookie", &format!("session=meowmeowmeow"))
.header("Set-Cookie", &format!("session={}", session.session_key))
.status(StatusCode::SEE_OTHER)
.body(Body::empty())
.body(String::new())
.unwrap()
}

View File

@@ -1 +1,2 @@
pub mod sessions;
pub mod user;

58
src/db/tables/sessions.rs Normal file
View File

@@ -0,0 +1,58 @@
use anyhow::Result;
use crate::db::CurrPool;
#[derive(Debug, Default, Clone)]
pub struct Session {
pub user_id: i64,
pub session_key: String,
pub expires: i64,
}
impl Session {
pub async fn insert_new(&self, pool: &CurrPool) -> Result<Self> {
let session = sqlx::query_as!(
Session,
r#"
INSERT INTO sessions (user_id, session_key, expires)
VALUES ($1, $2, $3)
RETURNING *
"#,
self.user_id,
self.session_key,
self.expires
)
.fetch_one(pool)
.await?;
Ok(session)
}
pub async fn get_by_username(pool: &CurrPool, user_id: i64) -> anyhow::Result<Self> {
let session = sqlx::query_as!(
Session,
"SELECT * FROM sessions WHERE user_id = $1",
user_id
)
.fetch_one(pool)
.await?;
Ok(session)
}
pub async fn get_by_session_key(pool: &CurrPool, session_key: String) -> anyhow::Result<Self> {
let session = sqlx::query_as!(
Session,
"SELECT * FROM sessions WHERE session_key = $1",
session_key
)
.fetch_one(pool)
.await?;
Ok(session)
}
pub async fn remove_old_sessions(pool: &CurrPool) -> anyhow::Result<()> {
let curr_time = time::OffsetDateTime::now_utc().unix_timestamp();
sqlx::query!("DELETE FROM sessions WHERE expires < $1", curr_time)
.execute(pool)
.await?;
Ok(())
}
}