185 lines
6.6 KiB
Rust
185 lines
6.6 KiB
Rust
use std::path::Path;
|
|
|
|
use super::{AppError, UserData};
|
|
use axum::{
|
|
body::Body,
|
|
extract::State,
|
|
http::Request,
|
|
middleware::Next,
|
|
response::{IntoResponse, Redirect},
|
|
};
|
|
use axum_extra::TypedHeader;
|
|
use chrono::Utc;
|
|
use headers::Cookie;
|
|
use sqlx::SqlitePool;
|
|
|
|
pub async fn inject_user_data(
|
|
State(db_pool): State<SqlitePool>,
|
|
cookie: Option<TypedHeader<Cookie>>,
|
|
mut request: Request<Body>,
|
|
next: Next,
|
|
) -> Result<impl IntoResponse, AppError> {
|
|
println!("Injecting user data");
|
|
if let Some(cookie) = cookie {
|
|
println!("{:#?}", cookie.get("session_token"));
|
|
if let Some(session_token) = cookie.get("session_token") {
|
|
println!("Found session token: {}", session_token);
|
|
let session_token: Vec<&str> = session_token.split('_').collect();
|
|
let query: Result<(i64, i64, String), _> = sqlx::query_as(
|
|
r#"SELECT user_id,expires_at,session_token_p2 FROM user_sessions WHERE session_token_p1=?"#,
|
|
)
|
|
.bind(session_token[0])
|
|
.fetch_one(&db_pool)
|
|
.await;
|
|
|
|
if let Ok(query) = query {
|
|
if let Ok(session_token_p2_db) = query.2.as_bytes().try_into() {
|
|
if let Ok(session_token_p2_cookie) = session_token
|
|
.get(1)
|
|
.copied()
|
|
.unwrap_or_default()
|
|
.as_bytes()
|
|
.try_into()
|
|
{
|
|
if constant_time_eq::constant_time_eq_n::<36>(
|
|
session_token_p2_cookie,
|
|
session_token_p2_db,
|
|
) {
|
|
let id = query.0;
|
|
println!("Found user: {}", id);
|
|
let expires_at = query.1;
|
|
if expires_at > Utc::now().timestamp() {
|
|
let row = sqlx::query_as!(
|
|
UserData,
|
|
"SELECT * FROM users WHERE id = ?",
|
|
id
|
|
)
|
|
.fetch_one(&db_pool)
|
|
.await?;
|
|
|
|
request.extensions_mut().insert(Some(UserData {
|
|
id: row.id,
|
|
email: row.email,
|
|
name: row.name,
|
|
family_name: row.family_name,
|
|
given_name: row.given_name,
|
|
}));
|
|
} else {
|
|
println!("Session expired");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(next.run(request).await)
|
|
}
|
|
|
|
pub async fn check_auth(
|
|
State(app_state): State<SqlitePool>,
|
|
request: Request<Body>,
|
|
next: Next,
|
|
) -> Result<impl IntoResponse, AppError> {
|
|
println!("check_auth");
|
|
println!("{:#?}", request);
|
|
if request
|
|
.extensions()
|
|
.get::<Option<UserData>>()
|
|
.ok_or("check_auth: extensions have no UserData")?
|
|
.is_some()
|
|
{
|
|
let path = &*request.uri().to_string();
|
|
println!("{}", path);
|
|
println!(
|
|
"{}",
|
|
&*request
|
|
.extensions()
|
|
.get::<Option<UserData>>()
|
|
.unwrap()
|
|
.as_ref()
|
|
.unwrap()
|
|
.email
|
|
);
|
|
|
|
let query: Result<(i64,), _> = match path {
|
|
"/profile" => {
|
|
sqlx::query_as(r#"select u.id from users u where email =?"#)
|
|
.bind(
|
|
request
|
|
.extensions()
|
|
.get::<Option<UserData>>()
|
|
.unwrap()
|
|
.as_ref()
|
|
.unwrap()
|
|
.email
|
|
.as_str(),
|
|
)
|
|
.fetch_one(&app_state)
|
|
.await
|
|
}
|
|
_ => {
|
|
// loop through path to find a permission
|
|
let mut remaining_path = Path::new(path);
|
|
loop {
|
|
let query: Result<(String,), _> = sqlx::query_as(r#"select r.item from role_permissions r join user_roles ur on ur.role_id = r.role_id join users u on u.id = ur.user_id where item = ? and email =?"#)
|
|
.bind(remaining_path.to_str().unwrap())
|
|
.bind(request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email.as_str())
|
|
.fetch_one(&app_state)
|
|
.await;
|
|
if let Ok(query) = query {
|
|
if query.0 != "" {
|
|
break;
|
|
}
|
|
}
|
|
if remaining_path.parent().is_none() {
|
|
break;
|
|
}
|
|
remaining_path = remaining_path.parent().unwrap();
|
|
|
|
println!("{}", remaining_path.to_str().unwrap());
|
|
}
|
|
sqlx::query_as(r#"select u.id from role_permissions r join user_roles ur on ur.role_id = r.role_id join users u on u.id = ur.user_id where item = ? and email =?"#)
|
|
.bind(remaining_path.to_str().unwrap())
|
|
.bind(request.extensions().get::<Option<UserData>>().unwrap().as_ref().unwrap().email.as_str())
|
|
.fetch_one(&app_state)
|
|
.await
|
|
}
|
|
};
|
|
|
|
// user is logged in
|
|
// check if user has the proper role
|
|
// if not, display banner and return to home page
|
|
let user_id = if let Ok(query) = query {
|
|
query.0
|
|
} else {
|
|
// user does not have the proper role
|
|
0
|
|
};
|
|
|
|
println!("{}", user_id);
|
|
if user_id == 0 {
|
|
// user does not have the proper role
|
|
// display banner and return to home page
|
|
return Ok(Redirect::to("/").into_response());
|
|
}
|
|
|
|
Ok(next.run(request).await)
|
|
} else {
|
|
// user is not logged in
|
|
// redirect to login page with return_url
|
|
let login_url = "/login?return_url=".to_owned() + &*request.uri().to_string();
|
|
Ok(Redirect::to(login_url.as_str()).into_response())
|
|
}
|
|
}
|
|
|
|
fn access_auth (_uri: &str, _userid: i64) {
|
|
// Check uri and userid for access and build the menu for links to the allowed resources
|
|
|
|
let _user_auth = true;
|
|
|
|
let _menu: Vec<String> = vec![];
|
|
|
|
|
|
} |