web synchronized with the new changes

This commit is contained in:
Priec
2026-08-09 16:30:27 +02:00
parent e66b025188
commit fd551ef7fb
44 changed files with 1215 additions and 88 deletions

106
web/src/authz.rs Normal file
View File

@@ -0,0 +1,106 @@
use crate::auth::{AuthorizationSnapshot, Permission};
pub(crate) const STRUCT_PROFILE: &str = "struct:profile";
pub(crate) const STRUCT_TABLE: &str = "struct:table";
pub(crate) const STRUCT_SCRIPT: &str = "struct:script";
pub(crate) const STRUCT_VALIDATION: &str = "struct:validation";
pub(crate) const STRUCT_ROLE: &str = "struct:role";
pub(crate) const STRUCT_USER: &str = "struct:user";
pub(crate) const MANAGE: &str = "manage";
pub(crate) fn permits(snapshot: &AuthorizationSnapshot, object: &str, action: &str) -> bool {
permissions_permit(&snapshot.permissions, object, action)
}
pub(crate) fn permissions_permit(
permissions: &[Permission],
object: &str,
action: &str,
) -> bool {
permissions
.iter()
.any(|permission| permission.action == action && object_matches(&permission.object, object))
}
pub(crate) fn can_manage(snapshot: &AuthorizationSnapshot, area: &str) -> bool {
permits(snapshot, area, MANAGE)
}
pub(crate) fn can_open_admin(snapshot: &AuthorizationSnapshot) -> bool {
[
STRUCT_PROFILE,
STRUCT_TABLE,
STRUCT_SCRIPT,
STRUCT_VALIDATION,
STRUCT_ROLE,
STRUCT_USER,
]
.into_iter()
.any(|area| can_manage(snapshot, area))
}
pub(crate) fn table_object(profile: &str, table: &str) -> String {
format!("data:{profile}/{table}")
}
pub(crate) fn permits_table(
snapshot: &AuthorizationSnapshot,
profile: &str,
table: &str,
action: &str,
) -> bool {
permits(snapshot, &table_object(profile, table), action)
}
pub(crate) fn is_direct_permission(permissions: &[Permission], object: &str, action: &str) -> bool {
permissions
.iter()
.any(|permission| permission.object == object && permission.action == action)
}
fn object_matches(pattern: &str, object: &str) -> bool {
match pattern.strip_suffix('*') {
Some(prefix) => object.starts_with(prefix),
None => pattern == object,
}
}
#[cfg(test)]
mod tests {
use super::*;
fn snapshot(permissions: &[(&str, &str)]) -> AuthorizationSnapshot {
AuthorizationSnapshot {
role: "bookkeeper".to_string(),
permissions: permissions
.iter()
.map(|(object, action)| Permission {
object: (*object).to_string(),
action: (*action).to_string(),
})
.collect(),
}
}
#[test]
fn structural_access_comes_from_permissions_not_role_names() {
let authorization = snapshot(&[(STRUCT_TABLE, MANAGE)]);
assert!(can_manage(&authorization, STRUCT_TABLE));
assert!(can_open_admin(&authorization));
assert!(!can_manage(&authorization, STRUCT_ROLE));
}
#[test]
fn data_wildcards_match_the_server_object_shapes() {
let global = snapshot(&[("data:*", "read")]);
assert!(permits_table(&global, "acme", "invoice", "read"));
let profile = snapshot(&[("data:acme/*", "insert")]);
assert!(permits_table(&profile, "acme", "invoice", "insert"));
assert!(!permits_table(&profile, "other", "invoice", "insert"));
let table = snapshot(&[("data:acme/invoice", "delete")]);
assert!(permits_table(&table, "acme", "invoice", "delete"));
assert!(!permits_table(&table, "acme", "customer", "delete"));
}
}