Added session creating

This commit is contained in:
xeovalyte 2025-02-03 09:34:30 +01:00
parent 30bf08986d
commit 36c785e8f2
Signed by: xeovalyte
SSH Key Fingerprint: SHA256:GWI1hq+MNKR2UOcvk7n9tekASXT8vyazK7vDF9Xyciw
9 changed files with 140 additions and 14 deletions

5
server/Cargo.lock generated
View File

@ -1650,6 +1650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0"
dependencies = [ dependencies = [
"bytes", "bytes",
"chrono",
"crc", "crc",
"crossbeam-queue", "crossbeam-queue",
"either", "either",
@ -1727,6 +1728,7 @@ dependencies = [
"bitflags", "bitflags",
"byteorder", "byteorder",
"bytes", "bytes",
"chrono",
"crc", "crc",
"digest", "digest",
"dotenvy", "dotenvy",
@ -1769,6 +1771,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bitflags", "bitflags",
"byteorder", "byteorder",
"chrono",
"crc", "crc",
"dotenvy", "dotenvy",
"etcetera", "etcetera",
@ -1804,6 +1807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540"
dependencies = [ dependencies = [
"atoi", "atoi",
"chrono",
"flume", "flume",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -2474,6 +2478,7 @@ dependencies = [
"dotenvy", "dotenvy",
"itertools", "itertools",
"rand 0.9.0", "rand 0.9.0",
"rand_chacha 0.9.0",
"serde", "serde",
"serde_json", "serde_json",
"sqlx", "sqlx",

View File

@ -8,7 +8,7 @@ edition = "2021"
axum = { version = "0.8", features = [ "macros", "json" ] } axum = { version = "0.8", features = [ "macros", "json" ] }
axum-extra = { version = "0.10.0", features = [ "typed-header" ] } axum-extra = { version = "0.10.0", features = [ "typed-header" ] }
tokio = { version = "1.43", features = [ "rt-multi-thread", "macros" ] } tokio = { version = "1.43", features = [ "rt-multi-thread", "macros" ] }
sqlx = { version = "0.8", features = [ "runtime-tokio", "postgres", "uuid" ] } sqlx = { version = "0.8", features = [ "runtime-tokio", "postgres", "uuid", "chrono" ] }
# Secondary crates # Secondary crates
csv = { version = "1.3" } csv = { version = "1.3" }
@ -21,10 +21,11 @@ argon2 = "0.5"
# Tertiary crates # Tertiary crates
tracing = "0.1" tracing = "0.1"
tracing-subscriber = "0.3" tracing-subscriber = "0.3"
chrono = "0.4.39" chrono = "0.4"
uuid = { version = "1.12.0", features = ["v4", "fast-rng"] } uuid = { version = "1.12", features = ["v4", "fast-rng"] }
serde_json = "1.0.137" serde_json = "1.0.137"
rand = "0.9" rand = "0.9"
rand_chacha = "0.9"
thiserror = { version = "2.0" } thiserror = { version = "2.0" }
itertools = "0.14" itertools = "0.14"

View File

@ -0,0 +1,7 @@
CREATE TABLE "sessions" (
session_id uuid NOT NULL PRIMARY KEY,
user_id uuid NOT NULL REFERENCES users (user_id) ON UPDATE cascade ON DELETE cascade,
token text NOT NULL UNIQUE,
expires_at timestamptz NOT NULL,
created_at timestamptz NOT NULL
);

View File

@ -12,6 +12,9 @@ use axum_extra::{
}; };
use bearer::verify_bearer; use bearer::verify_bearer;
pub use error::AuthError; pub use error::AuthError;
use rand::distr::Alphanumeric;
use rand::prelude::*;
use rand_chacha::ChaCha20Rng;
use tokio::task; use tokio::task;
mod bearer; mod bearer;
@ -72,3 +75,13 @@ pub async fn generate_password_hash(
Ok(password_hash?) Ok(password_hash?)
} }
pub fn generate_session_token() -> String {
let session = ChaCha20Rng::from_os_rng()
.sample_iter(&Alphanumeric)
.take(60)
.map(char::from)
.collect::<String>();
session
}

View File

@ -3,5 +3,6 @@ pub mod session;
pub mod user; pub mod user;
pub use member::Member; pub use member::Member;
pub use session::Session;
pub use user::User; pub use user::User;
pub use user::UserMember; pub use user::UserMember;

View File

@ -1,6 +1,37 @@
struct Session { use chrono::{DateTime, Utc};
id: u32, use sqlx::Postgres;
user_id: u32,
token: String, pub struct Session {
expires: chrono::NaiveDateTime, pub session_id: uuid::Uuid,
pub user_id: uuid::Uuid,
pub token: String,
pub expires_at: DateTime<Utc>,
pub created_at: DateTime<Utc>,
}
impl Session {
pub async fn insert(
&self,
transaction: &mut sqlx::Transaction<'_, Postgres>,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"
INSERT INTO sessions (
session_id, user_id, token, expires_at, created_at
)
VALUES (
$1, $2, $3, $4, $5
)
",
&self.session_id,
&self.user_id,
&self.token,
&self.expires_at,
&self.created_at
)
.execute(&mut **transaction)
.await?;
Ok(())
}
} }

View File

@ -0,0 +1,54 @@
use chrono::{DateTime, Duration, Utc};
use crate::auth::generate_session_token;
pub struct Session {
pub session_id: uuid::Uuid,
pub user_id: uuid::Uuid,
pub token: String,
pub expires_at: DateTime<Utc>,
pub created_at: DateTime<Utc>,
}
impl Session {
pub fn new(user_id: uuid::Uuid) -> Self {
let session_id = uuid::Uuid::new_v4();
let token = generate_session_token();
let created_at = Utc::now();
let expires_at = Utc::now() + Duration::days(7);
return Self {
session_id,
user_id,
token,
expires_at,
created_at,
};
}
}
use crate::database::model::Session as DbSession;
impl From<DbSession> for Session {
fn from(db_session: DbSession) -> Self {
Self {
session_id: db_session.session_id,
user_id: db_session.user_id,
token: db_session.token,
expires_at: db_session.expires_at,
created_at: db_session.created_at,
}
}
}
impl From<Session> for DbSession {
fn from(session: Session) -> Self {
Self {
session_id: session.session_id,
user_id: session.user_id,
token: session.token,
expires_at: session.expires_at,
created_at: session.created_at,
}
}
}

View File

@ -2,8 +2,10 @@ use axum::{extract::State, routing::post, Json, Router};
use crate::database::model::member::SearchMember; use crate::database::model::member::SearchMember;
use crate::database::model::Member as DbMember; use crate::database::model::Member as DbMember;
use crate::database::model::Session as DbSession;
use crate::database::model::User as DbUser; use crate::database::model::User as DbUser;
use crate::database::model::UserMember as DbUserMember; use crate::database::model::UserMember as DbUserMember;
use crate::model::session::Session;
use crate::{ use crate::{
auth::{generate_password_hash, Permissions}, auth::{generate_password_hash, Permissions},
AppState, AppState,
@ -34,7 +36,7 @@ pub async fn register<'a>(
State(state): State<AppState>, State(state): State<AppState>,
permissions: Permissions<'a>, permissions: Permissions<'a>,
Json(auth_request): Json<AuthRequest>, Json(auth_request): Json<AuthRequest>,
) -> Result<(), crate::Error> { ) -> Result<String, crate::Error> {
// Get all the members to link with the user // Get all the members to link with the user
let members = DbMember::search( let members = DbMember::search(
&state.pool, &state.pool,
@ -61,7 +63,11 @@ pub async fn register<'a>(
let user_ids: Vec<uuid::Uuid> = vec![user_id; member_ids.len()]; let user_ids: Vec<uuid::Uuid> = vec![user_id; member_ids.len()];
DbUserMember::insert_many(&mut transaction, &user_ids, &member_ids).await?; DbUserMember::insert_many(&mut transaction, &user_ids, &member_ids).await?;
// Create a new session
let db_session: DbSession = Session::new(user_id).into();
db_session.insert(&mut transaction).await?;
transaction.commit().await?; transaction.commit().await?;
Ok(()) Ok(db_session.token)
} }

View File

@ -1,11 +1,19 @@
use axum::{routing::post, Router}; use axum::{extract::State, routing::post, Router};
use crate::AppState; use crate::{auth::Permissions, AppState};
pub mod migrate; pub mod migrate;
pub fn routes() -> Router<AppState> { pub fn routes() -> Router<AppState> {
Router::new() Router::new()
.route("/members/migrate_request", post(migrate::migrate_request)) // .route("/members/migrate_request", post(migrate::migrate_request))
.route("/members/migrate_confirm", post(migrate::migrate_confirm)) // .route("/members/migrate_confirm", post(migrate::migrate_confirm))
}
pub async fn get_members<'a>(
State(state): State<AppState>,
permissions: Permissions<'a>,
body: String,
) -> Result<(), crate::Error> {
Ok(())
} }