about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin/kittybox_database_converter.rs4
-rw-r--r--src/bin/pyindieblog_to_kittybox.rs2
-rw-r--r--src/database/file/mod.rs24
-rw-r--r--src/frontend/login.rs235
-rw-r--r--src/frontend/mod.rs11
-rw-r--r--src/lib.rs6
-rw-r--r--src/main.rs2
-rw-r--r--src/micropub/get.rs4
-rw-r--r--src/micropub/post.rs15
9 files changed, 184 insertions, 119 deletions
diff --git a/src/bin/kittybox_database_converter.rs b/src/bin/kittybox_database_converter.rs
index 4dcd2ab..bc355c9 100644
--- a/src/bin/kittybox_database_converter.rs
+++ b/src/bin/kittybox_database_converter.rs
@@ -58,7 +58,7 @@ async fn convert_from_redis<S: Storage>(from: String, new_storage: S) -> anyhow:
             Ok(settings) => {
                 for (k, v) in settings.iter() {
                     if let Err(e) = storage
-                        .set_setting(k, &user, v)
+                        .set_setting(k, user, v)
                         .await
                         .with_context(|| format!("Failed setting {} for {}", k, user))
                     {
@@ -72,7 +72,7 @@ async fn convert_from_redis<S: Storage>(from: String, new_storage: S) -> anyhow:
         }
     }
 
-    return Ok(());
+    Ok(())
 }
 
 #[async_std::main]
diff --git a/src/bin/pyindieblog_to_kittybox.rs b/src/bin/pyindieblog_to_kittybox.rs
index 303ca56..38590c3 100644
--- a/src/bin/pyindieblog_to_kittybox.rs
+++ b/src/bin/pyindieblog_to_kittybox.rs
@@ -1,5 +1,5 @@
 use anyhow::{anyhow, Context, Result};
-use redis;
+
 use redis::AsyncCommands;
 use serde::{Deserialize, Serialize};
 use std::collections::HashMap;
diff --git a/src/database/file/mod.rs b/src/database/file/mod.rs
index d556f46..ee7d30b 100644
--- a/src/database/file/mod.rs
+++ b/src/database/file/mod.rs
@@ -88,7 +88,7 @@ mod tests {
 }
 
 fn url_to_path(root: &Path, url: &str) -> PathBuf {
-    url_to_relative_path(url).to_path(root).to_path_buf()
+    url_to_relative_path(url).to_path(root)
 }
 
 fn url_to_relative_path(url: &str) -> relative_path::RelativePathBuf {
@@ -321,11 +321,13 @@ impl Storage for FileStorage {
                     let orig = path.clone();
                     spawn_blocking::<_, Result<()>>(move || {
                         // We're supposed to have a parent here.
-                        let basedir = link.parent().ok_or(StorageError::new(
-                            ErrorKind::Backend,
-                            "Failed to calculate parent directory when creating a symlink",
-                        ))?;
-                        let relative = path_relative_from(&orig, &basedir).unwrap();
+                        let basedir = link.parent().ok_or_else(|| {
+                            StorageError::new(
+                                ErrorKind::Backend,
+                                "Failed to calculate parent directory when creating a symlink",
+                            )
+                        })?;
+                        let relative = path_relative_from(&orig, basedir).unwrap();
                         println!("{:?} - {:?} = {:?}", &orig, &basedir, &relative);
                         println!("Created a symlink at {:?}", &link);
                         let symlink_result;
@@ -374,7 +376,7 @@ impl Storage for FileStorage {
             let mut content = String::new();
             guard.read_to_string(&mut content).await?;
             let mut channels: Vec<super::MicropubChannel>;
-            if content.len() > 0 {
+            if !content.is_empty() {
                 channels = serde_json::from_str(&content)?;
             } else {
                 channels = Vec::default();
@@ -385,7 +387,7 @@ impl Storage for FileStorage {
                 name: post["properties"]["name"][0]
                     .as_str()
                     .map(|s| s.to_string())
-                    .unwrap_or_else(|| String::default()),
+                    .unwrap_or_else(String::default),
             });
             guard.seek(std::io::SeekFrom::Start(0)).await?;
             guard.set_len(0).await?;
@@ -438,7 +440,7 @@ impl Storage for FileStorage {
                 let mut content = String::new();
                 (&mut &*guard).read_to_string(&mut content).await?;
                 // This should not happen, but if it does, let's handle it gracefully instead of failing.
-                if content.len() == 0 {
+                if content.is_empty() {
                     return Ok(vec![]);
                 }
                 let channels: Vec<super::MicropubChannel> = serde_json::from_str(&content)?;
@@ -541,7 +543,7 @@ impl Storage for FileStorage {
         // it might come with a performance hit and/or memory usage inflation
         settings
             .get(setting)
-            .map(|s| s.clone())
+            .cloned()
             .ok_or_else(|| StorageError::new(ErrorKind::Backend, "Setting not set"))
     }
 
@@ -572,7 +574,7 @@ impl Storage for FileStorage {
         log::debug!("Locked. Writing.");
         let mut content = String::new();
         guard.read_to_string(&mut content).await?;
-        let mut settings: HashMap<String, String> = if content.len() == 0 {
+        let mut settings: HashMap<String, String> = if content.is_empty() {
             HashMap::default()
         } else {
             serde_json::from_str(&content)?
diff --git a/src/frontend/login.rs b/src/frontend/login.rs
index 09fa75f..1c7c662 100644
--- a/src/frontend/login.rs
+++ b/src/frontend/login.rs
@@ -1,15 +1,15 @@
-use std::convert::TryInto;
-use std::str::FromStr;
+use http_types::Mime;
 use log::{debug, error};
 use rand::Rng;
-use http_types::Mime;
+use serde::{Deserialize, Serialize};
+use sha2::{Digest, Sha256};
+use std::convert::TryInto;
+use std::str::FromStr;
 use tide::{Request, Response, Result};
-use serde::{Serialize, Deserialize};
-use sha2::{Sha256, Digest};
 
-use crate::frontend::{FrontendError, IndiewebEndpoints};
-use crate::{ApplicationState, database::Storage};
 use crate::frontend::templates::Template;
+use crate::frontend::{FrontendError, IndiewebEndpoints};
+use crate::{database::Storage, ApplicationState};
 
 markup::define! {
     LoginPage {
@@ -34,30 +34,36 @@ pub async fn form<S: Storage>(req: Request<ApplicationState<S>>) -> Result {
     let storage = &req.state().storage;
     let authorization_endpoint = req.state().authorization_endpoint.to_string();
     let token_endpoint = req.state().token_endpoint.to_string();
-    let blog_name = storage.get_setting("site_name", &owner).await.unwrap_or_else(|_| "Kitty Box!".to_string());
+    let blog_name = storage
+        .get_setting("site_name", &owner)
+        .await
+        .unwrap_or_else(|_| "Kitty Box!".to_string());
     let feeds = storage.get_channels(&owner).await.unwrap_or_default();
 
     Ok(Response::builder(200)
-       .body(Template {
-           title: "Sign in with IndieAuth",
-           blog_name: &blog_name,
-           endpoints: IndiewebEndpoints {
-               authorization_endpoint,
-               token_endpoint,
-               webmention: None,
-               microsub: None
-           },
-           feeds,
-           user: req.session().get("user"),
-           content: LoginPage {}.to_string(),
-       }.to_string())
-       .content_type("text/html; charset=utf-8")
-       .build())
+        .body(
+            Template {
+                title: "Sign in with IndieAuth",
+                blog_name: &blog_name,
+                endpoints: IndiewebEndpoints {
+                    authorization_endpoint,
+                    token_endpoint,
+                    webmention: None,
+                    microsub: None,
+                },
+                feeds,
+                user: req.session().get("user"),
+                content: LoginPage {}.to_string(),
+            }
+            .to_string(),
+        )
+        .content_type("text/html; charset=utf-8")
+        .build())
 }
 
 #[derive(Serialize, Deserialize)]
 struct LoginForm {
-    url: String
+    url: String,
 }
 
 #[derive(Serialize, Deserialize)]
@@ -67,21 +73,19 @@ struct IndieAuthClientState {
     /// The user's initial "me" value.
     me: String,
     /// Authorization endpoint used.
-    authorization_endpoint: String
+    authorization_endpoint: String,
 }
 
-
 #[derive(Serialize, Deserialize)]
 struct IndieAuthRequestParams {
     response_type: String,         // can only have "code". TODO make an enum
     client_id: String,             // always a URL. TODO consider making a URL
     redirect_uri: surf::Url,       // callback URI for IndieAuth
-    state: String,                 // CSRF protection, should include randomness and be passed through
-    code_challenge: String,        // base64-encoded PKCE challenge
+    state: String, // CSRF protection, should include randomness and be passed through
+    code_challenge: String, // base64-encoded PKCE challenge
     code_challenge_method: String, // usually "S256". TODO make an enum
-    scope: Option<String>,         // oAuth2 scopes to grant,
-    me: surf::Url,                 // User's entered profile URL
-    
+    scope: Option<String>, // oAuth2 scopes to grant,
+    me: surf::Url, // User's entered profile URL
 }
 
 /// Handle login requests. Find the IndieAuth authorization endpoint and redirect to it.
@@ -91,16 +95,22 @@ pub async fn handler<S: Storage>(mut req: Request<ApplicationState<S>>) -> Resul
         return Err(FrontendError::with_code(400, "Use the login form, Luke.").into());
     }
     if content_type.unwrap() != Mime::from_str("application/x-www-form-urlencoded").unwrap() {
-        return Err(FrontendError::with_code(400, "Login form results must be a urlencoded form").into());
+        return Err(
+            FrontendError::with_code(400, "Login form results must be a urlencoded form").into(),
+        );
     }
 
     let form = req.body_form::<LoginForm>().await?; // FIXME check if it returns 400 or 500 on error
     let homepage_uri = surf::Url::parse(&form.url)?;
     let http = &req.state().http_client;
-    
+
     let mut fetch_response = http.get(&homepage_uri).send().await?;
     if fetch_response.status() != 200 {
-        return Err(FrontendError::with_code(500, "Error fetching your authorization endpoint. Check if your website's okay.").into());
+        return Err(FrontendError::with_code(
+            500,
+            "Error fetching your authorization endpoint. Check if your website's okay.",
+        )
+        .into());
     }
 
     let mut authorization_endpoint: Option<surf::Url> = None;
@@ -123,14 +133,18 @@ pub async fn handler<S: Storage>(mut req: Request<ApplicationState<S>>) -> Resul
                                 || trimmed == "rel=authorization_endpoint"
                             {
                                 if let Ok(endpoint) = homepage_uri.join(uri) {
-                                    debug!("Found authorization endpoint {} for user {}", endpoint, homepage_uri.as_str());
+                                    debug!(
+                                        "Found authorization endpoint {} for user {}",
+                                        endpoint,
+                                        homepage_uri.as_str()
+                                    );
                                     authorization_endpoint = Some(endpoint);
                                     break;
                                 }
                             }
                         }
                     }
-                },
+                }
                 None => continue,
             }
         }
@@ -139,64 +153,93 @@ pub async fn handler<S: Storage>(mut req: Request<ApplicationState<S>>) -> Resul
     // bring out the big guns and parse HTML to find it.
     if authorization_endpoint.is_none() {
         let body = fetch_response.body_string().await?;
-        let pattern = easy_scraper::Pattern::new(r#"<link rel="authorization_endpoint" href="{{url}}">"#)
-            .expect("Cannot parse the pattern for authorization_endpoint");
+        let pattern =
+            easy_scraper::Pattern::new(r#"<link rel="authorization_endpoint" href="{{url}}">"#)
+                .expect("Cannot parse the pattern for authorization_endpoint");
         let matches = pattern.matches(&body);
         debug!("Matches for authorization_endpoint in HTML: {:?}", matches);
         if !matches.is_empty() {
             if let Ok(endpoint) = homepage_uri.join(&matches[0]["url"]) {
-                debug!("Found authorization endpoint {} for user {}", endpoint, homepage_uri.as_str());
+                debug!(
+                    "Found authorization endpoint {} for user {}",
+                    endpoint,
+                    homepage_uri.as_str()
+                );
                 authorization_endpoint = Some(endpoint)
             }
         }
     };
     // If even after this the authorization endpoint is still not found, bail out.
     if authorization_endpoint.is_none() {
-        error!("Couldn't find authorization_endpoint for {}", homepage_uri.as_str());
-        return Err(FrontendError::with_code(400, "Your website doesn't support the IndieAuth protocol.").into());
+        error!(
+            "Couldn't find authorization_endpoint for {}",
+            homepage_uri.as_str()
+        );
+        return Err(FrontendError::with_code(
+            400,
+            "Your website doesn't support the IndieAuth protocol.",
+        )
+        .into());
     }
     let mut authorization_endpoint: surf::Url = authorization_endpoint.unwrap();
     let mut rng = rand::thread_rng();
-    let state: String = data_encoding::BASE64URL.encode(serde_urlencoded::to_string(IndieAuthClientState {
-        nonce: (0..8).map(|_| {
+    let state: String = data_encoding::BASE64URL.encode(
+        serde_urlencoded::to_string(IndieAuthClientState {
+            nonce: (0..8)
+                .map(|_| {
+                    let idx = rng.gen_range(0..INDIEAUTH_PKCE_CHARSET.len());
+                    INDIEAUTH_PKCE_CHARSET[idx] as char
+                })
+                .collect(),
+            me: homepage_uri.to_string(),
+            authorization_endpoint: authorization_endpoint.to_string(),
+        })?
+        .as_bytes(),
+    );
+    // PKCE code generation
+    let code_verifier: String = (0..128)
+        .map(|_| {
             let idx = rng.gen_range(0..INDIEAUTH_PKCE_CHARSET.len());
             INDIEAUTH_PKCE_CHARSET[idx] as char
-        }).collect(),
-        me: homepage_uri.to_string(),
-        authorization_endpoint: authorization_endpoint.to_string()
-    })?.as_bytes());
-    // PKCE code generation
-    let code_verifier: String = (0..128).map(|_| {
-        let idx = rng.gen_range(0..INDIEAUTH_PKCE_CHARSET.len());
-        INDIEAUTH_PKCE_CHARSET[idx] as char
-    }).collect();
+        })
+        .collect();
     let mut hasher = Sha256::new();
     hasher.update(code_verifier.as_bytes());
     let code_challenge: String = data_encoding::BASE64URL.encode(&hasher.finalize());
 
-    authorization_endpoint.set_query(Some(&serde_urlencoded::to_string(IndieAuthRequestParams {
-        response_type: "code".to_string(),
-        client_id: req.url().origin().ascii_serialization(),
-        redirect_uri: req.url().join("login/callback")?,
-        state: state.clone(), code_challenge,
-        code_challenge_method: "S256".to_string(),
-        scope: Some("profile".to_string()),
-        me: homepage_uri,
-    })?));
+    authorization_endpoint.set_query(Some(&serde_urlencoded::to_string(
+        IndieAuthRequestParams {
+            response_type: "code".to_string(),
+            client_id: req.url().origin().ascii_serialization(),
+            redirect_uri: req.url().join("login/callback")?,
+            state: state.clone(),
+            code_challenge,
+            code_challenge_method: "S256".to_string(),
+            scope: Some("profile".to_string()),
+            me: homepage_uri,
+        },
+    )?));
 
     let cookies = vec![
-        format!(r#"indieauth_state="{}"; Same-Site: None; Secure; Max-Age: 600"#, state),
-        format!(r#"indieauth_code_verifier="{}"; Same-Site: None; Secure; Max-Age: 600"#, code_verifier)
+        format!(
+            r#"indieauth_state="{}"; Same-Site: None; Secure; Max-Age: 600"#,
+            state
+        ),
+        format!(
+            r#"indieauth_code_verifier="{}"; Same-Site: None; Secure; Max-Age: 600"#,
+            code_verifier
+        ),
     ];
 
-    let cookie_header = cookies.iter().map(|i| -> http_types::headers::HeaderValue {
-        (i as &str).try_into().unwrap()
-    }).collect::<Vec<_>>();
-    
+    let cookie_header = cookies
+        .iter()
+        .map(|i| -> http_types::headers::HeaderValue { (i as &str).try_into().unwrap() })
+        .collect::<Vec<_>>();
+
     Ok(Response::builder(302)
-       .header("Location", authorization_endpoint.to_string())
-       .header("Set-Cookie", &*cookie_header)
-       .build())
+        .header("Location", authorization_endpoint.to_string())
+        .header("Set-Cookie", &*cookie_header)
+        .build())
 }
 
 const INDIEAUTH_PKCE_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
@@ -211,12 +254,12 @@ struct IndieAuthCallbackResponse {
     #[allow(dead_code)]
     error_uri: Option<String>,
     // This needs to be further decoded to receive state back and will always be present
-    state: String
+    state: String,
 }
 
 impl IndieAuthCallbackResponse {
     fn is_successful(&self) -> bool {
-        !self.code.is_none()
+        self.code.is_some()
     }
 }
 
@@ -226,7 +269,7 @@ struct IndieAuthCodeRedeem {
     code: String,
     client_id: String,
     redirect_uri: String,
-    code_verifier: String
+    code_verifier: String,
 }
 
 #[derive(Serialize, Deserialize)]
@@ -234,7 +277,7 @@ struct IndieWebProfile {
     name: Option<String>,
     url: Option<String>,
     email: Option<String>,
-    photo: Option<String>
+    photo: Option<String>,
 }
 
 #[derive(Serialize, Deserialize)]
@@ -243,7 +286,7 @@ struct IndieAuthResponse {
     scope: Option<String>,
     access_token: Option<String>,
     token_type: Option<String>,
-    profile: Option<IndieWebProfile>
+    profile: Option<IndieWebProfile>,
 }
 
 /// Handle IndieAuth parameters, fetch the final h-card and redirect the user to the homepage.
@@ -252,41 +295,57 @@ pub async fn callback<S: Storage>(mut req: Request<ApplicationState<S>>) -> Resu
     let http: &surf::Client = &req.state().http_client;
     let origin = req.url().origin().ascii_serialization();
 
-    if req.cookie("indieauth_state").unwrap().value() != &params.state {
+    if req.cookie("indieauth_state").unwrap().value() != params.state {
         return Err(FrontendError::with_code(400, "The state doesn't match. A possible CSRF attack was prevented. Please try again later.").into());
     }
-    let state: IndieAuthClientState = serde_urlencoded::from_bytes(
-        &data_encoding::BASE64URL.decode(params.state.as_bytes())?
-    )?;
+    let state: IndieAuthClientState =
+        serde_urlencoded::from_bytes(&data_encoding::BASE64URL.decode(params.state.as_bytes())?)?;
 
     if !params.is_successful() {
-        return Err(FrontendError::with_code(400, &format!("The authorization endpoint indicated a following error: {:?}: {:?}", &params.error, &params.error_description)).into())
+        return Err(FrontendError::with_code(
+            400,
+            &format!(
+                "The authorization endpoint indicated a following error: {:?}: {:?}",
+                &params.error, &params.error_description
+            ),
+        )
+        .into());
     }
 
     let authorization_endpoint = surf::Url::parse(&state.authorization_endpoint).unwrap();
-    let mut code_response = http.post(authorization_endpoint)
+    let mut code_response = http
+        .post(authorization_endpoint)
         .body_string(serde_urlencoded::to_string(IndieAuthCodeRedeem {
             grant_type: "authorization_code".to_string(),
             code: params.code.unwrap().to_string(),
             client_id: origin.to_string(),
             redirect_uri: origin + "/login/callback",
-            code_verifier: req.cookie("indieauth_code_verifier").unwrap().value().to_string()
+            code_verifier: req
+                .cookie("indieauth_code_verifier")
+                .unwrap()
+                .value()
+                .to_string(),
         })?)
         .header("Content-Type", "application/x-www-form-urlencoded")
         .header("Accept", "application/json")
-        .send().await?;
+        .send()
+        .await?;
 
     if code_response.status() != 200 {
-        return Err(FrontendError::with_code(code_response.status(), &format!("Authorization endpoint returned an error when redeeming the code: {}", code_response.body_string().await?)).into());
+        return Err(FrontendError::with_code(
+            code_response.status(),
+            &format!(
+                "Authorization endpoint returned an error when redeeming the code: {}",
+                code_response.body_string().await?
+            ),
+        )
+        .into());
     }
 
     let json: IndieAuthResponse = code_response.body_json().await?;
-    drop(http);
     let session = req.session_mut();
     session.insert("user", &json.me)?;
 
     // TODO redirect to the page user came from
-    Ok(Response::builder(302)
-       .header("Location", "/")
-       .build())
+    Ok(Response::builder(302).header("Location", "/").build())
 }
diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs
index 76114c5..c0452f3 100644
--- a/src/frontend/mod.rs
+++ b/src/frontend/mod.rs
@@ -33,11 +33,14 @@ struct FrontendError {
     code: StatusCode,
 }
 impl FrontendError {
-    pub fn with_code<C>(code: C, msg: &str) -> Self where C: TryInto<StatusCode> {
+    pub fn with_code<C>(code: C, msg: &str) -> Self
+    where
+        C: TryInto<StatusCode>,
+    {
         Self {
             msg: msg.to_string(),
             source: None,
-            code: code.try_into().unwrap_or_else(|_| StatusCode::InternalServerError),
+            code: code.try_into().unwrap_or(StatusCode::InternalServerError),
         }
     }
     pub fn msg(&self) -> &str {
@@ -188,7 +191,7 @@ pub async fn onboarding_receiver<S: Storage>(mut req: Request<ApplicationState<S
 
     log::debug!("Creating feeds...");
     for feed in body.feeds {
-        if &feed.name == "" || &feed.slug == "" {
+        if feed.name.is_empty() || feed.slug.is_empty() {
             continue;
         };
         log::debug!("Creating feed {} with slug {}", &feed.name, &feed.slug);
@@ -408,7 +411,7 @@ where
     ) -> Result {
         let authorization_endpoint = request.state().authorization_endpoint.to_string();
         let token_endpoint = request.state().token_endpoint.to_string();
-        let owner = request.url().origin().ascii_serialization().clone() + "/";
+        let owner = request.url().origin().ascii_serialization() + "/";
         let site_name = &request
             .state()
             .storage
diff --git a/src/lib.rs b/src/lib.rs
index eb915c2..2b4d1cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -75,10 +75,10 @@ where
     app.with(
         tide::sessions::SessionMiddleware::new(
             tide::sessions::CookieStore::new(),
-            &app.state().cookie_secret.as_bytes()
+            app.state().cookie_secret.as_bytes(),
         )
-            .with_cookie_name("kittybox_session")
-            .without_save_unchanged()
+        .with_cookie_name("kittybox_session")
+        .without_save_unchanged(),
     );
     app
 }
diff --git a/src/main.rs b/src/main.rs
index 4f5f9ed..79e0cf5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -63,7 +63,7 @@ async fn main() -> Result<(), std::io::Error> {
     let cookie_secret: String = match env::var("COOKIE_SECRET").ok() {
         Some(value) => value,
         None => {
-            if let Some(filename) = env::var("COOKIE_SECRET_FILE").ok() {
+            if let Ok(filename) = env::var("COOKIE_SECRET_FILE") {
                 use async_std::io::ReadExt;
 
                 let mut file = async_std::fs::File::open(filename).await?;
diff --git a/src/micropub/get.rs b/src/micropub/get.rs
index 9732281..718714a 100644
--- a/src/micropub/get.rs
+++ b/src/micropub/get.rs
@@ -24,7 +24,7 @@ where
     match &*query.q {
         "config" => {
             let channels: Vec<MicropubChannel>;
-            match backend.get_channels(&user.me.as_str()).await {
+            match backend.get_channels(user.me.as_str()).await {
                 Ok(chans) => channels = chans,
                 Err(err) => return Ok(err.into())
             }
@@ -36,7 +36,7 @@ where
         },
         "channel" => {
             let channels: Vec<MicropubChannel>;
-            match backend.get_channels(&user.me.as_str()).await {
+            match backend.get_channels(user.me.as_str()).await {
                 Ok(chans) => channels = chans,
                 Err(err) => return Ok(err.into())
             }
diff --git a/src/micropub/post.rs b/src/micropub/post.rs
index c465a6f..de2b162 100644
--- a/src/micropub/post.rs
+++ b/src/micropub/post.rs
@@ -255,7 +255,7 @@ pub async fn new_post<S: Storage>(
                     || channel == vcards_channel
                     || channel == food_channel
                 {
-                    if let Err(err) = create_feed(storage, &uid, &channel, &user).await {
+                    if let Err(err) = create_feed(storage, &uid, &channel, user).await {
                         return error_json!(
                             500,
                             "database_error",
@@ -313,7 +313,7 @@ async fn create_feed(
             },
             "children": [uid]
         }),
-        &user,
+        user,
     );
     storage.put_post(&feed, user.me.as_str()).await
 }
@@ -483,8 +483,9 @@ async fn post_process_new_post<S: Storage>(
                 // TODO: Replace this function once the MF2 parser is ready
                 // A compliant parser's output format includes rels,
                 // we could just find a Webmention one in there
-                let pattern = easy_scraper::Pattern::new(r#"<link href="{{url}}" rel="webmention">"#)
-                    .expect("Pattern for webmentions couldn't be parsed");
+                let pattern =
+                    easy_scraper::Pattern::new(r#"<link href="{{url}}" rel="webmention">"#)
+                        .expect("Pattern for webmentions couldn't be parsed");
                 let matches = pattern.matches(&body);
                 if matches.is_empty() {
                     return None;
@@ -580,7 +581,7 @@ async fn process_json<S: Storage>(
                         "You're not allowed to delete someone else's posts."
                     );
                 }
-                if let Err(error) = req.state().storage.delete_post(&url).await {
+                if let Err(error) = req.state().storage.delete_post(url).await {
                     return Ok(error.into());
                 }
                 Ok(Response::builder(200).build())
@@ -602,7 +603,7 @@ async fn process_json<S: Storage>(
                         "You're not allowed to delete someone else's posts."
                     );
                 }
-                if let Err(error) = req.state().storage.update_post(&url, body.clone()).await {
+                if let Err(error) = req.state().storage.update_post(url, body.clone()).await {
                     Ok(error.into())
                 } else {
                     Ok(Response::builder(204).build())
@@ -679,7 +680,7 @@ async fn process_form<S: Storage>(
                             "You're not allowed to delete someone else's posts."
                         );
                     }
-                    if let Err(error) = req.state().storage.delete_post(&url).await {
+                    if let Err(error) = req.state().storage.delete_post(url).await {
                         return error_json!(500, "database_error", error);
                     }
                     return Ok(Response::builder(200).build());