docserver/src/defs/session.rs

403 lines
13 KiB
Rust

//use async_trait::async_trait;
use async_session::{Session, SessionStore,MemoryStore};
use async_sqlx_session::SqliteSessionStore;
// use axum::{
// http::{
// StatusCode,
// request::Parts,
// },
// extract::FromRequestParts,
// };
// use tower_cookies::Cookies;
use std::sync::{Arc,Mutex};
use rand_chacha::ChaCha8Rng;
pub type Random = Arc<Mutex<ChaCha8Rng>>;
use crate::{
// SESSION_COOKIE_NAME,
defs::{
FileStore,
AppDBs,
SESSION_ID,
USER_DATA,
},
users::{
User,
UserStatus,
},
};
#[derive(Clone)]
pub enum SessionStoreDB {
Files(FileStore),
SqlLite(SqliteSessionStore),
Memory(MemoryStore),
None,
}
/// In `SessionStoreDB` creation match the corresponding store to return it as item argument
impl SessionStoreDB {
pub fn connect_file_store(store: FileStore) -> Self{
SessionStoreDB::Files(store)
}
pub fn connect_memory_store() -> Self{
SessionStoreDB::Memory(MemoryStore::new())
}
pub fn connect_sqlite_store(store: SqliteSessionStore) -> Self{
SessionStoreDB::SqlLite(store)
}
pub async fn store_session_data(id: &str, user_data: &str, expire: u64, app_dbs: &AppDBs) -> String {
// dbg!("user_data: {}",&user_data);
let mut session = Session::new();
if ! id.is_empty() {
session.insert(SESSION_ID, id).unwrap_or_else(|e|{
println!("Error insert session {}",e);
});
}
if ! user_data.is_empty() {
session.insert(USER_DATA, user_data).unwrap_or_else(|e|{
println!("Error insert session {}",e);
});
}
if expire > 0 {
session.expire_in(std::time::Duration::from_secs(expire));
} else if app_dbs.config.session_expire > 0 {
session.expire_in(std::time::Duration::from_secs(app_dbs.config.session_expire));
}
//session.into_cookie_value().unwrap_or_default()
match app_dbs.sessions_store_db.to_owned() {
SessionStoreDB::Files(store) => {
store.store_session(session).await.unwrap_or_else(|e|{
println!("Error store session {}",e);
None
}).unwrap_or_default()
},
SessionStoreDB::SqlLite(store) => {
store.store_session(session).await.unwrap_or_else(|e|{
println!("Error store session {}",e);
None
}).unwrap_or_default()
},
SessionStoreDB::Memory(store) => {
store.store_session(session).await.unwrap_or_else(|e|{
println!("Error store session {}",e);
None
}).unwrap_or_default()
},
SessionStoreDB::None => {
String::from("")
},
}
}
pub async fn update_session_data(session: Session, app_dbs: &AppDBs) -> String {
//session.into_cookie_value().unwrap_or_default()
let cur_session = session.clone();
match app_dbs.sessions_store_db.to_owned() {
SessionStoreDB::Files(store) => {
store.store_session(session).await.unwrap_or_else(|e|{
println!("Error store session {}",e);
None
}).unwrap_or_default()
},
SessionStoreDB::SqlLite(store) => {
let _ = store.destroy_session(session).await;
store.store_session(cur_session).await.unwrap_or_else(|e|{
println!("Error store session {}",e);
None
}).unwrap_or_default()
},
SessionStoreDB::Memory(store) => {
store.store_session(session).await.unwrap_or_else(|e|{
println!("Error store session {}",e);
None
}).unwrap_or_default()
},
SessionStoreDB::None => {
String::from("")
},
}
}
pub async fn cleanup_data(app_dbs: &AppDBs) {
//session.into_cookie_value().unwrap_or_default()
match app_dbs.sessions_store_db.to_owned() {
SessionStoreDB::Files(store) => {
let _ = store.cleanup().await;
},
SessionStoreDB::SqlLite(store) => {
let _ = store.cleanup().await;
},
SessionStoreDB::Memory(store) => {
let _ = store.cleanup().await;
},
SessionStoreDB::None => {
},
}
}
}
#[derive(Clone, Default, Debug)]
pub struct AuthState{
pub session: Option<Session>,
pub user: Option<User>,
}
impl AuthState {
// pub fn new(session: Session, user: User) -> Self {
// let sid = session.get("sid").unwrap_or_default();
// let user_store = &app_dbs.user_store;
// let user = User::select("id", sid, user_store).await.unwrap_or_default();
// //let user = User::from_id(sid, app_dbs);
// Self {
// session,
// user
// }
// }
// pub fn sid(&self) -> String {
// if let Some(session) = &self.session {
// session.get("sid").unwrap_or_default()
// } else {
// String::from("")
// }
// }
pub fn id(&self) -> String {
if let Some(session) = &self.session {
session.id().to_owned()
} else {
String::from("")
}
}
#[allow(dead_code)]
pub fn ses_expired(&self) -> bool {
if let Some(session) = &self.session {
session.is_expired()
} else {
true
}
}
pub fn ses_destroyed(&self) -> bool {
if let Some(session) = &self.session {
session.is_destroyed()
} else {
true
}
}
pub fn destroy(&self) -> bool {
if let Some(mut session) = self.session.to_owned() {
session.destroy();
self.ses_destroyed()
} else {
true
}
}
#[allow(dead_code)]
pub fn ses_validate(&self) -> bool {
if let Some(session) = &self.session {
session.clone().validate().is_some()
} else {
false
}
}
pub fn user_data(&self) -> Vec<String> {
if let Some(session) = &self.session {
let user_data: String = session.get(USER_DATA).unwrap_or_default();
user_data.split("|").map(|s| s.to_string()).collect()
} else {
Vec::new()
}
}
pub fn user_id(&self) -> String {
let user_data = self.user_data();
if user_data.len() > 0 && user_data[0] != "0" {
user_data[0].to_owned()
} else {
String::from("")
}
}
pub fn user_name(&self) -> String {
let user_data = self.user_data();
if user_data.len() > 1 && user_data[1] != "" {
user_data[1].to_owned()
} else {
String::from("")
}
}
pub fn user_email(&self) -> String {
let user_data = self.user_data();
if user_data.len() > 2 && user_data[2] != "" {
user_data[2].to_owned()
} else {
String::from("")
}
}
pub fn user_roles(&self) -> String {
let user_data = self.user_data();
if user_data.len() > 3 && user_data[3] != "" {
user_data[3].to_owned()
} else {
String::from("")
}
}
pub fn user_items(&self) -> String {
let user_data = self.user_data();
if user_data.len() > 4 && user_data[4] != "" {
user_data[4].to_owned()
} else {
String::from("")
}
}
pub fn is_admin(&self) -> bool {
let user_data = self.user_data();
if user_data.len() > 5 && user_data[5] != "" {
user_data[5] == "true" || user_data[5] == "1"
} else {
false
}
}
#[allow(dead_code)]
pub fn user_status(&self) -> UserStatus {
let user_data = self.user_data();
if user_data.len() > 6 && user_data[6] != "" {
UserStatus::from_str(&user_data[6])
} else {
UserStatus::Unknown
}
}
pub fn has_auth_role(&self, auth_roles: &Vec<String>) -> bool {
let roles = self.user_roles();
for role in auth_roles.to_owned() {
if roles.contains(&role) {
return true;
}
}
return false;
}
pub async fn expire_in(&mut self, expire_secs: u64, app_dbs: &AppDBs ) -> Self {
if let Some(mut session) = self.session.to_owned() {
session.expire_in(std::time::Duration::from_secs(expire_secs));
let _ = SessionStoreDB::update_session_data(session.to_owned(),&app_dbs).await;
Self {
session: Some(session),
user: self.user.to_owned(),
}
} else {
self.to_owned()
}
}
#[allow(dead_code)]
pub async fn from_data(&self, app_dbs: &AppDBs) -> Self {
let user_id = self.user_id();
let user = if !user_id.is_empty() {
// dbg!(&user_id);
match User::select("id", &user_id, false, &app_dbs.user_store).await {
Ok(user) => Some(user),
Err(e) => {
println!("Error user {}: {:#}",&user_id,e);
None
}
}
} else {
None
};
// dbg!(&user);
Self {
session: self.session.to_owned(),
user,
}
}
pub async fn from_cookie(session_cookie: String, app_dbs: &AppDBs) -> Self {
let result_session = match app_dbs.sessions_store_db.to_owned() {
SessionStoreDB::Files(store) =>
store
.load_session(session_cookie)
.await
,
SessionStoreDB::SqlLite(store) =>
store
.load_session(session_cookie)
.await
,
SessionStoreDB::Memory(store) =>
store
.load_session(session_cookie.to_string())
.await
,
SessionStoreDB::None => {
dbg!("No store");
return AuthState::default();
},
};
// dbg!(&result_session);
match result_session {
Ok(op_session) => if let Some(session) = op_session {
if let Some(sid) = session.get::<String>("sid") {
// dbg!(
// "UserDataFromSession: session decoded success, user_data={}",
// &session
// );
let user_store = &app_dbs.user_store;
let user = User::select("id", &sid, false, user_store).await.unwrap_or_default();
return AuthState {
session: Some(session),
user: Some(user)
};
} else {
println!("No `sid` found in session");
}
},
Err(e) => {
println!("Error session {}", e);
}
}
AuthState::default()
}
}
/*
#[async_trait]
impl<S> FromRequestParts<S> for AuthState
where
S: Send + Sync,
{
type Rejection = (StatusCode, &'static str);
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
// let h = parts.headers.to_owned();
// dbg!(&h);
/*
if let Some(app_dbs) = parts.extensions.get::<Arc<AppDBs>>() {
if let Some(cookies) = parts.extensions.get::<Cookies>() {
if let Some(s_cookie) = cookies.get(SESSION_COOKIE_NAME) {
let session_cookie = s_cookie.to_string().replace(&format!("{}=",SESSION_COOKIE_NAME),"");
println!("From request parts cookie: {}",session_cookie);
// continue to decode the session cookie
// return Ok(
// AuthState::from_cookie(session_cookie, app_dbs).await
// );
}
}
}
*/
Ok(AuthState::default())
// Err((
// StatusCode::INTERNAL_SERVER_ERROR,
// "No `user_data` found in session",
// ))
// let cookie = Option::<Cookie>::g(parts, state);
// let cookie = Cookies::get(parts, state);
// if let Some(_user_agent) = parts.headers.get(USER_AGENT) {
// Ok(AuthState(None))
// } else {
// Err((StatusCode::BAD_REQUEST, "`User-Agent` header is missing"))
// }
// let cookie = Option::<TypedHeader<Cookie>>::from_request_parts(req, state)
//let cookies = Cookies::from(pa, state).await?;
// let info: String = cookies
// .get(SESSION_COOKIE_NAME)
// // .and_then(|c| c.value().parse().ok())
// .unwrap_or_default()
// ;
// dbg!(&info);
// //cookies.add(Cookie::new(COOKIE_NAME, visited.to_string()));
}
}
*/