about summary refs log tree commit diff
path: root/kittybox-rs/src/micropub/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'kittybox-rs/src/micropub/mod.rs')
-rw-r--r--kittybox-rs/src/micropub/mod.rs145
1 files changed, 81 insertions, 64 deletions
diff --git a/kittybox-rs/src/micropub/mod.rs b/kittybox-rs/src/micropub/mod.rs
index d7be785..d8a84e6 100644
--- a/kittybox-rs/src/micropub/mod.rs
+++ b/kittybox-rs/src/micropub/mod.rs
@@ -1,15 +1,15 @@
 use crate::database::{MicropubChannel, Storage, StorageError};
 use crate::indieauth::User;
 use crate::micropub::util::form_to_mf2_json;
-use axum::TypedHeader;
 use axum::extract::{BodyStream, Query};
 use axum::headers::ContentType;
 use axum::response::{IntoResponse, Response};
+use axum::TypedHeader;
 use axum::{http::StatusCode, Extension};
-use tracing::{error, info, warn, debug};
 use serde::{Deserialize, Serialize};
 use serde_json::json;
 use std::fmt::Display;
+use tracing::{debug, error, info, warn};
 
 #[derive(Serialize, Deserialize, Debug, PartialEq)]
 #[serde(rename_all = "kebab-case")]
@@ -91,7 +91,7 @@ impl axum::response::IntoResponse for MicropubError {
     fn into_response(self) -> axum::response::Response {
         axum::response::IntoResponse::into_response((
             StatusCode::from(&self),
-            axum::response::Json(self)
+            axum::response::Json(self),
         ))
     }
 }
@@ -374,11 +374,8 @@ pub(crate) async fn _post<D: 'static + Storage>(
         }
     }
 
-    let reply = IntoResponse::into_response((
-        StatusCode::ACCEPTED,
-        [("Location", uid.as_str())],
-        ()
-    ));
+    let reply =
+        IntoResponse::into_response((StatusCode::ACCEPTED, [("Location", uid.as_str())], ()));
 
     tokio::task::spawn(background_processing(db, mf2, http));
 
@@ -486,11 +483,14 @@ async fn post_action<D: Storage>(
 
 enum PostBody {
     Action(MicropubAction),
-    MF2(serde_json::Value)
+    MF2(serde_json::Value),
 }
 
 #[tracing::instrument]
-async fn dispatch_body(mut body: BodyStream, content_type: ContentType) -> Result<PostBody, MicropubError> {
+async fn dispatch_body(
+    mut body: BodyStream,
+    content_type: ContentType,
+) -> Result<PostBody, MicropubError> {
     let body: Vec<u8> = {
         debug!("Buffering body...");
         use tokio_stream::StreamExt;
@@ -538,7 +538,7 @@ async fn dispatch_body(mut body: BodyStream, content_type: ContentType) -> Resul
     } else {
         Err(MicropubError::new(
             ErrorType::UnsupportedMediaType,
-            "This Content-Type is not recognized. Try application/json instead?"
+            "This Content-Type is not recognized. Try application/json instead?",
         ))
     }
 }
@@ -549,28 +549,28 @@ pub async fn post<D: Storage + 'static>(
     Extension(http): Extension<reqwest::Client>,
     user: User,
     body: BodyStream,
-    TypedHeader(content_type): TypedHeader<ContentType>
+    TypedHeader(content_type): TypedHeader<ContentType>,
 ) -> axum::response::Response {
     match dispatch_body(body, content_type).await {
         Ok(PostBody::Action(action)) => match post_action(action, db, user).await {
             Ok(()) => Response::default(),
-            Err(err) => err.into_response()
+            Err(err) => err.into_response(),
         },
         Ok(PostBody::MF2(mf2)) => {
             let (uid, mf2) = normalize_mf2(mf2, &user);
             match _post(user, uid, mf2, db, http).await {
                 Ok(response) => response,
-                Err(err) => err.into_response()
+                Err(err) => err.into_response(),
             }
-        },
-        Err(err) => err.into_response()
+        }
+        Err(err) => err.into_response(),
     }
 }
 
 pub async fn query<D: Storage>(
     Extension(db): Extension<D>,
     Query(query): Query<MicropubQuery>,
-    user: User
+    user: User,
 ) -> axum::response::Response {
     let host = axum::http::Uri::try_from(user.me.as_str())
         .unwrap()
@@ -582,10 +582,13 @@ pub async fn query<D: Storage>(
         QueryType::Config => {
             let channels: Vec<MicropubChannel> = match db.get_channels(host.as_str()).await {
                 Ok(chans) => chans,
-                Err(err) => return MicropubError::new(
-                    ErrorType::InternalServerError,
-                    &format!("Error fetching channels: {}", err)
-                ).into_response(),
+                Err(err) => {
+                    return MicropubError::new(
+                        ErrorType::InternalServerError,
+                        &format!("Error fetching channels: {}", err),
+                    )
+                    .into_response()
+                }
             };
 
             axum::response::Json(json!({
@@ -598,50 +601,59 @@ pub async fn query<D: Storage>(
                 "channels": channels,
                 "_kittybox_authority": host.as_str(),
                 "syndicate-to": []
-            })).into_response()
-        },
+            }))
+            .into_response()
+        }
         QueryType::Source => {
             match query.url {
                 Some(url) => {
-                    if axum::http::Uri::try_from(&url).unwrap().authority().unwrap() != &host {
+                    if axum::http::Uri::try_from(&url)
+                        .unwrap()
+                        .authority()
+                        .unwrap()
+                        != &host
+                    {
                         return MicropubError::new(
                             ErrorType::NotAuthorized,
-                            "You are requesting a post from a website that doesn't belong to you."
-                        ).into_response()
+                            "You are requesting a post from a website that doesn't belong to you.",
+                        )
+                        .into_response();
                     }
                     match db.get_post(&url).await {
                         Ok(some) => match some {
                             Some(post) => axum::response::Json(&post).into_response(),
                             None => MicropubError::new(
                                 ErrorType::NotFound,
-                                "The specified MF2 object was not found in database."
-                            ).into_response()
+                                "The specified MF2 object was not found in database.",
+                            )
+                            .into_response(),
                         },
                         Err(err) => MicropubError::new(
                             ErrorType::InternalServerError,
-                            &format!("Backend error: {}", err)
-                        ).into_response()
+                            &format!("Backend error: {}", err),
+                        )
+                        .into_response(),
                     }
-                },
+                }
                 None => {
                     // Here, one should probably attempt to query at least the main feed and collect posts
                     // Using a pre-made query function can't be done because it does unneeded filtering
                     // Don't implement for now, this is optional
                     MicropubError::new(
                         ErrorType::InvalidRequest,
-                        "Querying for post list is not implemented yet."
-                    ).into_response()
+                        "Querying for post list is not implemented yet.",
+                    )
+                    .into_response()
                 }
             }
-        },
-        QueryType::Channel => {
-            match db.get_channels(host.as_str()).await {
-                Ok(chans) => axum::response::Json(json!({"channels": chans})).into_response(),
-                Err(err) => MicropubError::new(
-                    ErrorType::InternalServerError,
-                    &format!("Error fetching channels: {}", err)
-                ).into_response()
-            }
+        }
+        QueryType::Channel => match db.get_channels(host.as_str()).await {
+            Ok(chans) => axum::response::Json(json!({ "channels": chans })).into_response(),
+            Err(err) => MicropubError::new(
+                ErrorType::InternalServerError,
+                &format!("Error fetching channels: {}", err),
+            )
+            .into_response(),
         },
         QueryType::SyndicateTo => {
             axum::response::Json(json!({ "syndicate-to": [] })).into_response()
@@ -725,16 +737,16 @@ mod tests {
         let user = crate::indieauth::User::new(
             "https://localhost:8080/",
             "https://kittybox.fireburn.ru/",
-            "profile"
+            "profile",
         );
         let (uid, mf2) = super::normalize_mf2(post, &user);
-        
-        let err = super::_post(
-            user, uid, mf2, db.clone(), reqwest::Client::new()
-        ).await.unwrap_err();
+
+        let err = super::_post(user, uid, mf2, db.clone(), reqwest::Client::new())
+            .await
+            .unwrap_err();
 
         assert_eq!(err.error, super::ErrorType::InvalidScope);
-        
+
         let hashmap = db.mapping.read().await;
         assert!(hashmap.is_empty());
     }
@@ -754,21 +766,20 @@ mod tests {
         let user = crate::indieauth::User::new(
             "https://aaronparecki.com/",
             "https://kittybox.fireburn.ru/",
-            "create update media"
+            "create update media",
         );
         let (uid, mf2) = super::normalize_mf2(post, &user);
-        
-        let err = super::_post(
-            user, uid, mf2, db.clone(), reqwest::Client::new()
-        ).await.unwrap_err();
+
+        let err = super::_post(user, uid, mf2, db.clone(), reqwest::Client::new())
+            .await
+            .unwrap_err();
 
         assert_eq!(err.error, super::ErrorType::Forbidden);
-        
+
         let hashmap = db.mapping.read().await;
         assert!(hashmap.is_empty());
     }
 
-    
     #[tokio::test]
     async fn test_post_mf2() {
         let db = crate::database::MemoryStorage::new();
@@ -782,31 +793,37 @@ mod tests {
         let user = crate::indieauth::User::new(
             "https://localhost:8080/",
             "https://kittybox.fireburn.ru/",
-            "create"
+            "create",
         );
         let (uid, mf2) = super::normalize_mf2(post, &user);
 
-        let res = super::_post(
-            user, uid, mf2, db.clone(), reqwest::Client::new()
-        ).await.unwrap();
+        let res = super::_post(user, uid, mf2, db.clone(), reqwest::Client::new())
+            .await
+            .unwrap();
 
         assert!(res.headers().contains_key("Location"));
         let location = res.headers().get("Location").unwrap();
         assert!(db.post_exists(location.to_str().unwrap()).await.unwrap());
-        assert!(db.post_exists("https://localhost:8080/feeds/main").await.unwrap());
+        assert!(db
+            .post_exists("https://localhost:8080/feeds/main")
+            .await
+            .unwrap());
     }
 
     #[tokio::test]
     async fn test_query_foreign_url() {
         let mut res = super::query(
             axum::Extension(crate::database::MemoryStorage::new()),
-            axum::extract::Query(super::MicropubQuery::source("https://aaronparecki.com/feeds/main")),
+            axum::extract::Query(super::MicropubQuery::source(
+                "https://aaronparecki.com/feeds/main",
+            )),
             crate::indieauth::User::new(
                 "https://fireburn.ru/",
                 "https://quill.p3k.io/",
-                "create update media"
-            )
-        ).await;
+                "create update media",
+            ),
+        )
+        .await;
 
         assert_eq!(res.status(), 401);
         let body = res.body_mut().data().await.unwrap().unwrap();