Selaa lähdekoodia

Wrote a method for testing path containment.

Matthew Carr 2 vuotta sitten
vanhempi
commit
97688c8252

+ 1 - 0
crates/node/.vscode/settings.json

@@ -9,6 +9,7 @@
         "encrypter",
         "Hashable",
         "newtype",
+        "writecap",
         "Xsalsa"
     ]
 }

+ 9 - 8
crates/node/src/crypto.rs

@@ -571,11 +571,13 @@ impl<'a> From<&'a WriteCap> for WriteCapSig<'a> {
 }
 
 /// Verifies that the given `WriteCap` actually grants permission to write to the given `Path`.
-fn verify_write_cap(mut write_cap: &WriteCap, _path: &Path) -> Result<bool> {
+fn verify_write_cap(mut write_cap: &WriteCap, path: &Path) -> Result<bool> {
     let mut prev: Option<&WriteCap> = None;
     let mut sig_input = Vec::new();
     loop {
-        // TODO: Verify that `write_cap.path` contains `path`.
+        if !write_cap.path.contains(path) {
+            return Ok(false);
+        }
         // TODO: Verify that `write_cap.expires` is not in the past.
         if let Some(prev) = &prev {
             if prev.signing_key.to_principal() != write_cap.issued_to {
@@ -597,10 +599,9 @@ fn verify_write_cap(mut write_cap: &WriteCap, _path: &Path) -> Result<bool> {
                 write_cap = next;
             },
             None => {
-                // We're at the root key.
-                // TODO: Verify that the fingerprint of `write_cap.signing_key` matches to first
-                // component of `path`.
-                return Ok(true);
+                // We're at the root key. As long as the signer of this writecap is the owner of
+                // the path, then the writecap is valid.
+                return Ok(write_cap.signing_key.to_principal() == path.owner);
             }
         }
     }
@@ -722,14 +723,14 @@ mod tests {
 
     #[test]
     fn hash_to_string() {
-        let hash = test_helpers::make_principal().0;
+        let hash = make_principal().0;
         let string = hash.to_string();
         assert_eq!("Sha2_256:dSip4J0kurN5VhVo_aTipM-ywOOWrqJuRRVQ7aa-bew", string)
     }
 
     #[test]
     fn hash_to_string_round_trip() -> Result<()> {
-        let expected = test_helpers::make_principal().0;
+        let expected = make_principal().0;
         let string = expected.to_string();
         let actual = Hash::try_from(string.as_str())?;
         assert_eq!(expected, actual);

+ 56 - 0
crates/node/src/main.rs

@@ -187,6 +187,26 @@ impl Path {
         }
         Ok(())
     }
+
+    /// Returns true if `other` is a subpath of this `Path`.
+    fn contains(&self, other: &Path) -> bool {
+        if self.owner != other.owner {
+            return false;
+        };
+        // This path must be no longer than the other path.
+        if self.components.len() > other.components.len() {
+            return false;
+        }
+        // Skip the component containing the owner.
+        let self_iter = self.components.iter().skip(1);
+        let other_iter = other.components.iter().skip(1);
+        for pair in self_iter.zip(other_iter) {
+            if pair.0 != pair.1 {
+                return false;
+            }
+        }
+        true
+    }
 }
 
 impl<'s> TryFrom<&'s str> for Path {
@@ -343,4 +363,40 @@ mod tests {
         assert_eq!(expected, actual);
         Ok(())
     }
+
+    #[test]
+    fn path_contains_true() {
+        let larger = make_path(vec!["apps"]);
+        let smaller = make_path(vec!["apps", "bohdi"]);
+        assert!(larger.contains(&smaller));
+    }
+
+    #[test]
+    fn path_contains_true_only_owner() {
+        let larger = make_path(vec![]);
+        let smaller = make_path(vec![]);
+        assert!(larger.contains(&smaller));
+    }
+
+    #[test]
+    fn path_contains_false_self_is_longer() {
+        let first = make_path(vec!["apps", "bohdi"]);
+        let second = make_path(vec!["apps"]);
+        assert!(!first.contains(&second));
+    }
+
+    #[test]
+    fn path_contains_false_same_owners() {
+        let first = make_path(vec!["apps"]);
+        let second = make_path(vec!["nodes"]);
+        assert!(!first.contains(&second));
+    }
+
+    #[test]
+    fn path_contains_false_different_owners() {
+        let first = make_path(vec!["apps"]);
+        let mut second = make_path(vec!["apps"]);
+        second.owner = Principal(Hash::Sha2_256(PRINCIPAL2));
+        assert!(!first.contains(&second));
+    }
 }

+ 5 - 0
crates/node/src/test_helpers.rs

@@ -9,6 +9,11 @@ pub const PRINCIPAL: [u8; 32] = [
     0xCF, 0xB2, 0xC0, 0xE3, 0x96, 0xAE, 0xA2, 0x6E, 0x45, 0x15, 0x50, 0xED, 0xA6, 0xBE, 0x6D, 0xEC,
 ];
 
+pub const PRINCIPAL2: [u8; 32] = [
+    0x6E, 0x8A, 0x76, 0x1D, 0xC7, 0x3B, 0x50, 0x90, 0x51, 0x9E, 0x73, 0x9B, 0xEE, 0x7B, 0x02, 0xF9,
+    0xB9, 0x17, 0x7C, 0xF6, 0xBB, 0xC8, 0xD5, 0x30, 0xBF, 0x2A, 0xB4, 0xDE, 0x1B, 0x38, 0xCC, 0xF6,
+];
+
 pub const PAYLOAD: [u8; 128] = [
     0x39, 0x79, 0x1A, 0x0D, 0x8E, 0x6C, 0xF5, 0x4B, 0xF3, 0xA4, 0x75, 0xC4, 0x44, 0x73, 0x58, 0x58,
     0x97, 0x14, 0x64, 0xE0, 0xC6, 0xFE, 0xCB, 0xCF, 0xBE, 0x67, 0x49, 0x49, 0x40, 0xAE, 0x71, 0x5A,