feat: add UserRole RBAC framework for multi-user support
- UserRole enum: Admin (full), Viewer (read-only), AppUser (minimal) - can_access() method checks RPC method against role permissions - Role field on User struct with serde default (backward-compatible) - Viewer: read system/federation/DWN/identity/backup/container status - AppUser: system.stats, node.did, container list, password change Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,60 @@ use tokio::fs;
|
||||
|
||||
use crate::totp::TotpData;
|
||||
|
||||
/// User role for multi-user RBAC (Year 3 feature).
|
||||
/// - Admin: full access to all operations
|
||||
/// - Viewer: read-only dashboard, container status, monitoring
|
||||
/// - AppUser: access specific apps, no system configuration
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum UserRole {
|
||||
Admin,
|
||||
Viewer,
|
||||
AppUser,
|
||||
}
|
||||
|
||||
impl Default for UserRole {
|
||||
fn default() -> Self {
|
||||
UserRole::Admin
|
||||
}
|
||||
}
|
||||
|
||||
impl UserRole {
|
||||
/// Check if this role allows a given RPC method.
|
||||
pub fn can_access(&self, method: &str) -> bool {
|
||||
match self {
|
||||
UserRole::Admin => true,
|
||||
UserRole::Viewer => {
|
||||
// Read-only methods
|
||||
method.starts_with("system.")
|
||||
|| method.starts_with("node.")
|
||||
|| method.starts_with("federation.list")
|
||||
|| method.starts_with("dwn.status")
|
||||
|| method.starts_with("dwn.list")
|
||||
|| method.starts_with("dwn.query")
|
||||
|| method.starts_with("identity.list")
|
||||
|| method.starts_with("identity.get")
|
||||
|| method.starts_with("backup.list")
|
||||
|| method == "container-list"
|
||||
|| method == "container-status"
|
||||
|| method == "container-health"
|
||||
|| method == "health"
|
||||
|| method == "auth.logout"
|
||||
}
|
||||
UserRole::AppUser => {
|
||||
// App access + basic read
|
||||
method.starts_with("system.stats")
|
||||
|| method == "node.did"
|
||||
|| method == "container-list"
|
||||
|| method == "container-status"
|
||||
|| method == "health"
|
||||
|| method == "auth.logout"
|
||||
|| method == "auth.changePassword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct OnboardingState {
|
||||
complete: bool,
|
||||
@@ -21,6 +75,9 @@ pub struct User {
|
||||
pub onboarding_complete: bool,
|
||||
#[serde(default)]
|
||||
pub totp: Option<TotpData>,
|
||||
/// User role for RBAC (defaults to Admin for backward compatibility)
|
||||
#[serde(default)]
|
||||
pub role: UserRole,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
Reference in New Issue
Block a user