docserver/src/handlers/users/settings_handlers.rs

400 lines
17 KiB
Rust

use std::sync::Arc;
use axum::{
http::{
StatusCode,
Uri,
header::HeaderMap,
},
Json,
routing::{get,post},
Extension,
extract::ConnectInfo,
response::{IntoResponse,Response,Redirect},
Router,
};
use tower_cookies::Cookies;
use crate::{
route,
defs::{
AppDBs,
ReqHandler,
ReqHeaderMap,
TotpMode,
Random,
AppConnectInfo,
},
users::{
User,
UserData,
UserItem,
OpenidUser,
},
login_password::generate_hash,
handlers::{
add_session_cookie,
get_auth_state,
},
};
pub fn users_settings_router_handlers() -> Router {
// 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");
// // 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();
}
let openid_sel = OpenidUser::list_selection("userid", &user_sel.id.to_string(), &app_dbs.user_store, true,false, "|").await.unwrap_or_else(|e| {
println!("Error list selection {}: {}", &user_sel.name, e);
Vec::new()
});
req_handler.context.insert("openid_sel", &openid_sel);
let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
req_handler.context.insert("openid_sel_appkeys", &openid_sel_appkeys);
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();
}
let openid_sel = OpenidUser::list_selection("userid", &user_sel.id.to_string(), &app_dbs.user_store, true,false, "|").await.unwrap_or_else(|e| {
println!("Error list selection {}: {}", &user_sel.name, e);
Vec::new()
});
req_handler.context.insert("openid_sel", &openid_sel);
let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
req_handler.context.insert("openid_sel_appkeys", &openid_sel_appkeys);
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_base64().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_base64().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 openid_sel = OpenidUser::list_selection("userid", &user_sel.id.to_string(), &app_dbs.user_store, true,false, "|").await.unwrap_or_else(|e| {
// println!("Error list selection {}: {}", &user_sel.name, e);
// Vec::new()
//});
//let openid_sel_appkeys = openid_sel.iter().map(|id| id.appkey.to_string()).collect::<Vec<String>>().join(",");
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("");
}
let user_openids = user_data.opendis.to_owned();
user_sel.from_data(user_data);
let new_id= user_sel.id.to_string();
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));
OpenidUser::sync_ids(&new_id, &user_openids, &app_dbs.user_store).await;
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 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 {
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(
"/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))
}