403 lines
13 KiB
Rust
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()));
|
|
}
|
|
}
|
|
*/ |