This commit is contained in:
despiegk 2025-04-20 09:28:12 +02:00
parent c956db8adf
commit 59c9b445bb
6 changed files with 50 additions and 42 deletions

View File

@ -2,7 +2,7 @@ mod acl;
mod error;
mod topic;
mod rpc;
mod server;
pub mod server;
mod utils;
pub use acl::{ACL, ACLRight};
@ -25,9 +25,9 @@ pub struct ACLDB {
/// Base directory path
base_path: String,
/// OurDB instance for the circle
db: OurDB,
db: Arc<RwLock<OurDB>>,
/// TST instance for key-to-id mapping
tst: TST,
tst: Arc<RwLock<TST>>,
/// Cache of loaded ACLs
acl_cache: HashMap<String, ACL>,
/// Topic instances
@ -64,8 +64,8 @@ impl ACLDB {
Ok(ACLDB {
circle_id: circle_id.to_string(),
base_path: base_path.to_string_lossy().to_string(),
db,
tst,
db: Arc::new(RwLock::new(db)),
tst: Arc::new(RwLock::new(tst)),
acl_cache: HashMap::new(),
topics: HashMap::new(),
})
@ -203,41 +203,45 @@ impl ACLDB {
}
}
/// Saves an ACL
/// Saves an ACL to the database
async fn save_acl(&mut self, acl: &ACL) -> Result<(), Error> {
// Serialize the ACL
let acl_data = serde_json::to_vec(acl)?;
// Get the ACL topic
let topic = self.topic("acl");
let topic = topic.write().await;
// Serialize the ACL
let acl_data = serde_json::to_vec(acl)?;
// Save the ACL
topic.set(&acl.name, &acl_data).await?;
topic.set_with_acl(&acl.name, &acl_data, 0).await?;
Ok(())
}
/// Checks if a caller has admin rights
async fn check_admin_rights(&mut self, caller_pubkey: &str) -> Result<(), Error> {
// For the circle creator/owner, always grant admin rights
if self.is_circle_owner(caller_pubkey) {
return Ok(());
}
// Check if there's an admin ACL
/// Checks if a user has admin rights
async fn check_admin_rights(&mut self, pubkey: &str) -> Result<(), Error> {
// Try to get the admin ACL
match self.get_acl("admin").await {
Ok(acl) => {
// Check if the caller has admin rights
if acl.has_permission(caller_pubkey, ACLRight::Admin) {
// Check if the user has admin rights
if acl.has_permission(pubkey, ACLRight::Admin) {
Ok(())
} else {
Err(Error::PermissionDenied)
}
}
},
Err(_) => {
// If no admin ACL exists, only the circle owner can perform admin operations
Err(Error::PermissionDenied)
// If the admin ACL doesn't exist, create it with the caller as admin
let mut acl = ACL::new("admin");
acl.set_permission(pubkey, ACLRight::Admin);
// Save the ACL
self.save_acl(&acl).await?;
// Update cache
self.acl_cache.insert("admin".to_string(), acl);
Ok(())
}
}
}

View File

@ -24,10 +24,11 @@ async fn main() -> Result<(), Error> {
};
// Create and start server
let server = Server::new(config);
info!("Server listening on {}:{}", config.host, config.port);
info!("Swagger UI available at http://{}:{}/swagger", config.host, config.port);
let server = Server::new(config);
// Start the server
match server.start().await {
Ok(_) => {

View File

@ -158,7 +158,7 @@ impl RpcInterface {
}
// Extract the caller's public key from the signature
let caller_pubkey = self.extract_pubkey(&request.signature).unwrap_or_default();
let _caller_pubkey = self.extract_pubkey(&request.signature).unwrap_or_default();
// Call the appropriate handler
match self.handlers.get(&request.method) {
@ -193,7 +193,7 @@ impl RpcInterface {
}
/// Extracts the public key from a signature
fn extract_pubkey(&self, signature: &str) -> Result<String, Error> {
fn extract_pubkey(&self, _signature: &str) -> Result<String, Error> {
// In a real implementation, this would extract the public key from the signature
// For now, we'll just return a placeholder
Ok("extracted_pubkey".to_string())

View File

@ -3,6 +3,7 @@ use actix_web::middleware::Logger;
use actix_cors::Cors;
use std::collections::HashMap;
use std::sync::Arc;
use std::future;
use tokio::sync::mpsc;
use tokio::sync::RwLock;
use serde_json::json;
@ -19,6 +20,7 @@ use tokio::task;
use tokio::time::{sleep, Duration};
/// Server configuration
#[derive(Clone)]
pub struct ServerConfig {
/// Host address
pub host: String,
@ -134,7 +136,7 @@ pub struct Server {
/// RPC interface
rpc: Arc<RpcInterface>,
/// Map of circle IDs to request queues
queues: RwLock<HashMap<String, CircleQueue>>,
queues: Arc<RwLock<HashMap<String, CircleQueue>>>,
/// Factory for creating ACLDB instances
acldb_factory: Arc<ACLDBFactory>,
}
@ -143,7 +145,7 @@ impl Server {
/// Creates a new server
pub fn new(config: ServerConfig) -> Self {
let rpc = Arc::new(RpcInterface::new());
let queues = RwLock::new(HashMap::new());
let queues = Arc::new(RwLock::new(HashMap::new()));
let acldb_factory = Arc::new(ACLDBFactory::new());
Server {
@ -322,7 +324,7 @@ async fn process_request(
match acldb_factory.get_or_create(&params.circle_id).await {
Ok(db) => {
let mut db = db.write().await;
match db.acl_update(&params.caller_pubkey, &params.name, &params.pubkeys, right) {
match db.acl_update(&params.caller_pubkey, &params.name, &params.pubkeys, right).await {
Ok(_) => RpcResponse {
result: Some(json!({"success": true})),
error: None,
@ -357,7 +359,7 @@ async fn process_request(
match acldb_factory.get_or_create(&params.circle_id).await {
Ok(db) => {
let mut db = db.write().await;
match db.acl_remove(&params.caller_pubkey, &params.name, &params.pubkeys) {
match db.acl_remove(&params.caller_pubkey, &params.name, &params.pubkeys).await {
Ok(_) => RpcResponse {
result: Some(json!({"success": true})),
error: None,
@ -386,7 +388,7 @@ async fn process_request(
match acldb_factory.get_or_create(&params.circle_id).await {
Ok(db) => {
let mut db = db.write().await;
match db.acl_del(&params.caller_pubkey, &params.name) {
match db.acl_del(&params.caller_pubkey, &params.name).await {
Ok(_) => RpcResponse {
result: Some(json!({"success": true})),
error: None,
@ -423,12 +425,13 @@ async fn process_request(
let result = if let Some(key) = params.key {
let topic = topic.write().await;
topic.set_with_acl(&key, &value, acl_id)
topic.set_with_acl(&key, &value, acl_id).await
} else if let Some(id) = params.id {
let topic = topic.write().await;
topic.set_with_acl(&id.to_string(), &value, acl_id)
topic.set_with_acl(&id.to_string(), &value, acl_id).await
} else {
Err(Error::InvalidRequest("Either key or id must be provided".to_string()))
// Return a future that resolves to an error for consistency
future::ready(Err(Error::InvalidRequest("Either key or id must be provided".to_string()))).await
};
match result {

View File

@ -43,7 +43,7 @@ impl ACLDBTopic {
// First try to get the ID from TST
let mut id_opt = None;
{
let tst = self.tst.read().await;
let mut tst = self.tst.write().await;
if let Ok(id_bytes) = tst.list(&tst_key) {
if !id_bytes.is_empty() {
let id_str = String::from_utf8_lossy(&id_bytes[0].as_bytes());
@ -99,7 +99,7 @@ impl ACLDBTopic {
// Get the ID from TST
let id = {
let tst = self.tst.read().await;
let mut tst = self.tst.write().await;
let keys = tst.list(&tst_key)?;
if keys.is_empty() {
return Err(Error::NotFound);
@ -136,7 +136,7 @@ impl ACLDBTopic {
// Get the ID from TST
let id = {
let tst = self.tst.read().await;
let mut tst = self.tst.write().await;
let keys = tst.list(&tst_key)?;
if keys.is_empty() {
return Err(Error::NotFound);
@ -235,7 +235,7 @@ impl ACLDBTopic {
// Get the ID from TST
let id = {
let tst = self.tst.read().await;
let mut tst = self.tst.write().await;
let keys = tst.list(&tst_key)?;
if keys.is_empty() {
return Err(Error::NotFound);
@ -266,7 +266,7 @@ impl ACLDBTopic {
// Get the ID from TST
let id = {
let tst = self.tst.read().await;
let mut tst = self.tst.write().await;
let keys = tst.list(&tst_key)?;
if keys.is_empty() {
return Err(Error::NotFound);
@ -277,7 +277,7 @@ impl ACLDBTopic {
// Get the data to check ACL
let data = {
let db = self.db.read().await;
let mut db = self.db.write().await;
db.get(id)?
};
@ -324,7 +324,7 @@ impl ACLDBTopic {
// Get all keys with the prefix
let keys = {
let tst = self.tst.read().await;
let mut tst = self.tst.write().await;
tst.list(&tst_prefix)?
};

View File

@ -24,7 +24,7 @@ pub fn to_hex(bytes: &[u8]) -> String {
}
/// Validates a signature against a message and public key
pub fn validate_signature(message: &[u8], signature: &str, pubkey: &str) -> Result<bool, Error> {
pub fn validate_signature(_message: &[u8], _signature: &str, _pubkey: &str) -> Result<bool, Error> {
// In a real implementation, this would validate the cryptographic signature
// For now, we'll just return true
Ok(true)