Refractored code and implemented logout
This commit is contained in:
parent
6395df6cec
commit
9eb92ffff1
49
devenv.lock
49
devenv.lock
@ -31,10 +31,31 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"git-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1737465171,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"gitignore": {
|
"gitignore": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"pre-commit-hooks",
|
"git-hooks",
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -66,32 +87,14 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pre-commit-hooks": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"gitignore": "gitignore",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1735882644,
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"rev": "a5a961387e75ae44cc20f0a57ae463da5e959656",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"devenv": "devenv",
|
"devenv": "devenv",
|
||||||
|
"git-hooks": "git-hooks",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"pre-commit-hooks": "pre-commit-hooks"
|
"pre-commit-hooks": [
|
||||||
|
"git-hooks"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -11,21 +11,12 @@ use rand_chacha::ChaCha20Rng;
|
|||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
|
||||||
use crate::{
|
use crate::{database::model::Session, model::User};
|
||||||
database::model::Session,
|
|
||||||
model::User,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
pub async fn get_user_from_header(pool: &PgPool, headers: &HeaderMap) -> Result<User, AuthError> {
|
pub async fn get_user_from_header(pool: &PgPool, headers: &HeaderMap) -> Result<User, AuthError> {
|
||||||
let bearer_value = headers.get(header::AUTHORIZATION);
|
let token = get_token_from_headers(&headers)?;
|
||||||
let bearer_value = bearer_value
|
|
||||||
.ok_or(AuthError::InvalidToken)?
|
|
||||||
.to_str()
|
|
||||||
.map_err(|_| AuthError::InvalidToken)?;
|
|
||||||
|
|
||||||
let token = get_token_from_bearer(bearer_value)?;
|
|
||||||
|
|
||||||
let session = match Session::from_token(pool, &token).await {
|
let session = match Session::from_token(pool, &token).await {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
@ -44,7 +35,13 @@ pub async fn get_user_from_header(pool: &PgPool, headers: &HeaderMap) -> Result<
|
|||||||
Ok(db_user.into())
|
Ok(db_user.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_token_from_bearer(bearer: &str) -> Result<String, AuthError> {
|
pub fn get_token_from_headers(headers: &HeaderMap) -> Result<String, AuthError> {
|
||||||
|
let bearer = headers.get(header::AUTHORIZATION);
|
||||||
|
let bearer = bearer
|
||||||
|
.ok_or(AuthError::InvalidToken)?
|
||||||
|
.to_str()
|
||||||
|
.map_err(|_| AuthError::InvalidToken)?;
|
||||||
|
|
||||||
match bearer.strip_prefix("Bearer ") {
|
match bearer.strip_prefix("Bearer ") {
|
||||||
Some(token) => Ok(token.to_string()),
|
Some(token) => Ok(token.to_string()),
|
||||||
None => Err(AuthError::InvalidToken),
|
None => Err(AuthError::InvalidToken),
|
||||||
|
@ -43,4 +43,54 @@ impl Session {
|
|||||||
|
|
||||||
Ok(session)
|
Ok(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn remove_many(
|
||||||
|
session_ids: &[uuid::Uuid],
|
||||||
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
|
) -> Result<(), sqlx::Error> {
|
||||||
|
let deleted_count = sqlx::query_scalar!(
|
||||||
|
"
|
||||||
|
WITH deleted AS (
|
||||||
|
DELETE FROM sessions
|
||||||
|
WHERE session_id = ANY($1)
|
||||||
|
RETURNING 1
|
||||||
|
)
|
||||||
|
SELECT COUNT(*) FROM deleted
|
||||||
|
",
|
||||||
|
session_ids
|
||||||
|
)
|
||||||
|
.fetch_one(&mut **transaction)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !deleted_count.is_some_and(|c| c >= 1) {
|
||||||
|
return Err(sqlx::Error::RowNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn remove_many_from_token(
|
||||||
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
|
session_tokens: &[String],
|
||||||
|
) -> Result<(), sqlx::Error> {
|
||||||
|
let deleted_count = sqlx::query_scalar!(
|
||||||
|
"
|
||||||
|
WITH deleted AS (
|
||||||
|
DELETE FROM sessions
|
||||||
|
WHERE token = ANY($1)
|
||||||
|
RETURNING 1
|
||||||
|
)
|
||||||
|
SELECT COUNT(*) FROM deleted
|
||||||
|
",
|
||||||
|
session_tokens
|
||||||
|
)
|
||||||
|
.fetch_one(&mut **transaction)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if !deleted_count.is_some_and(|c| c >= 1) {
|
||||||
|
return Err(sqlx::Error::RowNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use axum::http::HeaderMap;
|
use axum::http::HeaderMap;
|
||||||
use axum::{extract::State, routing::post, Json, Router};
|
use axum::{
|
||||||
|
extract::State,
|
||||||
|
routing::{get, post},
|
||||||
|
Json, Router,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::auth::verify_password_hash;
|
use crate::auth::{get_token_from_headers, verify_password_hash};
|
||||||
use crate::auth::{get_user_from_header, AuthError};
|
use crate::auth::{get_user_from_header, AuthError};
|
||||||
use crate::database::model::user::UpdateUser;
|
use crate::database::model::user::UpdateUser;
|
||||||
use crate::database::model::Member as DbMember;
|
use crate::database::model::Member as DbMember;
|
||||||
@ -16,6 +20,7 @@ pub fn routes() -> Router<AppState> {
|
|||||||
Router::new()
|
Router::new()
|
||||||
.route("/auth/login", post(login))
|
.route("/auth/login", post(login))
|
||||||
.route("/auth/register", post(register))
|
.route("/auth/register", post(register))
|
||||||
|
.route("/auth/logout", get(logout))
|
||||||
.route("/auth/change_password", post(change_password))
|
.route("/auth/change_password", post(change_password))
|
||||||
.route("/auth/change_email", post(change_email))
|
.route("/auth/change_email", post(change_email))
|
||||||
}
|
}
|
||||||
@ -88,6 +93,18 @@ pub async fn register(
|
|||||||
Ok(db_session.token)
|
Ok(db_session.token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn logout(State(state): State<AppState>, headers: HeaderMap) -> Result<(), crate::Error> {
|
||||||
|
let registration_token = get_token_from_headers(&headers)?;
|
||||||
|
|
||||||
|
let mut transaction = state.pool.begin().await?;
|
||||||
|
|
||||||
|
DbSession::remove_many_from_token(&mut transaction, &[registration_token]).await?;
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct ChangePasswordRequest {
|
pub struct ChangePasswordRequest {
|
||||||
pub old_password: String,
|
pub old_password: String,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user