aboutsummaryrefslogtreecommitdiffstats
path: root/src/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/access')
-rw-r--r--src/access/envelope.rs45
-rw-r--r--src/access/mod.rs5
-rw-r--r--src/access/policy.rs1
3 files changed, 39 insertions, 12 deletions
diff --git a/src/access/envelope.rs b/src/access/envelope.rs
index 7244a3b..1804b98 100644
--- a/src/access/envelope.rs
+++ b/src/access/envelope.rs
@@ -72,15 +72,39 @@ pub(crate) fn signed_paths(doc: &impl ReadDoc) -> Vec<Vec<String>> {
/// its `*` segments as `path` has them.
pub(crate) fn signed_path(signed: &[Vec<String>], path: &[String]) -> Option<Vec<String>> {
signed.iter().find_map(|pattern| {
- (path.len() >= pattern.len()
- && pattern
- .iter()
- .zip(path)
- .all(|(segment, key)| segment == "*" || segment == key))
- .then(|| path[..pattern.len()].to_vec())
+ (path.len() >= pattern.len() && agree(pattern, path))
+ .then(|| path[..pattern.len()].to_vec())
})
}
+/// Whether `path` is where a user-signed value goes, of `signed` (`signed_paths`).
+pub(crate) fn is_signed(signed: &[Vec<String>], path: &[String]) -> bool {
+ signed
+ .iter()
+ .any(|pattern| pattern.len() == path.len() && agree(pattern, path))
+}
+
+/// Whether a user-signed value of `signed` may be below `path` (`signed_paths`).
+pub(crate) fn above_signed(signed: &[Vec<String>], path: &[String]) -> bool {
+ signed
+ .iter()
+ .any(|pattern| pattern.len() > path.len() && agree(pattern, path))
+}
+
+/// Whether a write at `path` reaches a user-signed value of `signed` (`signed_paths`):
+/// at one, within one, or above one.
+pub(crate) fn reaches_signed(signed: &[Vec<String>], path: &[String]) -> bool {
+ signed.iter().any(|pattern| agree(pattern, path))
+}
+
+/// Whether `pattern` and `path` agree as far as both go (`*`: any key).
+fn agree(pattern: &[String], path: &[String]) -> bool {
+ pattern
+ .iter()
+ .zip(path)
+ .all(|(segment, key)| segment == "*" || segment == key)
+}
+
/// A signed value's payload.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Payload {
@@ -280,5 +304,14 @@ mod tests {
signed_path(&signed, &path("_continuum/access/policy")),
Some(path("_continuum/access/policy"))
);
+ assert!(is_signed(&signed, &path("_continuum/users/alice")));
+ assert!(!is_signed(&signed, &path("_continuum/users/alice/caps")));
+ assert!(above_signed(&signed, &path("_continuum/users")));
+ assert!(above_signed(&signed, &path("a")));
+ assert!(!above_signed(&signed, &path("a/b")));
+ assert!(reaches_signed(&signed, &path("a")));
+ assert!(reaches_signed(&signed, &path("a/b/c")));
+ assert!(!reaches_signed(&signed, &path("a/c")));
+ assert!(!reaches_signed(&signed, &path("_continuum/members/x")));
}
}
diff --git a/src/access/mod.rs b/src/access/mod.rs
index b58355e..bdb5124 100644
--- a/src/access/mod.rs
+++ b/src/access/mod.rs
@@ -14,16 +14,11 @@ use serde::{Deserialize, Serialize};
use crate::document::meta;
pub(crate) mod bans;
-// Values signed by their users: what the store and the rules use; until then, the tests.
-#[cfg_attr(not(test), allow(dead_code))]
pub(crate) mod envelope;
pub(crate) mod policy;
pub(crate) mod registry;
pub(crate) mod rules;
pub(crate) mod screen;
-// Users' keys and signatures: what signed values and logins by key use; until then,
-// the tests.
-#[cfg_attr(not(test), allow(dead_code))]
pub(crate) mod sshsig;
pub(crate) mod token;
diff --git a/src/access/policy.rs b/src/access/policy.rs
index 8efedff..85b562a 100644
--- a/src/access/policy.rs
+++ b/src/access/policy.rs
@@ -51,7 +51,6 @@ impl Policy {
/// Whether values at the user-signed paths need their users' signatures
/// (`values: "signed"`, `access::envelope::signed_paths`).
- #[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn strict(&self) -> bool {
matches!(self, Policy::Enforced { strict: true, .. })
}