about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2024-08-28 14:51:13 +0300
committerVika <vika@fireburn.ru>2024-08-28 14:51:13 +0300
commite03ff3151878851af954aa2e9a17e7578873bbae (patch)
tree5f09b60194c96794e42599196ae6ad470a62938f /src
parent60becdedcdf78a7c643ad100bf95799b2d5b9625 (diff)
downloadkittybox-e03ff3151878851af954aa2e9a17e7578873bbae.tar.zst
Check validity of Micropub updates
In Kittybox, Micropub updates cannot modify UIDs, since UIDs are used
as a primary key.

Additional constraints may be added later, and perhaps I'll add a
Storage method that would check backend-specific constraints.
Diffstat (limited to 'src')
-rw-r--r--src/micropub/mod.rs56
1 files changed, 50 insertions, 6 deletions
diff --git a/src/micropub/mod.rs b/src/micropub/mod.rs
index 944506d..9838e5a 100644
--- a/src/micropub/mod.rs
+++ b/src/micropub/mod.rs
@@ -360,6 +360,47 @@ pub struct MicropubUpdate {
     pub delete: Option<MicropubPropertyDeletion>,
 }
 impl MicropubUpdate {
+    pub fn check_validity(&self) -> Result<(), MicropubError> {
+        if let Some(add) = &self.add {
+            if add.iter().map(|(k, _)| k.as_str()).any(|k| {
+                k.to_lowercase().as_str() == "uid"
+            }) {
+                return Err(MicropubError {
+                    error: ErrorKind::InvalidRequest,
+                    error_description: "Update cannot modify the post UID".to_owned()
+                });
+            }
+        }
+        if let Some(replace) = &self.replace {
+            if replace.iter().map(|(k, v)| k.as_str()).any(|k| {
+                k.to_lowercase().as_str() == "uid"
+            }) {
+                return Err(MicropubError {
+                    error: ErrorKind::InvalidRequest,
+                    error_description: "Update cannot modify the post UID".to_owned()
+                });
+            }
+        }
+        let iter = match &self.delete {
+            Some(MicropubPropertyDeletion::Properties(keys)) => {
+                Some(Box::new(keys.iter().map(|k| k.as_str())) as Box<dyn Iterator<Item = &str>>)
+            },
+            Some(MicropubPropertyDeletion::Values(map)) => {
+                Some(Box::new(map.iter().map(|(k, _)| k.as_str())) as Box<dyn Iterator<Item = &str>>)
+            },
+            None => None,
+        };
+        if let Some(mut iter) = iter {
+            if iter.any(|k| k.to_lowercase().as_str() == "uid") {
+                return Err(MicropubError {
+                    error: ErrorKind::InvalidRequest,
+                    error_description: "Update cannot modify the post UID".to_owned()
+                });
+            }
+        }
+        Ok(())
+    }
+
     /// Update a specified MF2-JSON document with this update.
     pub fn apply(self, post: &mut serde_json::Value) {
         if let Some(MicropubPropertyDeletion::Properties(ref delete)) = self.delete {
@@ -458,14 +499,17 @@ async fn post_action<D: Storage, A: AuthBackend>(
                 });
             }
 
-            db.update_post(
-                &action.url,
-                action.update.ok_or(MicropubError {
+            let update = if let Some(update) = action.update {
+                update
+            } else {
+                return Err(MicropubError {
                     error: ErrorKind::InvalidRequest,
                     error_description: "Update request is not set.".to_owned(),
-                })?
-            )
-            .await?
+                })
+            };
+
+            update.check_validity()?;
+            db.update_post(&action.url, update).await?;
         }
     }