346 lines
14 KiB
Rust
346 lines
14 KiB
Rust
|
use std::sync::Arc;
|
||
|
use urlencoding::{encode,decode};
|
||
|
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,
|
||
|
AuthState,
|
||
|
ReqHandler,
|
||
|
ReqHeaderMap,
|
||
|
MailMessage,
|
||
|
Random,
|
||
|
AppConnectInfo,
|
||
|
},
|
||
|
users::{
|
||
|
User,
|
||
|
UserStatus,
|
||
|
UserInvitation,
|
||
|
},
|
||
|
handlers::{
|
||
|
add_session_cookie,
|
||
|
get_auth_state,
|
||
|
},
|
||
|
};
|
||
|
pub fn users_invite_router_handlers() -> Router {
|
||
|
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 {
|
||
|
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("")
|
||
|
// });
|
||
|
// 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!"
|
||
|
}
|
||
|
route(
|
||
|
"/signup/:data", get(invite_signup_handler))
|
||
|
.route("/invite", get(invite_handler))
|
||
|
.route("/invite", post(post_invite_handler))
|
||
|
}
|