docserver/src/handlers/other_handlers.rs

225 lines
8.1 KiB
Rust

use std::sync::Arc;
use casbin::CoreApi;
use axum::{
extract::{Request,ConnectInfo},
http::{
StatusCode,
},
Extension,
response::{IntoResponse,Response,Redirect},
middleware::Next,
};
use tower_cookies::{Cookie, Cookies};
use crate::{
USER_AGENT,
SESSION_COOKIE_NAME,
defs::{
AppDBs,
ServPath,
AuthState,
SessionStoreDB,
TraceData,
TraceContent,
ReqHeaderMap,
AppConnectInfo,
},
};
/* // OLD get_cookie from Request
pub fn get_cookie(req: &Request) -> Option<u128> {
req
.headers()
.get_all("Cookie")
.iter()
.filter_map(|cookie| {
cookie
.to_str()
.ok()
.and_then(|cookie| cookie.parse::<Cookie>().ok())
})
.find_map(|cookie| {
(cookie.name() == SESSION_COOKIE_NAME).then(move || cookie.value().to_owned())
})
.and_then(|cookie_value| cookie_value.parse::<u128>().ok())
}
*/
pub async fn add_session_cookie(make: bool, cookies: &Cookies, session_token: &str, user_data: &str, expire: u64, app_dbs: &AppDBs, cookie_path: &str) -> String {
if make {
cookies.remove(Cookie::new(SESSION_COOKIE_NAME, ""));
}
let result_store = SessionStoreDB::store_session_data(&session_token,&user_data, expire, &app_dbs).await;
if result_store.is_empty() {
eprintln!("Unable to store session {}", &app_dbs.config.session_store_uri);
} else {
let cookie = Cookie::build(SESSION_COOKIE_NAME, result_store.to_owned())
// .domain(domain)
.path(format!("{}",cookie_path))
.secure(true)
.http_only(true)
.finish();
if make {
cookies.add(cookie);
}
}
result_store
}
pub async fn get_auth_state(update: bool, cookies: &Cookies, app_dbs: &AppDBs) -> AuthState {
if let Some(s_cookie) = cookies.get(SESSION_COOKIE_NAME) {
let session_cookie = s_cookie.to_string().replace(&format!("{}=",SESSION_COOKIE_NAME),"");
let mut auth_state = AuthState::from_cookie(session_cookie.to_string(), app_dbs).await;
if update {
let _ = auth_state.expire_in(app_dbs.config.session_expire, &app_dbs).await;
}
auth_state
} else {
// eprintln!("get_auth_state: No SESSION COOKIE found ");
AuthState::default()
}
}
pub fn trace_req(uri_path: &str, user_id: String, sid: String, info: String, context: String, role: String, req_header: ReqHeaderMap, app_dbs: &AppDBs) -> std::io::Result<()> {
let timestamp = chrono::Utc::now().timestamp().to_string();
let trace_content = TraceContent{
when: timestamp.to_owned(),
sid,
origin: uri_path.to_owned(),
trigger: String::from("req_handler"),
id: user_id.to_owned(),
info: info.to_owned(),
context,
role,
req: req_header.req_info(),
};
let trace_data = TraceData{
user_id,
timestamp,
contents: vec![trace_content]
};
trace_data.save(&app_dbs.config,false)
}
pub async fn rewrite_request_uri(
Extension(app_dbs): Extension<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
req: Request, next: Next,
) -> Result<impl IntoResponse, Response> {
// TODO Trace acccess to log or user session file !!!
let auth_state = get_auth_state(true, &cookies, &app_dbs).await;
let uri_path = req.uri().path().to_owned();
if uri_path == "/" {
return Ok(next.run(req).await);
}
// For long path is better than:
// let arr_root_path: Vec<String> = uri_path.split("/").map(|s| s.to_string()).collect();
// let root_path = arr_root_path[1].to_owned();
let mut root_path = String::from("/");
for it in uri_path.split("/") {
if ! it.is_empty() {
root_path = format!("/{}",it.to_owned());
break;
}
}
let serv_paths: Vec<ServPath> = app_dbs.config.serv_paths.clone().into_iter().filter(
|it| it.is_restricted && it.url_path == root_path
).collect();
// Only on First one
if serv_paths.len() > 0 {
let serv_path = serv_paths[0].to_owned();
let name = auth_state.user_name();
if name.is_empty() {
let uri_path = req.uri().path().to_string();
if uri_path.ends_with(".html") {
eprintln!("rewrite_request_uri: No user found in session for {}", &uri_path);
let new_uri = format!("{}?o={}",&serv_path.not_auth.as_str(),req.uri().path().to_string());
let _ = trace_req(&uri_path, auth_state.user_id(),auth_state.id(),
format!("user no name found in session"), String::from("rewrite_request_uri"),
auth_state.user_roles(),
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
&app_dbs);
return Err(
Redirect::temporary( &new_uri).into_response()
);
} else {
return Ok(next.run(req).await);
}
}
let arr_roles: Vec<String> = auth_state.user_roles().split(",").map(|s| s.replace(" ", "").to_string()).collect();
let req_method = req.method().to_string();
let target_path = serv_path.url_path.to_owned();
let enforcer = app_dbs.enforcer.clone();
for role in arr_roles {
let mut lock = enforcer.write().await;
let result = lock.enforce_mut(
vec![role.to_owned(),target_path.to_owned(), req_method.to_owned()]
).unwrap_or_else(|e|{
println!("Error enforce: {}",e);
false
});
drop(lock);
if result {
if uri_path.ends_with(".html") || app_dbs.config.trace_level > 1 {
let _ = trace_req(&uri_path,auth_state.user_id(),auth_state.id(),
format!("user in session with role {}",role),
String::from("rewrite_request_uri"),
auth_state.user_roles(),
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
&app_dbs);
}
return Ok(next.run(req).await);
}
}
// try with email
let mut lock = enforcer.write().await;
let result = lock.enforce_mut(
vec![
name,
target_path.to_owned(),
req_method.to_owned()
]
).unwrap_or_else(|e|{
println!("Error enforce: {}",e);
false
});
drop(lock);
if result { return Ok(next.run(req).await); }
let new_uri = format!("{}",serv_path.not_auth);
let agent = if let Some(user_agent) = req.headers().get(USER_AGENT) {
user_agent.to_str().unwrap_or("").to_owned()
} else {
String::from("")
};
if uri_path.ends_with(".html") || app_dbs.config.trace_level > 1 {
let _ = trace_req(&uri_path,auth_state.user_id(),auth_state.id(),
format!("user found in session"),
String::from("rewrite_request_uri"),
auth_state.user_roles(),
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
&app_dbs);
}
if agent.contains("curl") {
return Ok(
format!("Got to {}",&new_uri).into_response()
);
} else {
return Err(
Redirect::temporary(&new_uri).into_response()
);
}
}
if uri_path.ends_with(".html") || app_dbs.config.trace_level > 1 {
let _ = trace_req(&uri_path,auth_state.user_id(),auth_state.id(),
format!("user in session"),
String::from("rewrite_request_uri"),
auth_state.user_roles(),
ReqHeaderMap::new(req.headers().to_owned(), &uri_path, &app_connect_info),
&app_dbs);
}
Ok(next.run(req).await)
}
pub async fn handle_404(_req: Request) -> (StatusCode, &'static str) {
(StatusCode::NOT_FOUND, "Not found")
}