From 484a58e6f450e41aa3b2b91c17198726f948daaa Mon Sep 17 00:00:00 2001 From: Paul Z Date: Mon, 23 Oct 2023 22:30:21 +0200 Subject: [PATCH] delete bin endpoint --- server/src/error.rs | 8 +++++ server/src/main.rs | 73 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/server/src/error.rs b/server/src/error.rs index a6a6d7a..f74faf7 100644 --- a/server/src/error.rs +++ b/server/src/error.rs @@ -38,6 +38,12 @@ pub enum Error { #[error("invalid ttl")] InvalidTtl, + + #[error("unauthorized")] + Unauthorized, + + #[error("forbidden")] + Forbidden, } impl IntoResponse for Error { @@ -54,6 +60,8 @@ impl IntoResponse for Error { (StatusCode::BAD_REQUEST, "invalid multipart data").into_response() } Self::InvalidTtl => (StatusCode::BAD_REQUEST, "invalid ttl specified").into_response(), + Self::Unauthorized => (StatusCode::UNAUTHORIZED, "unauthorized\n").into_response(), + Self::Forbidden => (StatusCode::FORBIDDEN, "forbidden\n").into_response(), _ => { error!("{:?}", self); (StatusCode::INTERNAL_SERVER_ERROR, "internal server error\n").into_response() diff --git a/server/src/main.rs b/server/src/main.rs index 60f1461..296f07e 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -32,12 +32,12 @@ use chacha20::{ }; use futures_util::StreamExt; use garbage_collector::GarbageCollector; -use log::debug; +use log::{debug, warn}; use render::{html, raw}; use serde::Deserialize; use sha3::{Digest, Sha3_256}; use tokio::{ - fs::File, + fs::{self, File}, io::{AsyncWriteExt, BufReader, BufWriter}, }; use util::{IdSalt, KeySalt}; @@ -147,7 +147,14 @@ async fn main() { let app = Router::new() .route("/", get(get_index)) - .route("/:id", get(get_item).post(post_item).put(post_item)) + .route( + "/:id", + get(get_item) + .post(upload_bin) + .put(upload_bin) + .delete(delete_bin), + ) + .route("/:id/delete", get(delete_bin_interactive).post(delete_bin)) .with_state(state); axum::Server::bind(&"[::]:8080".parse().expect("valid listen address")) .serve(app.into_make_service()) @@ -195,12 +202,69 @@ async fn get_index( ))) } +async fn delete_bin( + Path(phrase): Path, + State(app_state): State, + oidc_extractor: Result, axum_oidc::error::Error>, + jwt_claims: Option>, +) -> HandlerResult { + let subject = match (oidc_extractor, jwt_claims) { + (_, Some(claims)) => claims.sub.to_string(), + (Ok(oidc), None) => oidc.claims.subject().to_string(), + (Err(_), None) => return Err(Error::Unauthorized), + }; + + let phrase = Phrase::from_str(&phrase)?; + let id = Id::from_phrase(&phrase, &app_state.id_salt); + + let metadata_path = format!("{}/{}.toml", app_state.data, id); + let metadata = Metadata::from_file(&metadata_path).await?; + + if metadata.subject != subject { + return Err(Error::Forbidden); + } + + debug!("deleting bin {}", id); + let res_meta = fs::remove_file(&format!("{}/{}.toml", app_state.data, id)).await; + let res_data = fs::remove_file(&format!("{}/{}.dat", app_state.data, id)).await; + + if res_meta.is_err() || res_data.is_err() { + warn!("failed to delete bin {} for manual deletion", id); + } + + Ok("ok\n") +} + +async fn delete_bin_interactive( + _: Path, + _: OidcExtractor, +) -> HandlerResult { + let body = html! { + + + {"zettoit bin"} + + + +
+

{"Confirm Deletion"}

+

{"The bin will be deleted. All data will be permanently lost."}

+
+ +
+
+ + + }; + Ok(Html(body)) +} + #[derive(Deserialize)] pub struct PostQuery { ttl: Option, } -async fn post_item( +async fn upload_bin( Path(phrase): Path, Query(params): Query, State(app_state): State, @@ -308,7 +372,6 @@ async fn post_item( } } -#[debug_handler] async fn get_item( Path(phrase): Path, State(app_state): State,