Login for the wasm interface
This commit is contained in:
		
							parent
							
								
									e5d8e6c62f
								
							
						
					
					
						commit
						1aba33fb91
					
				
							
								
								
									
										121
									
								
								app/src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								app/src/lib.rs
									
									
									
									
									
								
							@ -4,7 +4,12 @@ pub mod pages;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use pages::list_links;
 | 
					use pages::list_links;
 | 
				
			||||||
use pages::list_users;
 | 
					use pages::list_users;
 | 
				
			||||||
 | 
					use seed::attrs;
 | 
				
			||||||
 | 
					use seed::button;
 | 
				
			||||||
 | 
					use seed::input;
 | 
				
			||||||
 | 
					use seed::label;
 | 
				
			||||||
use seed::{div, log, prelude::*, App, Url, C};
 | 
					use seed::{div, log, prelude::*, App, Url, C};
 | 
				
			||||||
 | 
					use shared::apirequests::users::LoginUser;
 | 
				
			||||||
use shared::datatypes::User;
 | 
					use shared::datatypes::User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::i18n::{I18n, Lang};
 | 
					use crate::i18n::{I18n, Lang};
 | 
				
			||||||
@ -27,6 +32,8 @@ fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
 | 
				
			|||||||
        page: Page::init(url, orders, lang.clone()),
 | 
					        page: Page::init(url, orders, lang.clone()),
 | 
				
			||||||
        i18n: lang,
 | 
					        i18n: lang,
 | 
				
			||||||
        user: None,
 | 
					        user: None,
 | 
				
			||||||
 | 
					        login_form: LoginForm::default(),
 | 
				
			||||||
 | 
					        login_data: LoginUser::default(),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,6 +48,14 @@ struct Model {
 | 
				
			|||||||
    page: Page,
 | 
					    page: Page,
 | 
				
			||||||
    i18n: i18n::I18n,
 | 
					    i18n: i18n::I18n,
 | 
				
			||||||
    user: Option<User>,
 | 
					    user: Option<User>,
 | 
				
			||||||
 | 
					    login_form: LoginForm,
 | 
				
			||||||
 | 
					    login_data: LoginUser,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Default, Debug)]
 | 
				
			||||||
 | 
					struct LoginForm {
 | 
				
			||||||
 | 
					    username: ElRef<web_sys::HtmlInputElement>,
 | 
				
			||||||
 | 
					    password: ElRef<web_sys::HtmlInputElement>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
@ -83,6 +98,10 @@ pub enum Msg {
 | 
				
			|||||||
    GetLoggedUser,
 | 
					    GetLoggedUser,
 | 
				
			||||||
    UserReceived(User),
 | 
					    UserReceived(User),
 | 
				
			||||||
    NoMessage,
 | 
					    NoMessage,
 | 
				
			||||||
 | 
					    NotAuthenticated,
 | 
				
			||||||
 | 
					    Login,
 | 
				
			||||||
 | 
					    UsernameChanged(String),
 | 
				
			||||||
 | 
					    PasswordChanged(String),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
 | 
					fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
 | 
				
			||||||
@ -102,31 +121,62 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        Msg::NoMessage => (),
 | 
					        Msg::NoMessage => (),
 | 
				
			||||||
        Msg::GetLoggedUser => {
 | 
					        Msg::GetLoggedUser => {
 | 
				
			||||||
            orders.skip(); // No need to rerender/ complicated way to move into the closure
 | 
					            orders.skip(); // No need to rerender
 | 
				
			||||||
            orders.perform_cmd(async {
 | 
					            orders.perform_cmd(async {
 | 
				
			||||||
                let response = fetch(
 | 
					                // create request
 | 
				
			||||||
 | 
					                let request = unwrap_or_return!(
 | 
				
			||||||
                    Request::new("/admin/json/get_logged_user/")
 | 
					                    Request::new("/admin/json/get_logged_user/")
 | 
				
			||||||
                        .method(Method::Post)
 | 
					                        .method(Method::Post)
 | 
				
			||||||
                        .json(&())
 | 
					                        .json(&()),
 | 
				
			||||||
                        .expect("serialization failed"),
 | 
					                    Msg::NotAuthenticated
 | 
				
			||||||
                )
 | 
					                );
 | 
				
			||||||
                .await
 | 
					                // perform and get response
 | 
				
			||||||
                .expect("HTTP request failed");
 | 
					                let response = unwrap_or_return!(fetch(request).await, Msg::NotAuthenticated);
 | 
				
			||||||
 | 
					                // validate response status
 | 
				
			||||||
                let user: User = response
 | 
					                let response = unwrap_or_return!(response.check_status(), Msg::NotAuthenticated);
 | 
				
			||||||
                    .check_status() // ensure we've got 2xx status
 | 
					                let user: User = unwrap_or_return!(response.json().await, Msg::NotAuthenticated);
 | 
				
			||||||
                    .expect("status check failed")
 | 
					 | 
				
			||||||
                    .json()
 | 
					 | 
				
			||||||
                    .await
 | 
					 | 
				
			||||||
                    .expect("deserialization failed");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Msg::UserReceived(user)
 | 
					                Msg::UserReceived(user)
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Msg::UserReceived(user) => model.user = Some(user),
 | 
					        Msg::UserReceived(user) => model.user = Some(user),
 | 
				
			||||||
 | 
					        Msg::NotAuthenticated => {if model.user.is_some() {model.user = None; logout(orders)}},
 | 
				
			||||||
 | 
					        Msg::Login => {login_user(model, orders)}
 | 
				
			||||||
 | 
					        Msg::UsernameChanged(s) => model.login_data.username = s,
 | 
				
			||||||
 | 
					        Msg::PasswordChanged(s) => model.login_data.password = s,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn logout(orders: &mut impl Orders<Msg>) {
 | 
				
			||||||
 | 
					    orders.perform_cmd(async {let request = Request::new("/admin/logout/");
 | 
				
			||||||
 | 
					    unwrap_or_return!(fetch(request).await, Msg::GetLoggedUser);
 | 
				
			||||||
 | 
					    Msg::NotAuthenticated});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn login_user(model: &mut Model, orders: &mut impl Orders<Msg>) {
 | 
				
			||||||
 | 
					    orders.skip(); // No need to rerender
 | 
				
			||||||
 | 
					    let data = model.login_data.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    orders.perform_cmd(async {
 | 
				
			||||||
 | 
					        let data = data;
 | 
				
			||||||
 | 
					        // create request
 | 
				
			||||||
 | 
					        let request = unwrap_or_return!(
 | 
				
			||||||
 | 
					            Request::new("/admin/json/login_user/")
 | 
				
			||||||
 | 
					                .method(Method::Post)
 | 
				
			||||||
 | 
					                .json(&data),
 | 
				
			||||||
 | 
					            Msg::NotAuthenticated
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        // perform and get response
 | 
				
			||||||
 | 
					        let response = unwrap_or_return!(fetch(request).await, Msg::NotAuthenticated);
 | 
				
			||||||
 | 
					        // validate response status
 | 
				
			||||||
 | 
					        let response = unwrap_or_return!(response.check_status(), Msg::NotAuthenticated);
 | 
				
			||||||
 | 
					        let user: User = unwrap_or_return!(response.json().await, Msg::NotAuthenticated);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Msg::UserReceived(user)
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Urls<'a> {
 | 
					pub struct Urls<'a> {
 | 
				
			||||||
    base_url: std::borrow::Cow<'a, Url>,
 | 
					    base_url: std::borrow::Cow<'a, Url>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -188,8 +238,14 @@ impl<'a> Urls<'a> {
 | 
				
			|||||||
fn view(model: &Model) -> Node<Msg> {
 | 
					fn view(model: &Model) -> Node<Msg> {
 | 
				
			||||||
    div![
 | 
					    div![
 | 
				
			||||||
        C!["page"],
 | 
					        C!["page"],
 | 
				
			||||||
        navigation::navigation(&model.i18n, &model.base_url, &model.user),
 | 
					        if let Some(user) = &model.user {
 | 
				
			||||||
        view_content(&model.page, &model.base_url),
 | 
					            div![
 | 
				
			||||||
 | 
					                navigation::navigation(&model.i18n, &model.base_url, user),
 | 
				
			||||||
 | 
					                view_content(&model.page, &model.base_url)
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            view_login(&model.i18n, &model)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -205,6 +261,39 @@ fn view_content(page: &Page, url: &Url) -> Node<Msg> {
 | 
				
			|||||||
    ]
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn view_login(lang: &I18n, model: &Model) -> Node<Msg> {
 | 
				
			||||||
 | 
					    let t = move |key: &str| lang.translate(key, None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    div![
 | 
				
			||||||
 | 
					        C!["center", "login"],
 | 
				
			||||||
 | 
					        div![
 | 
				
			||||||
 | 
					            label![t("username")],
 | 
				
			||||||
 | 
					            input![
 | 
				
			||||||
 | 
					                input_ev(Ev::Input, |s| { Msg::UsernameChanged(s) }),
 | 
				
			||||||
 | 
					                attrs![
 | 
				
			||||||
 | 
					        At::Type => "text",
 | 
				
			||||||
 | 
					        At::Placeholder => t("username"),
 | 
				
			||||||
 | 
					        At::Name => "username",
 | 
				
			||||||
 | 
					        At::Value => model.login_data.username],
 | 
				
			||||||
 | 
					                el_ref(&model.login_form.username)
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        div![
 | 
				
			||||||
 | 
					            label![t("password")],
 | 
				
			||||||
 | 
					            input![
 | 
				
			||||||
 | 
					                input_ev(Ev::Input, |s| { Msg::PasswordChanged(s) }),
 | 
				
			||||||
 | 
					                attrs![
 | 
				
			||||||
 | 
					            At::Type => "password",
 | 
				
			||||||
 | 
					            At::Placeholder => t("password"),
 | 
				
			||||||
 | 
					        At::Name => "password",
 | 
				
			||||||
 | 
					        At::Value => model.login_data.password],
 | 
				
			||||||
 | 
					                el_ref(&model.login_form.password)
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					        button![t("login"), ev(Ev::Click, |_| Msg::Login)]
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ------ ------
 | 
					// ------ ------
 | 
				
			||||||
//     Start
 | 
					//     Start
 | 
				
			||||||
// ------ ------
 | 
					// ------ ------
 | 
				
			||||||
 | 
				
			|||||||
@ -8,18 +8,14 @@ use crate::{i18n::I18n, Msg};
 | 
				
			|||||||
///
 | 
					///
 | 
				
			||||||
/// The menu options are translated using the i18n module.
 | 
					/// The menu options are translated using the i18n module.
 | 
				
			||||||
#[must_use]
 | 
					#[must_use]
 | 
				
			||||||
pub fn navigation(i18n: &I18n, base_url: &Url, user: &Option<User>) -> Node<Msg> {
 | 
					pub fn navigation(i18n: &I18n, base_url: &Url, user: &User) -> Node<Msg> {
 | 
				
			||||||
    // A shortcut for translating strings.
 | 
					    // A shortcut for translating strings.
 | 
				
			||||||
    let t = move |key: &str| i18n.translate(key, None);
 | 
					    let t = move |key: &str| i18n.translate(key, None);
 | 
				
			||||||
    // Translate the wellcome message
 | 
					    // Translate the wellcome message
 | 
				
			||||||
    let welcome = if let Some(user) = user {
 | 
					    let welcome = i18n.translate(
 | 
				
			||||||
        i18n.translate(
 | 
					 | 
				
			||||||
        "welcome-user",
 | 
					        "welcome-user",
 | 
				
			||||||
        Some(&fluent_args![ "username" => user.username.clone()]),
 | 
					        Some(&fluent_args![ "username" => user.username.clone()]),
 | 
				
			||||||
        )
 | 
					    );
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        t("welcome")
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    nav![
 | 
					    nav![
 | 
				
			||||||
        ol![
 | 
					        ol![
 | 
				
			||||||
            // A button for the homepage, the list of URLs
 | 
					            // A button for the homepage, the list of URLs
 | 
				
			||||||
@ -57,10 +53,7 @@ pub fn navigation(i18n: &I18n, base_url: &Url, user: &Option<User>) -> Node<Msg>
 | 
				
			|||||||
            // The Welcome message
 | 
					            // The Welcome message
 | 
				
			||||||
            li![div![welcome]],
 | 
					            li![div![welcome]],
 | 
				
			||||||
            // The logout button
 | 
					            // The logout button
 | 
				
			||||||
            li![a![
 | 
					            li![a![ev(Ev::Click, |_| Msg::NotAuthenticated), t("logout"),]]
 | 
				
			||||||
                attrs! {At::Href => "/admin/logout/"},
 | 
					 | 
				
			||||||
                t("logout"),
 | 
					 | 
				
			||||||
            ]]
 | 
					 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -281,7 +281,7 @@ pub async fn webservice(
 | 
				
			|||||||
            .wrap(IdentityService::new(
 | 
					            .wrap(IdentityService::new(
 | 
				
			||||||
                CookieIdentityPolicy::new(&[0; 32])
 | 
					                CookieIdentityPolicy::new(&[0; 32])
 | 
				
			||||||
                    .name("auth-cookie")
 | 
					                    .name("auth-cookie")
 | 
				
			||||||
                    .secure(false),
 | 
					                    .secure(true),
 | 
				
			||||||
            ))
 | 
					            ))
 | 
				
			||||||
            .data(tera.clone())
 | 
					            .data(tera.clone())
 | 
				
			||||||
            .service(actix_web_static_files::ResourceFiles::new(
 | 
					            .service(actix_web_static_files::ResourceFiles::new(
 | 
				
			||||||
@ -377,6 +377,10 @@ pub async fn webservice(
 | 
				
			|||||||
                            .route(
 | 
					                            .route(
 | 
				
			||||||
                                "/get_logged_user/",
 | 
					                                "/get_logged_user/",
 | 
				
			||||||
                                web::post().to(views::get_logged_user_json),
 | 
					                                web::post().to(views::get_logged_user_json),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                            .route(
 | 
				
			||||||
 | 
					                                "/login_user/",
 | 
				
			||||||
 | 
					                                web::post().to(views::process_login_json),
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    // login to the admin area
 | 
					                    // login to the admin area
 | 
				
			||||||
 | 
				
			|||||||
@ -213,12 +213,6 @@ impl NewUser {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Deserialize)]
 | 
					 | 
				
			||||||
pub struct LoginUser {
 | 
					 | 
				
			||||||
    pub username: String,
 | 
					 | 
				
			||||||
    pub password: String,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
pub trait LinkDbOperations<T> {
 | 
					pub trait LinkDbOperations<T> {
 | 
				
			||||||
    async fn get_link_by_code(code: &str, server_config: &ServerConfig) -> Result<T, ServerError>;
 | 
					    async fn get_link_by_code(code: &str, server_config: &ServerConfig) -> Result<T, ServerError>;
 | 
				
			||||||
 | 
				
			|||||||
@ -17,13 +17,13 @@ use queries::{authenticate, Role};
 | 
				
			|||||||
use shared::apirequests::{
 | 
					use shared::apirequests::{
 | 
				
			||||||
    general::{Message, Status},
 | 
					    general::{Message, Status},
 | 
				
			||||||
    links::{LinkDelta, LinkRequestForm},
 | 
					    links::{LinkDelta, LinkRequestForm},
 | 
				
			||||||
    users::{UserDelta, UserRequestForm},
 | 
					    users::{LoginUser, UserDelta, UserRequestForm},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use tera::{Context, Tera};
 | 
					use tera::{Context, Tera};
 | 
				
			||||||
use tracing::{error, info, instrument, warn};
 | 
					use tracing::{error, info, instrument, warn};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::forms::LinkForm;
 | 
					use crate::forms::LinkForm;
 | 
				
			||||||
use crate::models::{LoginUser, NewUser};
 | 
					use crate::models::NewUser;
 | 
				
			||||||
use crate::queries;
 | 
					use crate::queries;
 | 
				
			||||||
use crate::ServerError;
 | 
					use crate::ServerError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -74,7 +74,6 @@ pub async fn wasm_app(config: web::Data<crate::ServerConfig>) -> Result<HttpResp
 | 
				
			|||||||
    Ok(HttpResponse::Ok().body(
 | 
					    Ok(HttpResponse::Ok().body(
 | 
				
			||||||
        r#"<!DOCTYPE html>
 | 
					        r#"<!DOCTYPE html>
 | 
				
			||||||
        <html>
 | 
					        <html>
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        <head>
 | 
					        <head>
 | 
				
			||||||
          <meta charset="utf-8" />
 | 
					          <meta charset="utf-8" />
 | 
				
			||||||
          <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
 | 
					          <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
 | 
				
			||||||
@ -84,7 +83,6 @@ pub async fn wasm_app(config: web::Data<crate::ServerConfig>) -> Result<HttpResp
 | 
				
			|||||||
          <link rel="stylesheet" href="/static/admin.css">
 | 
					          <link rel="stylesheet" href="/static/admin.css">
 | 
				
			||||||
          <title>Server integration example</title>
 | 
					          <title>Server integration example</title>
 | 
				
			||||||
        </head>
 | 
					        </head>
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        <body>
 | 
					        <body>
 | 
				
			||||||
          <section id="app"><div class="lds-ellipsis">Loading: <div></div><div></div><div></div><div></div></div></section>
 | 
					          <section id="app"><div class="lds-ellipsis">Loading: <div></div><div></div><div></div><div></div></div></section>
 | 
				
			||||||
          <script type="module">
 | 
					          <script type="module">
 | 
				
			||||||
@ -92,7 +90,6 @@ pub async fn wasm_app(config: web::Data<crate::ServerConfig>) -> Result<HttpResp
 | 
				
			|||||||
            init('/app/pkg/package_bg.wasm');
 | 
					            init('/app/pkg/package_bg.wasm');
 | 
				
			||||||
          </script>
 | 
					          </script>
 | 
				
			||||||
        </body>
 | 
					        </body>
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        </html>"#,
 | 
					        </html>"#,
 | 
				
			||||||
    ))
 | 
					    ))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -178,7 +175,7 @@ pub async fn get_logged_user_json(
 | 
				
			|||||||
    let user = authenticate(&id, &config).await?;
 | 
					    let user = authenticate(&id, &config).await?;
 | 
				
			||||||
    match user {
 | 
					    match user {
 | 
				
			||||||
        Role::NotAuthenticated | Role::Disabled => {
 | 
					        Role::NotAuthenticated | Role::Disabled => {
 | 
				
			||||||
            Err(ServerError::User("User not logged in!".to_string()))
 | 
					            Ok(HttpResponse::Unauthorized().finish())
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Role::Regular { user } | Role::Admin { user } => Ok(HttpResponse::Ok().json2(&user)),
 | 
					        Role::Regular { user } | Role::Admin { user } => Ok(HttpResponse::Ok().json2(&user)),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -484,8 +481,58 @@ pub async fn process_login(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        Err(e) => {
 | 
					        Err(e) => {
 | 
				
			||||||
            info!("Failed to login: {}", e);
 | 
					            info!("Failed to login: {}", e);
 | 
				
			||||||
 | 
					            Ok(HttpResponse::Unauthorized().json2(&Status::Error(Message {
 | 
				
			||||||
 | 
					                message: "Failed to Login".to_string(),
 | 
				
			||||||
 | 
					            })))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[instrument(skip(id))]
 | 
				
			||||||
 | 
					pub async fn process_login_json(
 | 
				
			||||||
 | 
					    data: web::Json<LoginUser>,
 | 
				
			||||||
 | 
					    config: web::Data<crate::ServerConfig>,
 | 
				
			||||||
 | 
					    id: Identity,
 | 
				
			||||||
 | 
					) -> Result<HttpResponse, ServerError> {
 | 
				
			||||||
 | 
					    // query the username to see if a user by that name exists.
 | 
				
			||||||
 | 
					    let user = queries::get_user_by_name(&data.username, &config).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    match user {
 | 
				
			||||||
 | 
					        Ok(u) => {
 | 
				
			||||||
 | 
					            // get the password hash
 | 
				
			||||||
 | 
					            if let Some(hash) = &u.password.secret {
 | 
				
			||||||
 | 
					                // get the servers secret
 | 
				
			||||||
 | 
					                let secret = &config.secret;
 | 
				
			||||||
 | 
					                // validate the secret
 | 
				
			||||||
 | 
					                let valid = Verifier::default()
 | 
				
			||||||
 | 
					                    .with_hash(hash)
 | 
				
			||||||
 | 
					                    .with_password(&data.password)
 | 
				
			||||||
 | 
					                    .with_secret_key(secret.secret.as_ref().expect("No secret available"))
 | 
				
			||||||
 | 
					                    .verify()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // login the user
 | 
				
			||||||
 | 
					                if valid {
 | 
				
			||||||
 | 
					                    info!("Log-in of user: {}", &u.username);
 | 
				
			||||||
 | 
					                    let session_token = u.username.clone();
 | 
				
			||||||
 | 
					                    id.remember(session_token);
 | 
				
			||||||
 | 
					                    Ok(HttpResponse::Ok().json2(&u))
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    info!("Invalid password for user: {}", &u.username);
 | 
				
			||||||
                    Ok(redirect_builder("/admin/login/"))
 | 
					                    Ok(redirect_builder("/admin/login/"))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // should fail earlier if secret is missing.
 | 
				
			||||||
 | 
					                Ok(HttpResponse::Unauthorized().json2(&Status::Error(Message {
 | 
				
			||||||
 | 
					                    message: "Failed to Login".to_string(),
 | 
				
			||||||
 | 
					                })))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Err(e) => {
 | 
				
			||||||
 | 
					            info!("Failed to login: {}", e);
 | 
				
			||||||
 | 
					            Ok(HttpResponse::Unauthorized().json2(&Status::Error(Message {
 | 
				
			||||||
 | 
					                message: "Failed to Login".to_string(),
 | 
				
			||||||
 | 
					            })))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,16 @@ form {
 | 
				
			|||||||
    background-color: #eae9ea;
 | 
					    background-color: #eae9ea;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					div.login div {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 60px;
 | 
				
			||||||
 | 
					    display: table;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					div.login input {
 | 
				
			||||||
 | 
					    padding: 15px;
 | 
				
			||||||
 | 
					    margin-bottom: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.center table p {
 | 
					.center table p {
 | 
				
			||||||
    font-size: x-small;
 | 
					    font-size: x-small;
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,12 @@ impl Default for UserRequestForm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Deserialize, Default, Serialize, Clone)]
 | 
				
			||||||
 | 
					pub struct LoginUser {
 | 
				
			||||||
 | 
					    pub username: String,
 | 
				
			||||||
 | 
					    pub password: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The Struct that is responsible for creating and editing users.
 | 
					/// The Struct that is responsible for creating and editing users.
 | 
				
			||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
 | 
					#[derive(Default, Debug, Clone, Serialize, Deserialize)]
 | 
				
			||||||
pub struct UserDelta {
 | 
					pub struct UserDelta {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user