Fix code quality: trailing whitespace, unused imports, clippy warnings
- Fix trailing whitespace in kex.rs and s3.rs - Add missing KexProposal import in kex_complete.rs - Auto-fix clippy warnings across all crates - All 153 tests pass
This commit is contained in:
@@ -28,15 +28,15 @@ impl UserPermission {
|
||||
admin_access: admin,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn readonly(username: String) -> Self {
|
||||
UserPermission::new(username, true, false, false)
|
||||
}
|
||||
|
||||
|
||||
pub fn full_access(username: String) -> Self {
|
||||
UserPermission::new(username, true, true, false)
|
||||
}
|
||||
|
||||
|
||||
pub fn admin(username: String) -> Self {
|
||||
UserPermission::new(username, true, true, true)
|
||||
}
|
||||
@@ -57,28 +57,32 @@ impl AccessControlList {
|
||||
max_connections: 10,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn add_user(&mut self, permission: UserPermission) {
|
||||
if let Some(existing) = self.users.iter_mut().find(|u| u.username == permission.username) {
|
||||
if let Some(existing) = self
|
||||
.users
|
||||
.iter_mut()
|
||||
.find(|u| u.username == permission.username)
|
||||
{
|
||||
*existing = permission;
|
||||
} else {
|
||||
self.users.push(permission);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn remove_user(&mut self, username: &str) {
|
||||
self.users.retain(|u| u.username != username);
|
||||
}
|
||||
|
||||
|
||||
pub fn get_user(&self, username: &str) -> Option<&UserPermission> {
|
||||
self.users.iter().find(|u| u.username == username)
|
||||
}
|
||||
|
||||
|
||||
pub fn has_access(&self, username: &str, require_write: bool) -> bool {
|
||||
if self.guest_access && !require_write {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
self.get_user(username)
|
||||
.map(|u| {
|
||||
if require_write {
|
||||
@@ -89,4 +93,4 @@ impl AccessControlList {
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use crate::acl::AccessControlList;
|
||||
use anyhow::Result;
|
||||
|
||||
pub struct AuthManager {
|
||||
acl: AccessControlList,
|
||||
@@ -9,26 +9,26 @@ impl AuthManager {
|
||||
pub fn new(acl: AccessControlList) -> Self {
|
||||
AuthManager { acl }
|
||||
}
|
||||
|
||||
|
||||
pub fn authenticate(&self, username: &str, password: Option<&str>) -> Result<bool> {
|
||||
if self.acl.guest_access && password.is_none() {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
|
||||
if password.is_none() {
|
||||
return Err(anyhow::anyhow!("Password required for user {}", username));
|
||||
}
|
||||
|
||||
|
||||
if self.acl.get_user(username).is_none() {
|
||||
return Err(anyhow::anyhow!("User {} not in ACL", username));
|
||||
}
|
||||
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
||||
pub fn check_permission(&self, username: &str, action: &str) -> Result<bool> {
|
||||
let require_write = action == "write" || action == "delete" || action == "create";
|
||||
|
||||
|
||||
if !self.acl.has_access(username, require_write) {
|
||||
return Err(anyhow::anyhow!(
|
||||
"User {} does not have {} permission",
|
||||
@@ -36,15 +36,15 @@ impl AuthManager {
|
||||
action
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
||||
pub fn get_acl(&self) -> &AccessControlList {
|
||||
&self.acl
|
||||
}
|
||||
|
||||
|
||||
pub fn update_acl(&mut self, acl: AccessControlList) {
|
||||
self.acl = acl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl SMBConfig {
|
||||
allow_users: vec!["accusys".to_string()],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn to_smb_conf(&self) -> String {
|
||||
format!(
|
||||
"[{}]\n path = {}\n comment = {}\n read only = {}\n browseable = {}\n valid users = {}\n",
|
||||
@@ -46,4 +46,4 @@ impl SMBConfig {
|
||||
self.allow_users.join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
pub mod config;
|
||||
pub mod manager;
|
||||
pub mod acl;
|
||||
pub mod auth;
|
||||
pub mod config;
|
||||
pub mod manager;
|
||||
pub mod monitor;
|
||||
|
||||
pub use config::SMBConfig;
|
||||
pub use manager::SMBManager;
|
||||
pub use acl::{AccessControlList, UserPermission};
|
||||
pub use auth::AuthManager;
|
||||
pub use monitor::{SMBMonitor, ConnectionStats, AccessLogEntry};
|
||||
pub use config::SMBConfig;
|
||||
pub use manager::SMBManager;
|
||||
pub use monitor::{AccessLogEntry, ConnectionStats, SMBMonitor};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use clap::Parser;
|
||||
use markbase_smb::{SMBConfig, SMBManager, AccessControlList, UserPermission, AuthManager, SMBMonitor};
|
||||
use markbase_smb::{
|
||||
AccessControlList, AuthManager, SMBConfig, SMBManager, SMBMonitor, UserPermission,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "markbase-smb")]
|
||||
@@ -16,34 +18,34 @@ enum Commands {
|
||||
/// Share name
|
||||
#[arg(short, long, default_value = "markbase")]
|
||||
name: String,
|
||||
|
||||
|
||||
/// Path to share
|
||||
#[arg(short, long, default_value = "/Users/accusys/momentry/var/sftpgo/data")]
|
||||
path: String,
|
||||
},
|
||||
|
||||
|
||||
/// Remove SMB share
|
||||
Remove {
|
||||
/// Share name
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
},
|
||||
|
||||
|
||||
/// List existing SMB shares
|
||||
List,
|
||||
|
||||
|
||||
/// Show SMB status
|
||||
Status,
|
||||
|
||||
|
||||
/// Manage user permissions
|
||||
User {
|
||||
#[command(subcommand)]
|
||||
action: UserCommands,
|
||||
},
|
||||
|
||||
|
||||
/// Show monitoring stats
|
||||
Stats,
|
||||
|
||||
|
||||
/// Show access logs
|
||||
Logs {
|
||||
/// Number of log entries to show
|
||||
@@ -58,24 +60,24 @@ enum UserCommands {
|
||||
Add {
|
||||
#[arg(short, long)]
|
||||
username: String,
|
||||
|
||||
|
||||
#[arg(short, long, default_value = "readonly")]
|
||||
permission: String,
|
||||
},
|
||||
|
||||
|
||||
/// Remove user permission
|
||||
Remove {
|
||||
#[arg(short, long)]
|
||||
username: String,
|
||||
},
|
||||
|
||||
|
||||
/// List all user permissions
|
||||
List,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
||||
match cli.command {
|
||||
Commands::Create { name, path } => {
|
||||
let config = SMBConfig::new(name, path);
|
||||
@@ -104,32 +106,33 @@ fn main() -> anyhow::Result<()> {
|
||||
let status = manager.status()?;
|
||||
println!("{}", serde_json::to_string_pretty(&status)?);
|
||||
}
|
||||
Commands::User { action } => {
|
||||
match action {
|
||||
UserCommands::Add { username, permission } => {
|
||||
let acl = AccessControlList::new();
|
||||
let perm = match permission.as_str() {
|
||||
"readonly" => UserPermission::readonly(username),
|
||||
"full" => UserPermission::full_access(username),
|
||||
"admin" => UserPermission::admin(username),
|
||||
_ => UserPermission::readonly(username),
|
||||
};
|
||||
|
||||
println!("User permission configuration:");
|
||||
println!("{}", serde_json::to_string_pretty(&perm)?);
|
||||
println!("\nTo apply, update system SMB configuration with this user.");
|
||||
}
|
||||
UserCommands::Remove { username } => {
|
||||
println!("Removing user '{}' from ACL", username);
|
||||
println!("To apply, update system SMB configuration.");
|
||||
}
|
||||
UserCommands::List => {
|
||||
let acl = AccessControlList::new();
|
||||
println!("Default ACL configuration:");
|
||||
println!("{}", serde_json::to_string_pretty(&acl)?);
|
||||
}
|
||||
Commands::User { action } => match action {
|
||||
UserCommands::Add {
|
||||
username,
|
||||
permission,
|
||||
} => {
|
||||
let acl = AccessControlList::new();
|
||||
let perm = match permission.as_str() {
|
||||
"readonly" => UserPermission::readonly(username),
|
||||
"full" => UserPermission::full_access(username),
|
||||
"admin" => UserPermission::admin(username),
|
||||
_ => UserPermission::readonly(username),
|
||||
};
|
||||
|
||||
println!("User permission configuration:");
|
||||
println!("{}", serde_json::to_string_pretty(&perm)?);
|
||||
println!("\nTo apply, update system SMB configuration with this user.");
|
||||
}
|
||||
}
|
||||
UserCommands::Remove { username } => {
|
||||
println!("Removing user '{}' from ACL", username);
|
||||
println!("To apply, update system SMB configuration.");
|
||||
}
|
||||
UserCommands::List => {
|
||||
let acl = AccessControlList::new();
|
||||
println!("Default ACL configuration:");
|
||||
println!("{}", serde_json::to_string_pretty(&acl)?);
|
||||
}
|
||||
},
|
||||
Commands::Stats => {
|
||||
let monitor = SMBMonitor::new();
|
||||
let stats = monitor.get_stats();
|
||||
@@ -149,6 +152,6 @@ fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,72 +12,68 @@ impl SMBManager {
|
||||
pub fn new(config: SMBConfig) -> Self {
|
||||
SMBManager { config }
|
||||
}
|
||||
|
||||
|
||||
pub fn check_smb_service() -> Result<bool> {
|
||||
let output = Command::new("sharing")
|
||||
.arg("-l")
|
||||
.output()?;
|
||||
|
||||
let output = Command::new("sharing").arg("-l").output()?;
|
||||
|
||||
let status = String::from_utf8_lossy(&output.stdout);
|
||||
Ok(!status.contains("No share point records"))
|
||||
}
|
||||
|
||||
|
||||
pub fn create_share(&self) -> Result<()> {
|
||||
let path = Path::new(&self.config.path);
|
||||
if !path.exists() {
|
||||
return Err(anyhow::anyhow!("Path does not exist: {}", self.config.path));
|
||||
}
|
||||
|
||||
eprintln!("Creating SMB share '{}' for path: {}", self.config.share_name, self.config.path);
|
||||
|
||||
|
||||
eprintln!(
|
||||
"Creating SMB share '{}' for path: {}",
|
||||
self.config.share_name, self.config.path
|
||||
);
|
||||
|
||||
let smb_conf_content = self.config.to_smb_conf();
|
||||
eprintln!("Generated smb.conf section:\n{}", smb_conf_content);
|
||||
|
||||
|
||||
eprintln!("\nTo enable SMB sharing, run:");
|
||||
eprintln!("sudo sharing -a \"{}\" -S \"{}\"", self.config.path, self.config.share_name);
|
||||
|
||||
eprintln!(
|
||||
"sudo sharing -a \"{}\" -S \"{}\"",
|
||||
self.config.path, self.config.share_name
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn remove_share(&self) -> Result<()> {
|
||||
eprintln!("Removing SMB share '{}'...", self.config.share_name);
|
||||
|
||||
|
||||
eprintln!("To remove SMB sharing, run:");
|
||||
eprintln!("sudo sharing -r \"{}\"", self.config.share_name);
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn list_shares() -> Result<Vec<String>> {
|
||||
let output = Command::new("sharing")
|
||||
.arg("-l")
|
||||
.output()?;
|
||||
|
||||
let output = Command::new("sharing").arg("-l").output()?;
|
||||
|
||||
let status = String::from_utf8_lossy(&output.stdout);
|
||||
|
||||
|
||||
if status.contains("No share point records") {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
|
||||
let shares: Vec<String> = status
|
||||
.lines()
|
||||
.filter(|line| line.contains("name:"))
|
||||
.map(|line| {
|
||||
line.split(":")
|
||||
.nth(1)
|
||||
.unwrap_or("")
|
||||
.trim()
|
||||
.to_string()
|
||||
})
|
||||
.map(|line| line.split(":").nth(1).unwrap_or("").trim().to_string())
|
||||
.collect();
|
||||
|
||||
|
||||
Ok(shares)
|
||||
}
|
||||
|
||||
|
||||
pub fn status(&self) -> Result<serde_json::Value> {
|
||||
let service_running = Self::check_smb_service()?;
|
||||
let shares = Self::list_shares()?;
|
||||
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"service_running": service_running,
|
||||
"share_name": self.config.share_name,
|
||||
@@ -86,4 +82,4 @@ impl SMBManager {
|
||||
"config": self.config,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Default)]
|
||||
pub struct ConnectionStats {
|
||||
pub total_connections: u64,
|
||||
pub active_connections: u32,
|
||||
@@ -12,19 +13,6 @@ pub struct ConnectionStats {
|
||||
pub uptime_seconds: u64,
|
||||
}
|
||||
|
||||
impl Default for ConnectionStats {
|
||||
fn default() -> Self {
|
||||
ConnectionStats {
|
||||
total_connections: 0,
|
||||
active_connections: 0,
|
||||
read_operations: 0,
|
||||
write_operations: 0,
|
||||
errors: 0,
|
||||
bytes_transferred: 0,
|
||||
uptime_seconds: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AccessLogEntry {
|
||||
@@ -38,12 +26,19 @@ pub struct AccessLogEntry {
|
||||
}
|
||||
|
||||
impl AccessLogEntry {
|
||||
pub fn new(username: String, action: String, path: String, success: bool, bytes: u64, duration: Duration) -> Self {
|
||||
pub fn new(
|
||||
username: String,
|
||||
action: String,
|
||||
path: String,
|
||||
success: bool,
|
||||
bytes: u64,
|
||||
duration: Duration,
|
||||
) -> Self {
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
|
||||
AccessLogEntry {
|
||||
timestamp: timestamp.to_string(),
|
||||
username,
|
||||
@@ -62,6 +57,12 @@ pub struct SMBMonitor {
|
||||
start_time: SystemTime,
|
||||
}
|
||||
|
||||
impl Default for SMBMonitor {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl SMBMonitor {
|
||||
pub fn new() -> Self {
|
||||
SMBMonitor {
|
||||
@@ -70,10 +71,10 @@ impl SMBMonitor {
|
||||
start_time: SystemTime::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn log_access(&mut self, entry: AccessLogEntry) {
|
||||
self.logs.push(entry.clone());
|
||||
|
||||
|
||||
if entry.success {
|
||||
if entry.action == "read" {
|
||||
self.stats.read_operations += 1;
|
||||
@@ -85,28 +86,28 @@ impl SMBMonitor {
|
||||
self.stats.errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn connection_opened(&mut self) {
|
||||
self.stats.total_connections += 1;
|
||||
self.stats.active_connections += 1;
|
||||
}
|
||||
|
||||
|
||||
pub fn connection_closed(&mut self) {
|
||||
self.stats.active_connections -= 1;
|
||||
}
|
||||
|
||||
|
||||
pub fn get_stats(&self) -> ConnectionStats {
|
||||
let uptime = SystemTime::now()
|
||||
.duration_since(self.start_time)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
|
||||
let mut stats = self.stats.clone();
|
||||
stats.uptime_seconds = uptime;
|
||||
stats
|
||||
}
|
||||
|
||||
|
||||
pub fn get_logs(&self, limit: usize) -> Vec<AccessLogEntry> {
|
||||
self.logs.iter().rev().take(limit).cloned().collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user