Bugfixes
This commit is contained in:
@@ -27,3 +27,6 @@ frontend/node_modules/
|
|||||||
|
|
||||||
/target
|
/target
|
||||||
.antigravitycli/
|
.antigravitycli/
|
||||||
|
.sqlx/
|
||||||
|
backend/.sqlx/
|
||||||
|
dist/
|
||||||
|
|||||||
+51
-12
@@ -4,14 +4,15 @@ use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier, password_ha
|
|||||||
use axum::{
|
use axum::{
|
||||||
Json,
|
Json,
|
||||||
extract::{Query, State},
|
extract::{Query, State},
|
||||||
http::StatusCode,
|
http::{StatusCode, header::SET_COOKIE},
|
||||||
response::{IntoResponse, Redirect},
|
response::{Html, IntoResponse, Response},
|
||||||
};
|
};
|
||||||
|
use jsonwebtoken::{EncodingKey, Header};
|
||||||
use rand::{RngCore, thread_rng};
|
use rand::{RngCore, thread_rng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::Row;
|
use sqlx::Row;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::{AppState, cookie::jwt::encode_token};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct QrCodeResponse {
|
pub struct QrCodeResponse {
|
||||||
@@ -57,12 +58,15 @@ pub async fn generate_qr_token(
|
|||||||
pub async fn validate_qr_token(
|
pub async fn validate_qr_token(
|
||||||
State(data): State<Arc<AppState>>,
|
State(data): State<Arc<AppState>>,
|
||||||
Query(params): Query<AuthQuery>,
|
Query(params): Query<AuthQuery>,
|
||||||
) -> Result<impl IntoResponse, StatusCode> {
|
) -> Response {
|
||||||
println!("Incoming token: {}", params.token);
|
let active_tokens_res = sqlx::query("SELECT user_id, token_hash FROM qr_codes")
|
||||||
let active_tokens = sqlx::query("SELECT user_id, token_hash FROM qr_codes")
|
|
||||||
.fetch_all(&data.db)
|
.fetch_all(&data.db)
|
||||||
.await
|
.await;
|
||||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
||||||
|
let active_tokens = match active_tokens_res {
|
||||||
|
Ok(tokens) => tokens,
|
||||||
|
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
|
||||||
|
};
|
||||||
|
|
||||||
let mut authenticated_user_id: Option<i16> = None;
|
let mut authenticated_user_id: Option<i16> = None;
|
||||||
let argon2 = Argon2::default();
|
let argon2 = Argon2::default();
|
||||||
@@ -82,10 +86,45 @@ pub async fn validate_qr_token(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(_user_id) = authenticated_user_id {
|
if let Some(user_id) = authenticated_user_id {
|
||||||
let redirect_url = format!("{}/", data.env.origin.trim_end_matches('/'));
|
let base_origin = data.env.origin.trim_end_matches('/');
|
||||||
Ok(Redirect::to(&redirect_url))
|
|
||||||
|
let header = Header::default();
|
||||||
|
let id_str = user_id.to_string();
|
||||||
|
let secret_bytes = data.env.token_secret.as_bytes();
|
||||||
|
let encoding_key = EncodingKey::from_secret(secret_bytes);
|
||||||
|
|
||||||
|
let token = encode_token(&header, id_str, &encoding_key);
|
||||||
|
|
||||||
|
let cookie_value = format!(
|
||||||
|
"token={}; Path=/; HttpOnly; SameSite=Lax; Max-Age=3600",
|
||||||
|
token
|
||||||
|
);
|
||||||
|
|
||||||
|
let redirect_html = format!(
|
||||||
|
r#"<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; url={}/" />
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.location.href = "{}/"
|
||||||
|
</script>
|
||||||
|
<title>Redirecting...</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Authenticated! Redirecting you to the dashboard...</p>
|
||||||
|
</body>
|
||||||
|
</html>"#,
|
||||||
|
base_origin, base_origin
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut response = Html(redirect_html).into_response();
|
||||||
|
if let Ok(header_value) = axum::http::HeaderValue::from_str(&cookie_value) {
|
||||||
|
response.headers_mut().insert(SET_COOKIE, header_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
} else {
|
} else {
|
||||||
Err(StatusCode::UNAUTHORIZED)
|
StatusCode::UNAUTHORIZED.into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -1,7 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
Router, middleware,
|
Router,
|
||||||
|
http::StatusCode,
|
||||||
|
middleware,
|
||||||
|
response::IntoResponse,
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,6 +21,14 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async fn debug_fallback_handler(uri: axum::http::Uri) -> impl IntoResponse {
|
||||||
|
println!(
|
||||||
|
"[BACKEND DEBUG] Axum Fallback triggered! Unmatched request path: {}",
|
||||||
|
uri
|
||||||
|
);
|
||||||
|
(StatusCode::NOT_FOUND, "Backend route not found")
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates the complete router with all API endpoints.
|
/// Creates the complete router with all API endpoints.
|
||||||
///
|
///
|
||||||
/// The router is organized in layers for proper middleware application. Uses [`AppState`]
|
/// The router is organized in layers for proper middleware application. Uses [`AppState`]
|
||||||
@@ -90,5 +101,6 @@ pub fn create_router(state: Arc<AppState>) -> Router {
|
|||||||
Router::new()
|
Router::new()
|
||||||
.merge(protected_routes)
|
.merge(protected_routes)
|
||||||
.merge(public_routes)
|
.merge(public_routes)
|
||||||
|
.fallback(debug_fallback_handler)
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<link data-trunk rel="rust" data-bin="bin" />
|
<link data-trunk rel="rust" data-bin="bin" />
|
||||||
<link data-trunk rel="scss" href="src/styles/main.scss" />
|
<link data-trunk rel="scss" href="src/styles/main.scss" />
|
||||||
<link data-trunk rel="icon" href="src/assets/favicon.ico" type="image/x-icon" />
|
<link data-trunk rel="icon" href="src/assets/favicon.ico" type="image/x-icon" />
|
||||||
<link data-trunk rel="copy-dir" href="src/assets" />
|
<link data-trunk rel="copy-dir" href="src/assets" data-target-path="assets" />
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Yew App</title>
|
<title>Yew App</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -136,6 +136,6 @@ pub fn denied_component() -> Html {
|
|||||||
#[component(Icon)]
|
#[component(Icon)]
|
||||||
pub fn icon_component() -> Html {
|
pub fn icon_component() -> Html {
|
||||||
html! {
|
html! {
|
||||||
<img src="assets/csg.png" class="csg-icon" />
|
<img src="/assets/csg.png" class="csg-icon" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user