docserver/src/handlers/users_handlers.rs

1719 lines
72 KiB
Rust
Raw Normal View History

2023-07-19 04:00:41 +01:00
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<Arc<AppDBs>>,
Extension(random): Extension<Random>,
Extension(cookies): Extension<Cookies>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
) -> 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<Arc<AppDBs>>,
// Extension(random): Extension<Random>,
// Extension(cookies): Extension<Cookies>,
// // _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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
) -> 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<Arc<AppDBs>>,
Extension(random): Extension<Random>,
Extension(cookies): Extension<Cookies>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_data): Json<UserData>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_login): Json<UserLogin>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_item): Json<UserItem>,
) -> 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<Arc<AppDBs>>,
// Extension(cookies): Extension<Cookies>,
// //_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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
axum::extract::Path(data): axum::extract::Path<String>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_data): Json<UserData>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_item): Json<UserItem>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
// Query(req_params): Query<ReqParams>,
axum::extract::Path(data): axum::extract::Path<String>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_data): Json<UserData>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
axum::extract::Path(data): axum::extract::Path<String>,
// 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_invite): Json<UserInvitation>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
) -> 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<Arc<AppDBs>>,
Extension(cookies): Extension<Cookies>,
Extension(random): Extension<Random>,
ConnectInfo(app_connect_info): ConnectInfo<AppConnectInfo>,
Json(user_item): Json<UserItem>,
//_auth_state: AuthState,
//axum::extract::Path(data): axum::extract::Path<String>,
) -> 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))
}