...
This commit is contained in:
parent
c956db8adf
commit
59c9b445bb
@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(_) => {
|
||||
|
@ -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())
|
||||
|
@ -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(¶ms.circle_id).await {
|
||||
Ok(db) => {
|
||||
let mut db = db.write().await;
|
||||
match db.acl_update(¶ms.caller_pubkey, ¶ms.name, ¶ms.pubkeys, right) {
|
||||
match db.acl_update(¶ms.caller_pubkey, ¶ms.name, ¶ms.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(¶ms.circle_id).await {
|
||||
Ok(db) => {
|
||||
let mut db = db.write().await;
|
||||
match db.acl_remove(¶ms.caller_pubkey, ¶ms.name, ¶ms.pubkeys) {
|
||||
match db.acl_remove(¶ms.caller_pubkey, ¶ms.name, ¶ms.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(¶ms.circle_id).await {
|
||||
Ok(db) => {
|
||||
let mut db = db.write().await;
|
||||
match db.acl_del(¶ms.caller_pubkey, ¶ms.name) {
|
||||
match db.acl_del(¶ms.caller_pubkey, ¶ms.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 {
|
||||
|
@ -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)?
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user