Dynamically check username

This commit is contained in:
Pierre HUBERT 2022-04-07 17:57:10 +02:00
parent 91d71c7006
commit a6acbde093
5 changed files with 81 additions and 6 deletions

View File

@ -28,6 +28,13 @@ pub struct GetUserRequest(pub UserID);
#[derive(Debug)] #[derive(Debug)]
pub struct GetUserResult(pub Option<User>); pub struct GetUserResult(pub Option<User>);
#[derive(Message)]
#[rtype(FindUserByUsernameResult)]
pub struct FindUserByUsername(pub String);
#[derive(Debug)]
pub struct FindUserByUsernameResult(pub Option<User>);
#[derive(Message)] #[derive(Message)]
#[rtype(GetAllUsersResult)] #[rtype(GetAllUsersResult)]
pub struct GetAllUsersRequest; pub struct GetAllUsersRequest;
@ -98,6 +105,14 @@ impl Handler<GetUserRequest> for UsersActor {
} }
} }
impl Handler<FindUserByUsername> for UsersActor {
type Result = MessageResult<FindUserByUsername>;
fn handle(&mut self, msg: FindUserByUsername, _ctx: &mut Self::Context) -> Self::Result {
MessageResult(FindUserByUsernameResult(self.manager.find_by_username_or_email(&msg.0)))
}
}
impl Handler<GetAllUsersRequest> for UsersActor { impl Handler<GetAllUsersRequest> for UsersActor {
type Result = MessageResult<GetAllUsersRequest>; type Result = MessageResult<GetAllUsersRequest>;

View File

@ -0,0 +1,21 @@
use actix::Addr;
use actix_web::{HttpResponse, Responder, web};
use crate::actors::users_actor::{FindUserByUsername, UsersActor};
#[derive(serde::Deserialize)]
pub struct FindUserNameReq {
username: String,
}
#[derive(serde::Serialize)]
struct FindUserResult {
user_id: Option<String>,
}
pub async fn find_username(req: web::Form<FindUserNameReq>, users: web::Data<Addr<UsersActor>>) -> impl Responder {
let res = users.send(FindUserByUsername(req.0.username)).await.unwrap();
HttpResponse::Ok().json(FindUserResult {
user_id: res.0.map(|r| r.uid)
})
}

View File

@ -2,4 +2,5 @@ pub mod assets_controller;
pub mod base_controller; pub mod base_controller;
pub mod login_controller; pub mod login_controller;
pub mod settings_controller; pub mod settings_controller;
pub mod admin_controller; pub mod admin_controller;
pub mod admin_api;

View File

@ -8,11 +8,8 @@ use clap::Parser;
use basic_oidc::actors::bruteforce_actor::BruteForceActor; use basic_oidc::actors::bruteforce_actor::BruteForceActor;
use basic_oidc::actors::users_actor::UsersActor; use basic_oidc::actors::users_actor::UsersActor;
use basic_oidc::constants::{ use basic_oidc::constants::*;
DEFAULT_ADMIN_PASSWORD, DEFAULT_ADMIN_USERNAME, MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, use basic_oidc::controllers::*;
SESSION_COOKIE_NAME,
};
use basic_oidc::controllers::{admin_controller, settings_controller};
use basic_oidc::controllers::assets_controller::assets_route; use basic_oidc::controllers::assets_controller::assets_route;
use basic_oidc::controllers::login_controller::{login_route, logout_route}; use basic_oidc::controllers::login_controller::{login_route, logout_route};
use basic_oidc::data::app_config::AppConfig; use basic_oidc::data::app_config::AppConfig;
@ -120,6 +117,9 @@ async fn main() -> std::io::Result<()> {
.route("/admin/clients", web::get().to(admin_controller::clients_route)) .route("/admin/clients", web::get().to(admin_controller::clients_route))
.route("/admin/users", web::get().to(admin_controller::users_route)) .route("/admin/users", web::get().to(admin_controller::users_route))
.route("/admin/create_user", web::get().to(admin_controller::create_user)) .route("/admin/create_user", web::get().to(admin_controller::create_user))
// Admin API
.route("/admin/api/find_username", web::post().to(admin_api::find_username))
}) })
.bind(listen_address)? .bind(listen_address)?
.run() .run()

View File

@ -14,6 +14,8 @@
<label class="form-label mt-4" for="username">User name</label> <label class="form-label mt-4" for="username">User name</label>
<input class="form-control" id="username" type="text" <input class="form-control" id="username" type="text"
name="username" value="{{ u.username }}" required/> name="username" value="{{ u.username }}" required/>
<div class="valid-feedback">This username is valid</div>
<div class="invalid-feedback">This username is already taken.</div>
</div> </div>
<!-- First name --> <!-- First name -->
@ -99,6 +101,39 @@
</form> </form>
<script> <script>
// Check Username
async function find_username(username) {
let data = new URLSearchParams();
data.append("username", username);
return (await(await fetch("/admin/api/find_username", {
body: data,
method: "POST",
})).json()).user_id
}
const usernameEl = document.getElementById("username")
async function check_username() {
try {
usernameEl.classList.remove("is-invalid");
usernameEl.classList.remove("is-valid");
if (usernameEl.value === "")
return;
const userID = await find_username(usernameEl.value);
usernameEl.classList.add((userID === null || userID === "{{ u.uid }}") ? "is-valid" : "is-invalid");
} catch(e) {
console.error(e);
}
}
check_username();
usernameEl.addEventListener("change", check_username);
usernameEl.addEventListener("keyup", check_username);
// Clients granted // Clients granted
function refreshDisplayAuthorizedClients() { function refreshDisplayAuthorizedClients() {
const clientsSelectorEl = document.getElementById("clients_target"); const clientsSelectorEl = document.getElementById("clients_target");
@ -110,5 +145,8 @@
el.addEventListener("change", refreshDisplayAuthorizedClients) el.addEventListener("change", refreshDisplayAuthorizedClients)
}) })
</script> </script>
{% endblock content %} {% endblock content %}