mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
app: probe for password reset support
This commit is contained in:
parent
562ad524c4
commit
62104b417a
@ -13,10 +13,13 @@ use crate::{
|
|||||||
user_details::UserDetails,
|
user_details::UserDetails,
|
||||||
user_table::UserTable,
|
user_table::UserTable,
|
||||||
},
|
},
|
||||||
infra::cookies::get_cookie,
|
infra::{api::HostService, cookies::get_cookie},
|
||||||
|
};
|
||||||
|
|
||||||
|
use yew::{
|
||||||
|
prelude::*,
|
||||||
|
services::{fetch::FetchTask, ConsoleService},
|
||||||
};
|
};
|
||||||
use yew::prelude::*;
|
|
||||||
use yew::services::ConsoleService;
|
|
||||||
use yew_router::{
|
use yew_router::{
|
||||||
agent::{RouteAgentDispatcher, RouteRequest},
|
agent::{RouteAgentDispatcher, RouteRequest},
|
||||||
route::Route,
|
route::Route,
|
||||||
@ -29,11 +32,14 @@ pub struct App {
|
|||||||
user_info: Option<(String, bool)>,
|
user_info: Option<(String, bool)>,
|
||||||
redirect_to: Option<AppRoute>,
|
redirect_to: Option<AppRoute>,
|
||||||
route_dispatcher: RouteAgentDispatcher,
|
route_dispatcher: RouteAgentDispatcher,
|
||||||
|
password_reset_enabled: bool,
|
||||||
|
task: Option<FetchTask>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
Login((String, bool)),
|
Login((String, bool)),
|
||||||
Logout,
|
Logout,
|
||||||
|
PasswordResetProbeFinished(anyhow::Result<bool>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for App {
|
impl Component for App {
|
||||||
@ -58,7 +64,15 @@ impl Component for App {
|
|||||||
}),
|
}),
|
||||||
redirect_to: Self::get_redirect_route(),
|
redirect_to: Self::get_redirect_route(),
|
||||||
route_dispatcher: RouteAgentDispatcher::new(),
|
route_dispatcher: RouteAgentDispatcher::new(),
|
||||||
|
password_reset_enabled: false,
|
||||||
|
task: None,
|
||||||
};
|
};
|
||||||
|
app.task = Some(
|
||||||
|
HostService::probe_password_reset(
|
||||||
|
app.link.callback_once(Msg::PasswordResetProbeFinished),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
app.apply_initial_redirections();
|
app.apply_initial_redirections();
|
||||||
app
|
app
|
||||||
}
|
}
|
||||||
@ -82,6 +96,16 @@ impl Component for App {
|
|||||||
self.user_info = None;
|
self.user_info = None;
|
||||||
self.redirect_to = None;
|
self.redirect_to = None;
|
||||||
}
|
}
|
||||||
|
Msg::PasswordResetProbeFinished(Ok(enabled)) => {
|
||||||
|
self.task = None;
|
||||||
|
self.password_reset_enabled = enabled;
|
||||||
|
}
|
||||||
|
Msg::PasswordResetProbeFinished(Err(err)) => {
|
||||||
|
self.task = None;
|
||||||
|
ConsoleService::error(&format!(
|
||||||
|
"Could not probe for password reset support: {err:#}"
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.user_info.is_none() {
|
if self.user_info.is_none() {
|
||||||
self.route_dispatcher
|
self.route_dispatcher
|
||||||
@ -97,6 +121,7 @@ impl Component for App {
|
|||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let link = self.link.clone();
|
let link = self.link.clone();
|
||||||
let is_admin = self.is_admin();
|
let is_admin = self.is_admin();
|
||||||
|
let password_reset_enabled = self.password_reset_enabled;
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
{self.view_banner()}
|
{self.view_banner()}
|
||||||
@ -104,7 +129,7 @@ impl Component for App {
|
|||||||
<div class="row justify-content-center" style="padding-bottom: 80px;">
|
<div class="row justify-content-center" style="padding-bottom: 80px;">
|
||||||
<div class="py-3" style="max-width: 1000px">
|
<div class="py-3" style="max-width: 1000px">
|
||||||
<Router<AppRoute>
|
<Router<AppRoute>
|
||||||
render = Router::render(move |s| Self::dispatch_route(s, &link, is_admin))
|
render = Router::render(move |s| Self::dispatch_route(s, &link, is_admin, password_reset_enabled))
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -135,6 +160,10 @@ impl App {
|
|||||||
let route_service = RouteService::<()>::new();
|
let route_service = RouteService::<()>::new();
|
||||||
let current_route = route_service.get_path();
|
let current_route = route_service.get_path();
|
||||||
if current_route.contains("reset-password") {
|
if current_route.contains("reset-password") {
|
||||||
|
if !self.password_reset_enabled {
|
||||||
|
self.route_dispatcher
|
||||||
|
.send(RouteRequest::ReplaceRoute(Route::from(AppRoute::Login)));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match &self.user_info {
|
match &self.user_info {
|
||||||
@ -162,10 +191,15 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_route(switch: AppRoute, link: &ComponentLink<Self>, is_admin: bool) -> Html {
|
fn dispatch_route(
|
||||||
|
switch: AppRoute,
|
||||||
|
link: &ComponentLink<Self>,
|
||||||
|
is_admin: bool,
|
||||||
|
password_reset_enabled: bool,
|
||||||
|
) -> Html {
|
||||||
match switch {
|
match switch {
|
||||||
AppRoute::Login => html! {
|
AppRoute::Login => html! {
|
||||||
<LoginForm on_logged_in=link.callback(Msg::Login)/>
|
<LoginForm on_logged_in=link.callback(Msg::Login) password_reset_enabled=password_reset_enabled/>
|
||||||
},
|
},
|
||||||
AppRoute::CreateUser => html! {
|
AppRoute::CreateUser => html! {
|
||||||
<CreateUserForm/>
|
<CreateUserForm/>
|
||||||
@ -200,11 +234,23 @@ impl App {
|
|||||||
AppRoute::ChangePassword(username) => html! {
|
AppRoute::ChangePassword(username) => html! {
|
||||||
<ChangePasswordForm username=username is_admin=is_admin />
|
<ChangePasswordForm username=username is_admin=is_admin />
|
||||||
},
|
},
|
||||||
AppRoute::StartResetPassword => html! {
|
AppRoute::StartResetPassword => {
|
||||||
<ResetPasswordStep1Form />
|
if password_reset_enabled {
|
||||||
},
|
html! {
|
||||||
|
<ResetPasswordStep1Form />
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
App::dispatch_route(AppRoute::Login, link, is_admin, password_reset_enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
AppRoute::FinishResetPassword(token) => html! {
|
AppRoute::FinishResetPassword(token) => html! {
|
||||||
<ResetPasswordStep2Form token=token />
|
if password_reset_enabled {
|
||||||
|
html! {
|
||||||
|
<ResetPasswordStep2Form token=token />
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
App::dispatch_route(AppRoute::Login, link, is_admin, password_reset_enabled)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ pub struct FormModel {
|
|||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {
|
pub struct Props {
|
||||||
pub on_logged_in: Callback<(String, bool)>,
|
pub on_logged_in: Callback<(String, bool)>,
|
||||||
|
pub password_reset_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
@ -147,6 +148,7 @@ impl Component for LoginForm {
|
|||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
type Field = yew_form::Field<FormModel>;
|
type Field = yew_form::Field<FormModel>;
|
||||||
|
let password_reset_enabled = self.common.password_reset_enabled;
|
||||||
if self.refreshing {
|
if self.refreshing {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
@ -198,12 +200,18 @@ impl Component for LoginForm {
|
|||||||
<i class="bi-box-arrow-in-right me-2"/>
|
<i class="bi-box-arrow-in-right me-2"/>
|
||||||
{"Login"}
|
{"Login"}
|
||||||
</button>
|
</button>
|
||||||
<NavButton
|
{ if password_reset_enabled {
|
||||||
classes="btn-link btn"
|
html! {
|
||||||
disabled=self.common.is_task_running()
|
<NavButton
|
||||||
route=AppRoute::StartResetPassword>
|
classes="btn-link btn"
|
||||||
{"Forgot your password?"}
|
disabled=self.common.is_task_running()
|
||||||
</NavButton>
|
route=AppRoute::StartResetPassword>
|
||||||
|
{"Forgot your password?"}
|
||||||
|
</NavButton>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html!{}
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
{ if let Some(e) = &self.common.error {
|
{ if let Some(e) = &self.common.error {
|
||||||
|
@ -3,9 +3,11 @@ use anyhow::{anyhow, Context, Result};
|
|||||||
use graphql_client::GraphQLQuery;
|
use graphql_client::GraphQLQuery;
|
||||||
use lldap_auth::{login, registration, JWTClaims};
|
use lldap_auth::{login, registration, JWTClaims};
|
||||||
|
|
||||||
use yew::callback::Callback;
|
use yew::{
|
||||||
use yew::format::Json;
|
callback::Callback,
|
||||||
use yew::services::fetch::{Credentials, FetchOptions, FetchService, FetchTask, Request, Response};
|
format::Json,
|
||||||
|
services::fetch::{Credentials, FetchOptions, FetchService, FetchTask, Request, Response},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct HostService {}
|
pub struct HostService {}
|
||||||
@ -286,4 +288,17 @@ impl HostService {
|
|||||||
"Could not validate token",
|
"Could not validate token",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn probe_password_reset(callback: Callback<Result<bool>>) -> Result<FetchTask> {
|
||||||
|
let request = Request::get("/auth/reset/step1/lldap_unlikely_very_long_user_name")
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(yew::format::Nothing)?;
|
||||||
|
FetchService::fetch_with_options(
|
||||||
|
request,
|
||||||
|
get_default_options(),
|
||||||
|
create_handler(callback, move |status: http::StatusCode, _data: String| {
|
||||||
|
Ok(status != http::StatusCode::NOT_FOUND)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user