From b7b875baec52fb63e7c04d662ae6bd00d00c5ff6 Mon Sep 17 00:00:00 2001 From: Xander Bil Date: Sun, 2 Jun 2024 22:54:04 +0200 Subject: [PATCH] add endpoint to retrieve other user ssh keys --- src/controllers/users_controller.rs | 55 +++++++++++++++++++++-------- src/lib.rs | 1 + src/models/user.rs | 1 + templates/users/show.html | 9 +++++ tests/users.rs | 14 ++++++++ 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/controllers/users_controller.rs b/src/controllers/users_controller.rs index abc001d..80cdcce 100644 --- a/src/controllers/users_controller.rs +++ b/src/controllers/users_controller.rs @@ -47,6 +47,7 @@ pub async fn show_user<'r>( html: template!("users/show.html"; user: User = user.clone(), current_user: User = session.user, + errors: Option = None ), json: Json(user), }) @@ -58,6 +59,24 @@ pub async fn show_user<'r>( } } +#[get("/users/keys/")] +pub async fn show_ssh_key<'r>( + db: DbConn, + username: String, +) -> Json> { + let user = User::find_by_username(username, &db).await.unwrap(); + let mut keys = vec![]; + if let Some(ssh_keys) = user.ssh_key { + for line in ssh_keys.lines() { + let line = line.trim(); + if !line.is_empty() { + keys.push(line.to_string()) + } + } + } + Json(keys) +} + #[get("/users")] pub async fn list_users<'r>( session: AdminSession, @@ -184,27 +203,35 @@ pub async fn register<'r>( } #[put("/users/", data = "")] -pub async fn update_user<'r>( +pub async fn update_user<'r, 'o: 'r>( username: String, change: Api, session: UserSession, db: DbConn, -) -> Result< - Either< - impl Responder<'r, 'static>, - Custom>, - >, -> { +) -> Result> { let mut user = User::find_by_username(username, &db).await?; if session.user.id == user.id || session.user.admin { - user.change_with(change.into_inner())?; - let user = user.update(&db).await?; - Ok(Left(Accepter { - html: Redirect::to(uri!(show_user(user.username))), - json: Custom(Status::NoContent, ()), - })) + match user.change_with(change.into_inner()) { + Ok(()) => { + let user = user.update(&db).await?; + Ok(OneOf::One(Accepter { + html: Redirect::to(uri!(show_user(user.username))), + json: Custom(Status::NoContent, ()), + })) + }, + Err(ZauthError::ValidationError(errors)) => Ok(OneOf::Two(Custom( + Status::UnprocessableEntity, + template! { + "users/show.html"; + user: User = user, + current_user: User = session.user, + errors: Option = Some(errors.clone()), + }, + ))), + Err(other) => Err(other), + } } else { - Ok(Right(Custom(Status::Forbidden, ()))) + Ok(OneOf::Three(Custom(Status::Forbidden, ()))) } } diff --git a/src/lib.rs b/src/lib.rs index bd2fdd9..02cd6aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,6 +123,7 @@ fn assemble(rocket: Rocket) -> Rocket { users_controller::register, users_controller::current_user, users_controller::show_user, + users_controller::show_ssh_key, users_controller::list_users, users_controller::update_user, users_controller::change_state, diff --git a/src/models/user.rs b/src/models/user.rs index 2c8bfd3..cba287e 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -436,6 +436,7 @@ impl User { self.ssh_key = Some(ssh_key); } self.subscribed_to_mailing_list = change.subscribed_to_mailing_list; + self.validate()?; Ok(()) } diff --git a/templates/users/show.html b/templates/users/show.html index b3c223b..3ec9e0c 100644 --- a/templates/users/show.html +++ b/templates/users/show.html @@ -25,6 +25,15 @@
Update profile information
+ + {% match errors %} + {% when Some with (errors) %} +
+ {{ errors }} +
+ {% when None %} + {% endmatch %} +
diff --git a/tests/users.rs b/tests/users.rs index 9095c75..4ab2c1b 100644 --- a/tests/users.rs +++ b/tests/users.rs @@ -163,6 +163,20 @@ async fn show_user_as_admin() { #[rocket::async_test] async fn update_self() { common::as_user(async move |http_client, db, user| { + let response = http_client + .put(format!("/users/{}", user.username)) + .header(ContentType::Form) + .header(Accept::JSON) + .body("ssh_key=ssh-fake%20supersecretkey") + .dispatch() + .await; + + assert_eq!( + response.status(), + Status::UnprocessableEntity, + "user should not be able to update invalid public ssh key" + ); + let response = http_client .put(format!("/users/{}", user.username)) .header(ContentType::Form)