use std::sync::Arc; use urlencoding::{encode,decode}; // use tokio::sync::RwLock; use axum::{ //extract::{self,Request,Query}, http::{ StatusCode, Uri, header::HeaderMap,// HeaderValue}, }, Json, routing::{get,post}, Extension, extract::ConnectInfo, response::{IntoResponse,Response,Redirect}, // http::Request, handler::HandlerWithoutStateExt, http::StatusCode, routing::get, Router, Router, }; use tower_cookies::{Cookie, Cookies}; use crate::{ SESSION_COOKIE_NAME, DEFAULT_ROLES, route, defs::{ AppDBs, AuthState, SessionStoreDB, ReqHandler, ReqHeaderMap, MailMessage, // TotpAlgorithm, TotpMode, Random, AppConnectInfo, // UserNotifyData, // TOKEN_AUTH_VALUE, // TOKEN_KEY_VALUE, }, users::{ User, // UserStore, // UserId, UserData, UserLogin, UserItem, UserStatus, UserInvitation, }, login_password::{generate_hash,verify_password}, handlers::{ add_session_cookie, get_auth_state, }, }; pub fn users_router_handlers() -> Router { async fn main_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(random): Extension, Extension(cookies): Extension, ConnectInfo(app_connect_info): ConnectInfo, ) -> Response { // if let Some(cookie_value) = get_cookie(&req) { // println!("cookie_value: {}",&cookie_value.to_string()); // // TODO check value // } //let has_cookie: bool; // dbg!(&auth_state.session); // if auth_state.user.is_none() { // eprintln!("No user found in session"); // } let auth_state = get_auth_state(true, &cookies, &app_dbs).await; // has_cookie=true; // TODO check value // let sid: String = format!("{}",&auth_state.sid()); // println!("auth_sid: {}",&sid); // println!("id: {}",&auth_state.id()); // println!("is_expired: {}",&auth_state.ses_expired()); // println!("is_destroyed: {}",&auth_state.ses_destroyed()); // println!("validate: {}",&auth_state.ses_validate()); // let _u = &auth_state.user; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "main_handler" ); // if let Some(a) = auth_state { // println!("Auth State from root"); // } // let uri_path = format!("{}",&uri.path().to_string()); // dbg!("uri: {}",&uri_path); req_handler.prepare_response(); req_handler.context.insert("with_menu", "1"); let result = if let Some(tpl) = app_dbs.config.tpls.get("main") { req_handler.render_template(&tpl,"main") } else { String::from("main") }; let _ = req_handler.trace_req(String::from("main request")); // if !has_cookie { // let mut u128_pool = [0u8; 16]; // match random.lock() { // Ok(mut r) => r.fill_bytes(&mut u128_pool), // Err(e) => println!("Error random: {}",e), // } // let session_token = u128::from_le_bytes(u128_pool).to_string(); // let user_data = format!("{}|{}","jesus" ,"admin,dev"); // let result_store = SessionStoreDB::store_session_data(&session_token,&user_data,&app_dbs).await; // println!("Rest store: {}",&result_store); // let cookie = Cookie::build(SESSION_COOKIE_NAME, session_token.to_owned()) // // .domain(domain) // .path("/") // .secure(true) // .http_only(true) // .finish(); // cookies.remove(Cookie::new(SESSION_COOKIE_NAME, "")); // cookies.add(cookie); // } ( req_handler.req_header.header, result.to_owned() ).into_response() } // async fn auto_handler( // //req: Request, // header: HeaderMap, // uri: Uri, // Extension(app_dbs): Extension>, // Extension(random): Extension, // Extension(cookies): Extension, // // _auth_state: AuthState, // ) -> Response { // // if let Some(cookie_value) = get_cookie(&req) { // // println!("cookie_value: {}",&cookie_value.to_string()); // // // TODO check value // // } // let auth_state = get_auth_state(true, &cookies, &app_dbs).await; // let has_cookie: bool; // if let Some(cookie_value) = cookies.get(SESSION_COOKIE_NAME) { // println!("cookie_value: {}",&cookie_value.to_string()); // //has_cookie=true; // has_cookie=false; // // TODO check value // } else { // has_cookie=false; // } // // if let Some(a) = auth_state { // // println!("Auth State from root"); // // } // let uri_path = format!("{}",&uri.path().to_string()); // let file = "hello.html"; // let result = app_dbs.tera.render(&file, &app_dbs.context).unwrap_or_else(|e|{ // println!("Error render {}: {}",&file,e); // String::from("") // }); // /* // if !has_cookie { // let mut u128_pool = [0u8; 16]; // match random.lock() { // Ok(mut r) => r.fill_bytes(&mut u128_pool), // Err(e) => println!("Error random: {}",e), // } // let session_token = u128::from_le_bytes(u128_pool).to_string(); // let user_data = format!("{}|{}","jesus" ,"admin,dev"); // let result_store = SessionStoreDB::store_session_data(&session_token,&user_data,&app_dbs).await; // println!("Rest store: {}",&result_store); // let cookie = Cookie::build(SESSION_COOKIE_NAME, result_store) // // .domain(domain) // .path("/") // .secure(true) // .http_only(true) // .finish(); // cookies.remove(Cookie::new(SESSION_COOKIE_NAME, "")); // cookies.add(cookie); // } // */ // dbg!("uri: {}",&uri_path); // ( // header, // result.to_owned() // ).into_response() // // "Hello, World!" // } async fn signup_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "signup_handler" ); if !auth_state.is_admin() { let total_users = User::count(&app_dbs.user_store).await.unwrap_or_else(|e|{ println!("Count error: {}",e); 0 }); if ! app_dbs.config.signup_mode.contains("open") && total_users != 0 { let msg = format!("Config signup mode not open: {}", app_dbs.config.signup_mode); println!("{}",&msg); let _ = req_handler.trace_req(msg); return Redirect::temporary( &format!("/")).into_response(); } let total_users = User::count(&app_dbs.user_store).await.unwrap_or_else(|e|{ println!("Count error: {}",e); -1 }); // Fake to insert firt time admin user ... if total_users < 1 { let isadmin=true; req_handler.context.insert("isadmin", &isadmin); } } let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } req_handler.context.insert("password_score", &app_dbs.config.password_score); req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode)); // req_handler.context.insert("with_menu", "1"); if app_dbs.config.totp_mode != TotpMode::No { match req_handler.otp_generate() { Ok(totp) => { req_handler.context.insert("otp_code", &totp.get_secret_base32()); req_handler.context.insert("otp_url", &totp.get_url()); req_handler.context.insert("otp_qr", &totp.get_qr().unwrap_or_default()); req_handler.context.insert("totp_digits", &app_dbs.config.totp_digits); req_handler.context.insert("totp_algorithm",&format!("{}",&app_dbs.config.totp_algorithm)); }, Err(e) => { println!("Error TOTP generartor: {}",e); } } } req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields); let result = if let Some(tpl) = app_dbs.config.tpls.get("signup") { req_handler.render_template(&tpl,"signup") } else { String::from("signup") }; let _ = req_handler.trace_req(format!("Signup request")); ( res_headers, result.to_owned() ).into_response() } async fn post_signup_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(random): Extension, Extension(cookies): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_data): Json, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "post_signup_handler" ); if user_data.name.is_empty() { let _ = req_handler.trace_req(format!("No name found")); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } if user_data.password.is_empty() { let _ = req_handler.trace_req(format!("user '{}' no password found",&user_data.name)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let passwd_score = User::password_score(&user_data.password); if passwd_score < app_dbs.config.password_score { let _ = req_handler.trace_req(format!("User '{}' password '{}' score: {} under {}" ,&user_data.name,&user_data.password, passwd_score,app_dbs.config.password_score) ); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } let new_hash = generate_hash(&user_data.password); // println!("password: {}", &new_hash); // // if user_data.password.is_empty() { // // return Err(error_page(&SignupError::MissingDetails)); // // } // match verify_password(&user_data.password, &new_hash) { // Ok(_) => { // println!("Is valid!"); // }, // Err(e) => { // println!("NOT valid {}",e); // //return Err(error_page(&SignupError::PasswordsDoNotMatch)) // } // } let otp_enabled: bool; let otp_verified: bool; let otp_base32: String; let otp_auth_url: String; let otp_defs: String; if app_dbs.config.totp_mode != TotpMode::No && !user_data.otp_auth.is_empty() { match req_handler.otp_check(&user_data.otp_code,&user_data.otp_auth, "") { Ok(val) => { if val { otp_enabled = true; } else { let _ = req_handler.trace_req(format!("User '{}' not valid TOTP code",&user_data.name)); // otp_enabled = false; return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } }, Err(e) => { println!("TOTP check: {}", e); let _ = req_handler.trace_req(format!("User '{}' TOTP check error: {}",&user_data.name,e)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } } } else { otp_enabled = false; } if otp_enabled { otp_verified= true; otp_base32 = user_data.otp_code.to_owned(); otp_auth_url = user_data.otp_url.to_owned(); otp_defs = format!("{},{}", &app_dbs.config.totp_digits, format!("{}",&app_dbs.config.totp_algorithm), ); } else { otp_verified = false; otp_base32 = String::from(""); otp_auth_url = String::from(""); otp_defs = String::from(""); } let roles = if ! user_data.roles.is_empty() { user_data.roles.to_owned() } else { DEFAULT_ROLES.to_owned() }; let isadmin = if user_data.id == "A" { true } else { false }; let mut new_items = user_data.items.to_owned(); new_items.remove("invite_key"); new_items.remove("invite_id"); let user = User{ id: 0, name: user_data.name.to_owned(), fullname: user_data.name.to_owned(), email: user_data.email.to_owned(), description: user_data.description.to_owned(), password: new_hash, otp_enabled, otp_verified, otp_base32, otp_auth_url, otp_defs, created: chrono::Utc::now().timestamp().to_string(), lastaccess: String::from(""), status: UserStatus::Created, items: User::json_items(new_items), isadmin, roles, }; let usr_sel = User::select("name", &user_data.name, false, &app_dbs.user_store).await.unwrap_or_default(); if usr_sel.name == user_data.name { // User already exists let _ = req_handler.trace_req(format!("User 'name' = '{}' already exists",&user_data.name)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let str_user_data = match user.add(&app_dbs.user_store).await { Ok(id) => { println!("user {} created -> {}", &user_data.name, id); format!("{}|{}|{}",id, &user_data.name, &user_data.roles) }, Err(e) => { let _ = req_handler.trace_req(format!("User '{}' create error: {}",&user_data.name,e)); println!("user {} error -> {:#}", &user_data.name, e); return ( StatusCode::NOT_FOUND, req_handler.req_header.header, "Error" ).into_response(); } }; let session_token = req_handler.new_token(); println!("session: {}", &session_token.to_string()); let session_cookie = add_session_cookie(true,&cookies, &session_token, &str_user_data, 0, &app_dbs, "/").await; let _ = req_handler.trace_req(format!("User '{}' created",&user_data.name)); if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie); } ( req_handler.req_header.header, "Ok" ).into_response() } async fn login_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, ) -> Response { SessionStoreDB::cleanup_data(&app_dbs).await; let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "login_handler" ); let total_users = User::count(&app_dbs.user_store).await.unwrap_or_else(|e|{ let _ = req_handler.trace_req( format!("Users count error: {}",e)); println!("Count error: {}",e); -1 }); if total_users < 1 { let _ = req_handler.trace_req(String::from("No users found")); return Redirect::temporary( &format!("/signup")).into_response(); } let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } // req_handler.context.insert("with_menu", "1"); req_handler.context.insert("use_mail", &app_dbs.config.use_mail); req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode)); if app_dbs.config.totp_mode != TotpMode::No { req_handler.context.insert("with_totp", "1"); req_handler.context.insert("totp_digits", &app_dbs.config.totp_digits); } let _ = req_handler.trace_req(String::from("login request")); let result = if let Some(tpl) = app_dbs.config.tpls.get("login") { req_handler.render_template(&tpl,"login") } else { String::from("login") }; ( res_headers, result.to_owned() ).into_response() } async fn post_login_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_login): Json, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "post_login_handler" ); if user_login.name.is_empty() || user_login.password.is_empty() { let _ = req_handler.trace_req(String::from("Empty name or password")); // return Err(error_page(&SignupError::MissingDetails)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let field = if user_login.name.contains("@") { "email" } else { "name" }; let mut user_sel = User::select(&field, &user_login.name, false, &app_dbs.user_store).await.unwrap_or_else(|e|{ println!("Error select: {}", e); User::default() }); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("No name '{}' found",&user_login.name)); // User not exists return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error data" ).into_response(); } if user_sel.status != UserStatus::Active && user_sel.status != UserStatus::Created { let _ = req_handler.trace_req(format!("user '{}' in not valid status: {}",&user_login.name, &user_sel.status)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error status" ).into_response(); } if verify_password(&user_login.password, &user_sel.password).is_err() { let _ = req_handler.trace_req(format!("user '{}' not valid password: {}",&user_login.name, &user_sel.password)); println!("password NOT valid"); // TODO //return Err(error_page(&SignupError::PasswordsDoNotMatch)) return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error data" ).into_response(); } let result=format!("{}:{}","OK",&user_sel.otp_verified); if app_dbs.config.totp_mode != TotpMode::No { if user_login.otp_auth.is_empty() && (app_dbs.config.totp_mode == TotpMode::Mandatory || user_sel.otp_enabled) { let _ = req_handler.trace_req(format!("user '{}' not valid Totp: {}",&user_login.name, &user_sel.otp_enabled)); return ( req_handler.req_header.header, result ).into_response(); } else if user_sel.otp_enabled && user_sel.otp_verified && !user_sel.otp_base32.is_empty() && !user_sel.otp_defs.is_empty() { match req_handler.otp_check(&user_sel.otp_base32,&user_login.otp_auth, &user_sel.otp_defs) { Ok(val) => { if !val { let _ = req_handler.trace_req(format!("user '{}' not valid TOTP code",&user_login.name)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } }, Err(e) => { let _ = req_handler.trace_req(format!("user '{}' TOTP check error: {}",&user_login.name,e)); println!("TOTP check: {}", e); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } } } } user_sel.lastaccess = chrono::Utc::now().timestamp().to_string(); if user_sel.status != UserStatus::Active { user_sel.status = UserStatus::Active } let user_data = user_sel.session_data(); match user_sel.update(&app_dbs.user_store).await { Ok(_) => { let session_token = req_handler.new_token(); let session_cookie = add_session_cookie(true,&cookies, &session_token, &user_data, 0, &app_dbs, "/").await; if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) }; let new_auth_state = AuthState::from_cookie(session_cookie.to_string(), &app_dbs).await; req_handler = ReqHandler::new( req_handler.req_header, &app_dbs, &uri, &new_auth_state, &random, "post_login_handler" ); let _ = req_handler.trace_req(format!("user '{}', new token: '{}', cookie: '{}' ",&user_login.name, &session_token, &session_cookie)); ( req_handler.req_header.header, result ).into_response() }, Err(e) => { let _ = req_handler.trace_req(format!("user '{}' update error: {}",&user_login.name,e)); ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response() } } } async fn logout_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "logout_handler" ); let id = auth_state.id(); let res = auth_state.destroy(); cookies.remove(Cookie::new(SESSION_COOKIE_NAME, "")); if app_dbs.config.verbose > 1 { println!("Session: {} destroyed: {}",&id, &res); } let _ = req_handler.trace_req(format!("Session '{}' logout",&id)); let auth_state = AuthState::default(); req_handler = ReqHandler::new( req_handler.req_header, &app_dbs, &uri, &auth_state, &random, "logout_handler" ); let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } // these is to use user_items like color_theme // let user_items = User::hash_items(&auth_state.user_items()); // req_handler.context.insert("usr_items", &user_items); req_handler.context.insert("with_menu", "1"); let result = if let Some(tpl) = app_dbs.config.tpls.get("logout") { req_handler.render_template(&tpl,"logout") } else { String::from("logout") }; ( res_headers, result.to_owned() ).into_response() } async fn check_item_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_item): Json, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "logout_handler" ); let result = if user_item.name == "password" { let _ = req_handler.trace_req(format!("Password estimate")); User::estimate_password(&user_item.value) } else { let user_sel = User::select(&user_item.name, &user_item.value, false,&app_dbs.user_store).await.unwrap_or_default(); if !user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("User '{}' = '{}' not found",&user_item.name,&user_item.value)); // User not exists return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } String::from("OK") }; ( req_handler.req_header.header, result.to_owned() ).into_response() } // async fn edit_user_handler( // header: HeaderMap, // uri: Uri, // Extension(app_dbs): Extension>, // Extension(cookies): Extension, // //_auth_state: AuthState, // ) -> Response { // let auth_state = get_auth_state(true, &cookies, &app_dbs).await; // let mut req_handler = ReqHandler::new( // ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string())), // &app_dbs, // &uri, // &auth_state, // "root_handler" // ); // let uri_path = format!("{}",&uri.path().to_string()); // let file = "hello.html"; // let result = app_dbs.tera.render(&file, &app_dbs.context).unwrap_or_else(|e|{ // println!("Error render {}: {}",&file,e); // String::from("") // }); // req_handler.context.insert("with_menu", "1"); // dbg!("uri: {}",&uri_path); // // let mut new_header = header.to_owned(); // //new_header.append("Set-Cookie", "session_token=_; Max-Age=0".parse().unwrap()); // // cookies.remove(Cookie::new(SESSION_COOKIE_NAME, "")); // ( // req_handler.req_header.header, // result.to_owned() // ).into_response() // // "Hello, World!" // } async fn user_settings_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; if auth_state.session.is_none() { return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); } let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "user_settings_handler" ); let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } let user_id = auth_state.user_id(); if user_id.is_empty() { let _ = req_handler.trace_req(format!("user not id found")); // User not exists return Redirect::temporary( &format!("/")).into_response(); } let user_sel = User::select("id", &user_id, true, &app_dbs.user_store).await.unwrap_or_default(); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("Edit user id '{}' not found ",&user_id)); // User not exists return Redirect::temporary( &format!("/")).into_response(); } req_handler.context.insert("with_menu", "1"); req_handler.context.insert("user", &user_sel); req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields); req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode)); // let user_items = User::hash_items(&user_sel.items); // req_handler.context.insert("usr_items", &user_items); req_handler.context.insert("no_edit", "true"); req_handler.context.insert("edit_target", "main"); let result = if let Some(tpl) = app_dbs.config.tpls.get("user_settings") { req_handler.render_template(&tpl,"user setting") } else { String::from("user settings") }; let _ = req_handler.trace_req(format!("User '{}' settings",&user_sel.id)); ( res_headers, result.to_owned() ).into_response() } async fn user_settings_edit_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, axum::extract::Path(data): axum::extract::Path, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; if auth_state.session.is_none() { return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); } let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "user_settings_edit_handler" ); let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } if data != "main" && data != "password" && data != "totp" { let _ = req_handler.trace_req(format!("Edit user not data section '{}' ",&data)); return Redirect::temporary( &format!("/")).into_response(); } let user_id = auth_state.user_id(); if user_id.is_empty() { // User not exists let _ = req_handler.trace_req(format!("Edit user not id ")); return Redirect::temporary( &format!("/")).into_response(); } let user_sel = User::select("id", &user_id, true, &app_dbs.user_store).await.unwrap_or_default(); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("Edit user id '{}' not found ",&user_id)); // User not exists return Redirect::temporary( &format!("/")).into_response(); } req_handler.context.insert("with_menu", "1"); req_handler.context.insert("user", &user_sel); req_handler.context.insert("edit_target", &data); req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields); req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode)); if data == "totp" && app_dbs.config.totp_mode != TotpMode::No { if !user_sel.otp_base32.is_empty() { match req_handler.otp_make(&user_sel.otp_base32, &user_sel.otp_defs) { Ok(totp) => { req_handler.context.insert("otp_code", &user_sel.otp_base32); req_handler.context.insert("otp_url", &user_sel.otp_auth_url); req_handler.context.insert("otp_qr", &totp.get_qr().unwrap_or_default()); }, Err(e) => { println!("User settings error totp: {}",e); } } } else { match req_handler.otp_generate() { Ok(totp) => { req_handler.context.insert("otp_code", &totp.get_secret_base32()); req_handler.context.insert("otp_url", &totp.get_url()); req_handler.context.insert("otp_qr", &totp.get_qr().unwrap_or_default()); }, Err(e) => { println!("Error TOTP generartor: {}",e); } } } req_handler.context.insert("totp_digits", &app_dbs.config.totp_digits); req_handler.context.insert("totp_algorithm",&format!("{}",&app_dbs.config.totp_algorithm)); } let _ = req_handler.trace_req(format!("Edit user '{}' settings",&user_id)); // req_handler.context.insert("no_edit", "true"); let result = if let Some(tpl) = app_dbs.config.tpls.get("user_settings") { req_handler.render_template(&tpl,"user setting") } else { String::from("user settings") }; ( res_headers, result.to_owned() ).into_response() } async fn post_user_settings_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_data): Json, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "post_user_settings_handler" ); if auth_state.session.is_none() { let _ = req_handler.trace_req(format!("No session found for user '{}'",&user_data.id)); return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); } let user_id = auth_state.user_id(); if user_id.is_empty() { let _ = req_handler.trace_req(format!("No user found")); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let mut user_sel = User::select("id", &user_id, false,&app_dbs.user_store).await.unwrap_or_default(); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("User '{}' not found",&user_id)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } if !user_data.password.is_empty() { let passwd_score = User::password_score(&user_data.password); if passwd_score < app_dbs.config.password_score { let _ = req_handler.trace_req(format!("User '{}' password '{}' score: {} under {}" ,&user_id,&user_data.password, passwd_score,app_dbs.config.password_score )); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } user_sel.password = generate_hash(&user_data.password); } let otp_enabled: bool; if app_dbs.config.totp_mode != TotpMode::No && !user_data.otp_auth.is_empty() { match req_handler.otp_check(&user_data.otp_code,&user_data.otp_auth, "") { Ok(val) => { if val { otp_enabled = true; } else { // otp_enabled = fasle; let _ = req_handler.trace_req(format!("User '{}' not valid TOTP code",&user_id)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } }, Err(e) => { println!("TOTP check: {}", e); let _ = req_handler.trace_req(format!("User '{}' TOTP check error: {}",&user_id,e)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } } } else { otp_enabled = false; } if otp_enabled { user_sel.otp_enabled= true; user_sel.otp_verified= true; user_sel.otp_base32 = user_data.otp_code.to_owned(); user_sel.otp_auth_url = user_data.otp_url.to_owned(); user_sel.otp_defs = format!("{},{}", &app_dbs.config.totp_digits, format!("{}",&app_dbs.config.totp_algorithm), ); } else { user_sel.otp_enabled= false; user_sel.otp_verified = false; user_sel.otp_base32 = String::from(""); user_sel.otp_auth_url = String::from(""); user_sel.otp_defs = String::from(""); } user_sel.from_data(user_data); let user_data = user_sel.session_data(); match user_sel.update(&app_dbs.user_store).await { Ok(_) => { let session_token = auth_state.id(); let session_cookie = add_session_cookie(true,&cookies, &session_token, &user_data, 0, &app_dbs, "/").await; if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) }; let _ = req_handler.trace_req(format!("User '{}' updated",&user_id)); let result =String::from("OK"); ( req_handler.req_header.header, result.to_owned() ).into_response() }, Err(e) => { let _ = req_handler.trace_req(format!("User '{}' update error: {}",&user_id,e)); ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response() } } } async fn post_reset_password_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_item): Json, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "post_reset_password_handler" ); if ! app_dbs.config.use_mail { let _ = req_handler.trace_req(format!("Mail disabled in config, user '{}' password can not be reset",&user_item.name)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error no service" ).into_response(); } if user_item.name.is_empty() { let _ = req_handler.trace_req(format!("No user name")); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let field = if user_item.name.contains("@") { "email" } else { "name" }; let mut user_sel = User::select(&field, &user_item.name, false, &app_dbs.user_store).await.unwrap_or_else(|e|{ println!("Error select: {}", e); User::default() }); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("User '{}' = '{}' not found",&field,&user_item.name)); // User not exists return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error data" ).into_response(); } if user_sel.status != UserStatus::Active && user_sel.status != UserStatus::Created { let _ = req_handler.trace_req(format!("user '{}' in not valid status: {}",&user_item.name, &user_sel.status)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error status" ).into_response(); } if app_dbs.config.totp_mode != TotpMode::No { if user_sel.otp_base32.is_empty() && (app_dbs.config.totp_mode == TotpMode::Mandatory || user_sel.otp_enabled) { let _ = req_handler.trace_req(format!("user '{}' not valid Totp: {}",&user_sel.name, &user_sel.otp_enabled)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error data" ).into_response(); } else if user_sel.otp_enabled && user_sel.otp_verified && !user_sel.otp_base32.is_empty() && !user_sel.otp_defs.is_empty() { match req_handler.otp_check(&user_sel.otp_base32,&user_item.value, &user_sel.otp_defs) { Ok(val) => { if !val { let _ = req_handler.trace_req(format!("User '{}' not valid TOTP code",&user_item.name)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } }, Err(e) => { println!("TOTP check: {}", e); let _ = req_handler.trace_req(format!("User '{}' TOTP check error: {}",&user_item.name,e)); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } } } } let session_token = req_handler.new_token(); user_sel.status = UserStatus::Pending; let user_data = user_sel.session_data(); let session_cookie = add_session_cookie(false,&cookies, &session_token, &user_data, app_dbs.config.session_expire, &app_dbs, "invitation").await; let session_encoded_key = encode(session_cookie.as_str()); let body=format!("This is a user password reset request for docserver service"); let subject = format!("DocServer password reset"); let reset_url= format!( "{}://{}/reset", &app_dbs.config.protocol, &app_dbs.config.hostport, ); let reset_expiration = format!("{} minutes",(&app_dbs.config.session_expire/60)); req_handler.context.insert("reset_url", &reset_url); req_handler.context.insert("reset_expiration", &reset_expiration); req_handler.context.insert("email_body",&body); req_handler.context.insert("reset_key",&session_encoded_key); req_handler.context.insert("email_subject",&subject); let mail_content= if let Some(tpl) = app_dbs.config.tpls.get("reset_password_mail_txt") { req_handler.render_template(tpl, "reset password") } else { format!("{}\n{}\n{}/{}\n",&subject,&body,&reset_url,&session_cookie) }; let mail_html_content = if let Some(tpl) = app_dbs.config.tpls.get("reset_password_mail_html") { req_handler.render_template(tpl, "invite") } else { format!("{}\n{}\n{}/{}\n",&subject,&body,&reset_url,&session_cookie) }; let mail_check = MailMessage::check(&app_dbs); if ! mail_check.is_empty() { let _ = req_handler.trace_req(format!("Mail service check error: {}",&mail_check)); ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error service" ).into_response() } else { match MailMessage::new( &app_dbs.config.mail_from, &user_sel.email, &app_dbs.config.mail_reply_to, ) { Ok(mail_message) => { match mail_message.send_html_message( &subject, &mail_content, &mail_html_content, &app_dbs ).await { Ok(_) => { let _ = req_handler.trace_req(format!("Mail sent to: '{}' reset url: {} cookie: {}", &user_sel.name, &reset_url,&session_cookie )); ( StatusCode::OK, format!("Mail sent to {}",&user_sel.name) ).into_response() }, Err(e) => { let _ = req_handler.trace_req(format!("Mail message send to: '{}' Error: {} ",&user_sel.name,e)); println!("Error mail message send: {}",e); ( StatusCode::INTERNAL_SERVER_ERROR, req_handler.req_header.header, "Error service" ).into_response() } } }, Err(e) => { let _ = req_handler.trace_req(format!("Mail message send to: '{}' Creation error: {} ",&user_sel.name,e)); println!("Error mail message creation: {}",e); ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error service" ).into_response() } } } //let result=format!("{}","OK"); // if ! auth_state.has_auth_role(&app_dbs.config.auth_roles) { // return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); // // return ( // // StatusCode::UNAUTHORIZED, // // header, // // "Error authorization" // // ).into_response(); // } // ( // //status, // req_handler.req_header.header, // result, // ).into_response() } async fn reset_password_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, // Query(req_params): Query, axum::extract::Path(data): axum::extract::Path, ) -> Response { // dbg!(&user_item); let session_cookie = decode(&data).unwrap_or_default().to_string(); let auth_state = AuthState::from_cookie(session_cookie.to_owned(), &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "reset_password_handler" ); let user_id = auth_state.user_id(); if user_id.is_empty() { let _ = req_handler.trace_req(format!("No user found")); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let user_sel = User::select("id", &user_id, false, &app_dbs.user_store).await.unwrap_or_else(|e|{ println!("Error select: {}", e); User::default() }); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("User 'id' = '{}' not found",&user_id)); // User not exists return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error data" ).into_response(); } if user_sel.status != UserStatus::Active { let _ = req_handler.trace_req(format!("user '{}' in not valid status: {}",&user_id, &user_sel.status)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error status" ).into_response(); } let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } req_handler.context.insert("with_menu", "1"); req_handler.context.insert("user", &user_sel); req_handler.context.insert("edit_target", "password"); req_handler.context.insert("edit_reset", "password"); req_handler.context.remove("web_menu_items"); let result = if let Some(tpl) = app_dbs.config.tpls.get("user_settings") { req_handler.render_template(&tpl,"user setting") } else { String::from("user settings") }; let user_data = user_sel.session_data(); let session_token = req_handler.new_token(); let session_cookie = add_session_cookie(true,&cookies, &session_token, &user_data, 0, &app_dbs, "/").await; if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) }; let _ = req_handler.trace_req(format!("user '{}' reset password",&user_id)); ( res_headers, result.to_owned() ).into_response() } async fn post_user_password_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_data): Json, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "post_reset_password_handler" ); if user_data.password.is_empty() { let _ = req_handler.trace_req(format!("No passwordfound")); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } if auth_state.session.is_none() { let _ = req_handler.trace_req(format!("No session found for user '{}'",&user_data.id)); return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); } let user_id = auth_state.user_id(); if user_id.is_empty() { let _ = req_handler.trace_req(format!("No user found")); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let mut user_sel = User::select("id", &user_id, false,&app_dbs.user_store).await.unwrap_or_default(); if user_sel.name.is_empty() { let _ = req_handler.trace_req(format!("User '{}' not found",&user_id)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response(); } let passwd_score = User::password_score(&user_data.password); if passwd_score < app_dbs.config.password_score { let _ = req_handler.trace_req(format!("User '{}' password '{}' score: {} under {}" ,&user_id,&user_data.password, passwd_score,app_dbs.config.password_score) ); return ( StatusCode::UNAUTHORIZED, req_handler.req_header.header, "Error" ).into_response(); } user_sel.password = generate_hash(&user_data.password); let user_data = user_sel.session_data(); match user_sel.update(&app_dbs.user_store).await { Ok(_) => { let session_token = auth_state.id(); let session_cookie = add_session_cookie(true,&cookies, &session_token, &user_data, 0, &app_dbs, "/").await; if app_dbs.config.verbose > 1 { println!("session cookie: {}", &session_cookie) }; let _ = req_handler.trace_req(format!("user '{}' reset password OK",&user_id)); let result =String::from("OK"); ( req_handler.req_header.header, result.to_owned() ).into_response() }, Err(e) => { let _ = req_handler.trace_req(format!("Error user '{}' reset password: {}",&user_id,e)); ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error" ).into_response() }, } } async fn invite_signup_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, axum::extract::Path(data): axum::extract::Path, // auth_state: AuthState, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "invite_signup_handler" ); if ! app_dbs.config.signup_mode.contains("invitation") { let msg = format!("Config signup mode not invitation: {}", app_dbs.config.signup_mode ); println!("{}", &msg); let _ = req_handler.trace_req(msg); return Redirect::temporary( &format!("/")).into_response(); } // println!("root_handler: {}",&session_cookie); let session_cookie = decode(&data).unwrap_or_default().to_string(); let auth_state = AuthState::from_cookie(session_cookie.to_owned(), &app_dbs).await; if auth_state.session.is_none() { // TODO make it prettier let _ = req_handler.trace_req(format!("No session found")); return ( StatusCode::NOT_FOUND, req_handler.req_header.header, "No valid invitation found" ).into_response(); } //let user_data = auth_state.user_data(); let mut usr = User::default(); usr.roles = auth_state.user_roles(); usr.email = auth_state.user_email(); let usr_id = auth_state.user_id(); let invite_id = if usr_id == "0" { usr_id } else { usr.email.to_owned() }; // let _uri_path = format!("{}",&uri.path().to_string()); // let file = "hello.html"; // let result = app_dbs.tera.render(&file, &app_dbs.context).unwrap_or_else(|e|{ // println!("Error render {}: {}",&file,e); // String::from("") // }); let mut res_headers = HeaderMap::new(); if req_handler.req_header.is_browser() { res_headers.append(axum::http::header::CONTENT_TYPE,"text/html; charset=utf-8".parse().unwrap()); } req_handler.context.insert("user", &usr); req_handler.context.insert("isadmin", ""); req_handler.context.insert("totp_mode", &format!("{}",&app_dbs.config.totp_mode)); req_handler.context.insert("invite_key", &data); req_handler.context.insert("invite_id", &invite_id); req_handler.context.insert("admin_fields", &app_dbs.config.admin_fields); let result = if let Some(tpl) = app_dbs.config.tpls.get("signup") { req_handler.render_template(&tpl,"signup") } else { String::from("signup") }; let _ = req_handler.trace_req(format!("Invite to '{}' data: {}",&invite_id, &data)); ( res_headers, result.to_owned() ).into_response() } async fn post_invite_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_invite): Json, ) -> Response { //dbg!(&user_item); let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "post_invite_handler" ); if ! app_dbs.config.signup_mode.contains("invitation") { let msg = format!("Config signup mode not invitation: {}", app_dbs.config.signup_mode ); println!("{}", &msg); let _ = req_handler.trace_req(msg); return Redirect::temporary( &format!("/")).into_response(); } if ! auth_state.has_auth_role(&app_dbs.config.auth_roles) { let _ = req_handler.trace_req(format!("User '{}' not have role 'dev'",&auth_state.user_id())); return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); // return ( // StatusCode::UNAUTHORIZED, // header, // "Error authorization" // ).into_response(); } if ! user_invite.email.contains("@") { let _ = req_handler.trace_req(format!("Invite email '{}' not contains '@'",&user_invite.email)); return ( StatusCode::BAD_REQUEST, req_handler.req_header.header, "Error invitation data" ).into_response(); } let session_token = req_handler.new_token(); let mut usr = User::default(); usr.email = user_invite.email.to_owned(); usr.roles = user_invite.roles.to_owned(); usr.isadmin = user_invite.isadmin; usr.status = UserStatus::Pending; let user_data = usr.session_data(); let session_cookie = add_session_cookie(false,&cookies, &session_token, &user_data, user_invite.expire, &app_dbs, "invitation").await; let session_encoded_key = encode(session_cookie.as_str()); let body=format!("This is an invitation to docserver service"); let subject = format!("DocServer Invitation"); let signup_url= format!( "{}://{}/signup", &app_dbs.config.protocol, &app_dbs.config.hostport, ); let invite_expiration = format!("{} minutes", (&app_dbs.config.session_expire/60) ); req_handler.context.insert("signup_url", &signup_url); req_handler.context.insert("invite_expiration", &invite_expiration); req_handler.context.insert("email_body",&body); req_handler.context.insert("invite_key",&session_encoded_key); req_handler.context.insert("email_subject",&subject); let (status, result) = if app_dbs.config.use_mail && user_invite.send_email { let mail_content= if let Some(tpl) = app_dbs.config.tpls.get("invite_mail_txt") { req_handler.render_template(tpl, "invite") } else { format!("{}\n{}\n{}/signup/{}\n",&subject,&body,&signup_url,&session_cookie) }; let mail_html_content = if let Some(tpl) = app_dbs.config.tpls.get("invite_mail_html") { req_handler.render_template(tpl, "invite") } else { format!("{}\n{}\n{}/signup/{}\n",&subject,&body,&signup_url,&session_cookie) }; let mail_check = MailMessage::check(&app_dbs); if ! mail_check.is_empty() { ( StatusCode::BAD_REQUEST, mail_check ) } else { //"jesus.perezlorenzo@gmail.com", // "jesus@librecloud.online", match MailMessage::new( &app_dbs.config.mail_from, &user_invite.email, &app_dbs.config.mail_reply_to, ) { Ok(mail_message) => { //match mail_message.send_message( match mail_message.send_html_message( &subject, &mail_content, &mail_html_content, &app_dbs ).await { Ok(_) => { let _ = req_handler.trace_req(format!( "Invitation mail sent to: '{}' reset url: {} roles: {}, isadmin: {}, expiration: {} cookie: {}", &user_invite.email, &invite_expiration, user_invite.roles, user_invite.isadmin, &signup_url,&session_cookie )); (StatusCode::OK, format!("Mail sent to {}",&user_invite.email)) }, Err(e) => { println!("Invitation to: {} Error mail message send: {}",&user_invite.email, e); ( StatusCode::INTERNAL_SERVER_ERROR, String::from("Error") ) } } }, Err(e) => { println!("Invitation to: {} Error mail message creation: {}",&user_invite.email, e); ( StatusCode::BAD_REQUEST, String::from("Error") ) } } } } else { let _ = req_handler.trace_req(format!( "Created invitation: '{}' reset url: {} roles: {}, isadmin: {}, expiration: {} cookie: {}", &user_invite.email, &invite_expiration, user_invite.roles, user_invite.isadmin, &signup_url,&session_cookie )); (StatusCode::OK, format!("No mail sent to {}",&user_invite.email)) }; req_handler.prepare_response(); req_handler.context.insert("email_result",&result); let response = if let Some(tpl) = app_dbs.config.tpls.get("invite_output") { req_handler.render_template(tpl, "invite") } else { format!("{}\n{}\n{}/signup/{}\n",&subject,&body,&signup_url,&session_cookie) }; ( status, req_handler.req_header.header, response, ).into_response() } async fn invite_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, ) -> Response { let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let mut req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "invite_handler" ); if ! app_dbs.config.signup_mode.contains("invitation") { let msg = format!("Config signup mode not invitation: {}", app_dbs.config.signup_mode ); println!("{}",&msg); let _ = req_handler.trace_req(msg); return Redirect::temporary( &format!("/")).into_response(); } if ! auth_state.has_auth_role(&app_dbs.config.auth_roles) { let _ = req_handler.trace_req(format!("User '{}' not have role 'dev'",&auth_state.user_id())); return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); // return ( // StatusCode::UNAUTHORIZED, // header, // "Error authorization" // ).into_response(); } let title = format!("DocServer Invitation"); let invite_url= format!( "{}://{}/invite", &app_dbs.config.protocol, &app_dbs.config.hostport, ); let invite_expire = format!("{} minutes", (&app_dbs.config.invite_expire/60) ); req_handler.context.insert("target_url", &invite_url); req_handler.context.insert("invite_expire", &invite_expire); if app_dbs.config.use_mail { req_handler.context.insert("use_mail", &app_dbs.config.use_mail); } req_handler.prepare_response(); req_handler.context.insert("with_menu", "1"); let response = if let Some(tpl) = app_dbs.config.tpls.get("invite_create") { req_handler.render_template(tpl, "invite create") } else { format!("{} invite",&title) }; let _ = req_handler.trace_req(format!( "Invitation: url: {}, expiration: {}", &invite_url, &invite_expire, )); ( req_handler.req_header.header, response, ).into_response() // let uri_path = format!("{}",&uri.path().to_string()); // let file = "hello.html"; // let result = app_dbs.tera.render(&file, &app_dbs.context).unwrap_or_else(|e|{ // println!("Error render {}: {}",&file,e); // String::from("") // }); //dbg!("uri: {}",&uri_path); // let mut new_header = header.to_owned(); //new_header.append("Set-Cookie", "session_token=_; Max-Age=0".parse().unwrap()); // cookies.remove(Cookie::new(SESSION_COOKIE_NAME, "")); // ( // header, // result.to_owned() // ).into_response() // "Hello, World!" } async fn update_user_item_handler( header: HeaderMap, uri: Uri, Extension(app_dbs): Extension>, Extension(cookies): Extension, Extension(random): Extension, ConnectInfo(app_connect_info): ConnectInfo, Json(user_item): Json, //_auth_state: AuthState, //axum::extract::Path(data): axum::extract::Path, ) -> Response { dbg!(&user_item); let auth_state = get_auth_state(true, &cookies, &app_dbs).await; let req_handler = ReqHandler::new( ReqHeaderMap::new(header, &format!("{}",&uri.path().to_string()), &app_connect_info), &app_dbs, &uri, &auth_state, &random, "update_user_item_handler" ); if ! auth_state.has_auth_role(&app_dbs.config.auth_roles) { let _ = req_handler.trace_req(format!("User '{}' not have role 'dev'",&auth_state.user_id())); return Redirect::temporary( &format!("/login?o={}",uri.path().to_string())).into_response(); // return ( // StatusCode::UNAUTHORIZED, // header, // "Error authorization" // ).into_response(); } let result=""; ( //status, req_handler.req_header.header, result, ).into_response() } route("/", get(main_handler)) // .route("/auto", get(auto_handler)) .route("/login", get(login_handler)) .route("/login", post(post_login_handler)) .route("/signup", get(signup_handler)) .route("/signup", post(post_signup_handler)) .route("/signup/:data", get(invite_signup_handler)) .route("/logout", get(logout_handler)) .route("/check", post(check_item_handler)) .route("/invite", get(invite_handler)) .route("/invite", post(post_invite_handler)) .route("/reset/:data", get(reset_password_handler)) .route("/reset", post(post_reset_password_handler)) .route("/resetup", post(post_user_password_handler)) .route("/settings", get(user_settings_handler)) .route("/settings/:item", get(user_settings_edit_handler)) // .route("/update", post(update_user_handler)) .route("/settings", post(post_user_settings_handler)) .route("/update_item", post(update_user_item_handler)) }