From d1467f03bd827b012d1e0bd34e447922424d6951 Mon Sep 17 00:00:00 2001 From: Warren Date: Sat, 20 Jun 2026 20:44:23 +0800 Subject: [PATCH] SMB CLI: Add multi-user support (--user name:password) - Add --user CLI argument (repeatable) format: name:password - Default user 'demo:demo123' if no users specified - All users get ReadWrite access to the share - Note: SMB3 encryption not available (smb-server v1 out of scope) Example: smb-start --user alice:pass1 --user bob:pass2 --share-name myshare All 229 tests pass. --- markbase-core/src/cli/tools/smb_server.rs | 49 ++++++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/markbase-core/src/cli/tools/smb_server.rs b/markbase-core/src/cli/tools/smb_server.rs index ce0cd6e..c8bdfa6 100644 --- a/markbase-core/src/cli/tools/smb_server.rs +++ b/markbase-core/src/cli/tools/smb_server.rs @@ -15,14 +15,31 @@ pub enum SmbServerCommand { #[arg(long)] read_only: bool, + + #[arg(short, long, value_parser = parse_user)] + user: Vec<(String, String)>, }, } +fn parse_user(s: &str) -> Result<(String, String), String> { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 2 { + return Err(format!("Invalid user format '{}'. Expected 'name:password'", s)); + } + Ok((parts[0].to_string(), parts[1].to_string())) +} + pub async fn handle_smb_server_command(cmd: SmbServerCommand) -> anyhow::Result<()> { #[cfg(feature = "smb-server")] { match cmd { - SmbServerCommand::Start { port, root, share_name, read_only } => { + SmbServerCommand::Start { + port, + root, + share_name, + read_only, + user, + } => { use std::path::PathBuf; use smb_server::{Access, Share, SmbServer}; @@ -35,26 +52,36 @@ pub async fn handle_smb_server_command(cmd: SmbServerCommand) -> anyhow::Result< ) .try_init(); - let addr: std::net::SocketAddr = - format!("0.0.0.0:{}", port).parse()?; + let addr: std::net::SocketAddr = format!("0.0.0.0:{}", port).parse()?; let root_path = PathBuf::from(&root); let vfs = Box::new(crate::vfs::local_fs::LocalFs::new()); let backend = crate::vfs::smb_server_backend::VfsShareBackend::new(vfs, root_path) .read_only(read_only); - let share = Share::new(&share_name, backend) - .user("demo", Access::ReadWrite); + let users: Vec<(String, String)> = if user.is_empty() { + vec![("demo".to_string(), "demo123".to_string())] + } else { + user + }; - let server = SmbServer::builder() - .listen(addr) - .user("demo", "demo123") - .share(share) - .build()?; + let mut builder = SmbServer::builder().listen(addr); + for (name, password) in &users { + builder = builder.user(name, password); + } + + let mut share = Share::new(&share_name, backend); + for (name, _) in &users { + share = share.user(name, Access::ReadWrite); + } + + let server = builder.share(share).build()?; + + let user_list: Vec<&str> = users.iter().map(|(n, _)| n.as_str()).collect(); log::info!("SMB server listening on {}", addr); log::info!("Share '{}' at root: {}", share_name, root); - log::info!("User: demo / demo123"); + log::info!("Users: {}", user_list.join(", ")); server.serve().await?; }