:3
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub mod sessions;
|
||||
pub mod user;
|
||||
|
||||
58
src/db/tables/sessions.rs
Normal file
58
src/db/tables/sessions.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user