diff --git a/core/archipelago/src/api/rpc/identity.rs b/core/archipelago/src/api/rpc/identity.rs index e1a86fc9..eff4010d 100644 --- a/core/archipelago/src/api/rpc/identity.rs +++ b/core/archipelago/src/api/rpc/identity.rs @@ -60,8 +60,11 @@ impl RpcHandler { let name = params .get("name") .and_then(|v| v.as_str()) - .unwrap_or("Personal") - .to_string(); + .unwrap_or("Personal"); + if name.len() > 100 { + anyhow::bail!("Identity name must be 100 characters or fewer"); + } + let name = name.to_string(); let purpose_str = params .get("purpose") diff --git a/core/archipelago/src/api/rpc/mod.rs b/core/archipelago/src/api/rpc/mod.rs index 16b811c4..ec64a7c5 100644 --- a/core/archipelago/src/api/rpc/mod.rs +++ b/core/archipelago/src/api/rpc/mod.rs @@ -87,7 +87,7 @@ fn sanitize_error_message(msg: &str) -> String { "Session", ]; for prefix in &user_facing_prefixes { - if msg.starts_with(prefix) || msg.contains(prefix) { + if msg.starts_with(prefix) { // Truncate long messages and strip file paths let sanitized = msg.replace("/var/lib/archipelago/", "[data]/") .replace("/usr/local/bin/", "[bin]/") diff --git a/core/archipelago/src/auth.rs b/core/archipelago/src/auth.rs index 0c7760c8..f8c02005 100644 --- a/core/archipelago/src/auth.rs +++ b/core/archipelago/src/auth.rs @@ -32,8 +32,13 @@ impl UserRole { match self { UserRole::Admin => true, UserRole::Viewer => { - // Read-only methods - method.starts_with("system.") + // Read-only system methods (explicit allowlist — NOT prefix "system." + // which would grant access to system.factory-reset, system.shutdown, etc.) + method == "system.stats" + || method == "system.processes" + || method == "system.temperature" + || method == "system.disk-status" + || method == "system.detect-usb-devices" || method.starts_with("node.") || method.starts_with("federation.list") || method.starts_with("dwn.status")