diff --git a/app/src/components/app.rs b/app/src/components/app.rs index 9be91d9..3c9bca7 100644 --- a/app/src/components/app.rs +++ b/app/src/components/app.rs @@ -85,7 +85,7 @@ impl Component for App { } if self.user_info.is_none() { self.route_dispatcher - .send(RouteRequest::ReplaceRoute(Route::new_no_state("/login"))); + .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login))); } true } @@ -138,7 +138,7 @@ impl App { match &self.user_info { None => { self.route_dispatcher - .send(RouteRequest::ReplaceRoute(Route::new_no_state("/login"))); + .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login))); } Some((user_name, is_admin)) => match &self.redirect_to { Some(url) => { @@ -148,7 +148,7 @@ impl App { None => { if *is_admin { self.route_dispatcher - .send(RouteRequest::ReplaceRoute(Route::new_no_state("/users"))); + .send(RouteRequest::ReplaceRoute(Route::from(AppRoute::ListUsers))); } else { self.route_dispatcher .send(RouteRequest::ReplaceRoute(Route::from( diff --git a/app/src/components/login.rs b/app/src/components/login.rs index ff42133..a34b4ba 100644 --- a/app/src/components/login.rs +++ b/app/src/components/login.rs @@ -15,6 +15,7 @@ use yew_form_derive::Model; pub struct LoginForm { common: CommonComponentParts, form: Form, + refreshing: bool, } /// The fields of the form, with the constraints. @@ -34,6 +35,7 @@ pub struct Props { pub enum Msg { Update, Submit, + AuthenticationRefreshResponse(Result<(String, bool)>), AuthenticationStartResponse( ( opaque::client::login::ClientLogin, @@ -99,6 +101,14 @@ impl CommonComponent for LoginForm { .emit(user_info.context("Could not log in")?); Ok(true) } + Msg::AuthenticationRefreshResponse(user_info) => { + self.refreshing = false; + self.common.cancel_task(); + if let Ok(user_info) = user_info { + self.common.on_logged_in.emit(user_info); + } + Ok(true) + } } } @@ -112,10 +122,19 @@ impl Component for LoginForm { type Properties = Props; fn create(props: Self::Properties, link: ComponentLink) -> Self { - LoginForm { + let mut app = LoginForm { common: CommonComponentParts::::create(props, link), form: Form::::new(FormModel::default()), + refreshing: true, + }; + if let Err(e) = + app.common + .call_backend(HostService::refresh, (), Msg::AuthenticationRefreshResponse) + { + ConsoleService::debug(&format!("Could not refresh auth: {}", e)); + app.refreshing = false; } + app } fn update(&mut self, msg: Self::Message) -> ShouldRender { @@ -128,63 +147,71 @@ impl Component for LoginForm { fn view(&self) -> Html { type Field = yew_form::Field; - html! { -
-
-
- - - + if self.refreshing { + html! { +
+ {"Loading"} +
+ } + } else { + html! { + +
+
+ + + +
+
- -
-
-
- - - +
+
+ + + +
+
- -
-
- - - {"Forgot your password?"} - -
-
- { if let Some(e) = &self.common.error { - html! { e.to_string() } - } else { html! {} } - } -
- +
+ + + {"Forgot your password?"} + +
+
+ { if let Some(e) = &self.common.error { + html! { e.to_string() } + } else { html! {} } + } +
+ + } } } } diff --git a/app/src/infra/api.rs b/app/src/infra/api.rs index 89d87d4..ba86114 100644 --- a/app/src/infra/api.rs +++ b/app/src/infra/api.rs @@ -227,6 +227,32 @@ impl HostService { ) } + pub fn refresh(_request: (), callback: Callback>) -> Result { + let set_cookies = |jwt_claims: JWTClaims| { + let is_admin = jwt_claims.groups.contains("lldap_admin"); + set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp) + .map(|_| set_cookie("is_admin", &is_admin.to_string(), &jwt_claims.exp)) + .map(|_| (jwt_claims.user.clone(), is_admin)) + .context("Error clearing cookie") + }; + let parse_token = move |data: String| { + serde_json::from_str::(&data) + .context("Could not parse response") + .and_then(|r| { + get_claims_from_jwt(r.token.as_str()) + .context("Could not parse response") + .and_then(set_cookies) + }) + }; + call_server( + "/auth/refresh", + yew::format::Nothing, + callback, + "Could not start authentication: ", + parse_token, + ) + } + // The `_request` parameter is to make it the same shape as the other functions. pub fn logout(_request: (), callback: Callback>) -> Result { call_server_empty_response_with_error_message( diff --git a/app/static/spinner.gif b/app/static/spinner.gif new file mode 100644 index 0000000..9590093 Binary files /dev/null and b/app/static/spinner.gif differ