123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- use microrm::prelude::*;
- use tide::http::mime;
- use crate::{schema, user::UserExt, UIDCError};
- type Request = tide::Request<super::ServerStateWrapper>;
- fn generate_template_data(
- lease: &mut microrm::ConnectionLease,
- realm: µrm::Stored<schema::Realm>,
- user: µrm::Stored<schema::User>,
- ) -> Result<serde_json::Value, UIDCError> {
- let has_totp = user
- .auth
- .with(
- schema::AuthChallenge::ChallengeType,
- schema::AuthChallengeType::Totp.into_serialized(),
- )
- .count(lease)?
- > 0;
- let template_data = serde_json::json!({
- "username": user.username,
- "realm": realm.shortname,
- "totp_control": if has_totp {
- serde_json::json!([{ "value": "keep", "text": "Keep as-is"}, { "value": "remove", "text": "Remove" }, { "value": "reset", "text": "Reset" }])
- } else {
- serde_json::json!([{ "value": "keep", "text": "Leave disabled" }, { "value": "reset", "text": "Start setup" }])
- },
- });
- Ok(template_data)
- }
- async fn um_index(req: Request) -> tide::Result<tide::Response> {
- let shelper = super::session::SessionHelper::new(&req);
- let mut lease = req.state().lease().await?;
- let (realm, user_id) = match shelper.verify_session(&mut lease, &req) {
- Some(v) => v,
- None => {
- return Ok(tide::Redirect::temporary(format!(
- "../v1/session/login?redirect={}",
- req.url()
- ))
- .into())
- }
- };
- let user = realm
- .users
- .with_id(user_id)
- .first()
- .get(&mut lease)?
- .unwrap();
- let template_data = generate_template_data(&mut lease, &realm, &user)?;
- Ok(tide::Response::builder(200)
- .content_type(mime::HTML)
- .body(
- req.state()
- .core
- .templates
- .render("um_index", &template_data)
- .map_err(|_| tide::Error::from_str(500, "error rendering template"))?,
- )
- .build())
- }
- #[derive(serde::Deserialize)]
- struct UpdateForm {
- current_password: String,
- new_password: Option<String>,
- new_password_repeated: Option<String>,
- totp_control: Option<String>,
- }
- async fn um_update(mut req: Request) -> tide::Result<tide::Response> {
- let update_form: UpdateForm = req.body_form().await?;
- let shelper = super::session::SessionHelper::new(&req);
- let mut lease = req.state().lease().await?;
- let (realm, user_id) = match shelper.verify_session(&mut lease, &req) {
- Some(v) => v,
- None => {
- return Ok(tide::Redirect::temporary("../v1/session/login?redirect=../../um/").into())
- }
- };
- let user = realm
- .users
- .with_id(user_id)
- .first()
- .get(&mut lease)?
- .unwrap();
- log::info!("processing update request...");
- let progress: Result<Vec<String>, UIDCError> = (|| {
- let mut info_msgs = vec![];
- let challenge = user.verify_challenge_by_type(
- &mut lease,
- schema::AuthChallengeType::Password,
- update_form.current_password.as_bytes(),
- )?;
- if !challenge {
- Err(UIDCError::Abort("password verification failed"))?
- }
- if let Some((new_pass, new_pass_repeated)) = update_form
- .new_password
- .as_ref()
- .zip(update_form.new_password_repeated.as_ref())
- {
- if new_pass != new_pass_repeated {
- Err(UIDCError::Abort("entered passwords do not match"))?
- }
- if !new_pass.is_empty() {
- user.set_new_password(&mut lease, new_pass.as_bytes())?;
- info_msgs.push("Updated password!".into());
- }
- } else if update_form.new_password.is_some() || update_form.new_password_repeated.is_some()
- {
- Err(UIDCError::Abort("must enter new password twice"))?
- }
- if let Some(totp) = update_form.totp_control.as_ref() {
- if totp == "remove" {
- user.clear_totp(&mut lease)?;
- info_msgs.push("Cleared TOTP setup".into());
- } else if totp == "reset" {
- let (_secret, _uri) = user.generate_totp_with_uri()?;
- Err(UIDCError::Abort(
- "totp setup outside of cli not (yet) supported",
- ))?
- }
- }
- Ok(info_msgs)
- })();
- let mut template_data = generate_template_data(&mut lease, &realm, &user)?;
- match progress {
- Ok(info_msgs) => {
- template_data
- .as_object_mut()
- .and_then(|o| o.insert("info_msg".into(), serde_json::json!(info_msgs)));
- }
- Err(UIDCError::Abort(msg)) => {
- template_data
- .as_object_mut()
- .and_then(|o| o.insert("error_msg".into(), serde_json::json!([msg])));
- }
- Err(e) => {
- template_data
- .as_object_mut()
- .and_then(|o| o.insert("error_msg".into(), serde_json::json!([e.to_string()])));
- }
- }
- Ok(tide::Response::builder(200)
- .content_type(mime::HTML)
- .body(
- req.state()
- .core
- .templates
- .render("um_index", &template_data)
- .map_err(|_| tide::Error::from_str(500, "error rendering template"))?,
- )
- .build())
- }
- pub(super) fn um_server(mut route: tide::Route<super::ServerStateWrapper>) {
- route
- .at("um")
- .get(|_req| async { Ok(tide::Redirect::permanent("um/")) });
- route.at("um/").get(um_index);
- route.at("um/update").post(um_update);
- // route.at("/change_password").get(um_change_password).post(um_change_password_post);
- }
|