//! SMB Server Configuration Templates //! Provides preset configurations for common deployment scenarios use std::path::PathBuf; /// SMB Server Configuration #[derive(Clone, Debug)] pub struct SmbConfig { pub port: u16, pub root: PathBuf, pub share_name: String, pub read_only: bool, pub users: Vec<(String, String)>, pub backend: SmbBackend, pub ldap: Option, pub cache: CacheConfig, pub encryption: EncryptionConfig, } #[derive(Clone, Debug)] pub enum SmbBackend { LocalFs, S3 { endpoint: String, bucket: String, access_key: String, secret_key: String, region: String, }, } #[derive(Clone, Debug)] pub struct LdapConfig { pub url: String, pub base_dn: String, pub bind_dn: String, pub bind_password: String, pub user_search_base: String, pub group_search_base: String, pub user_id_attr: String, pub user_filter: String, pub group_filter: String, pub home_dir_attr: String, pub home_dir_prefix: String, pub user_groups_attr: String, } #[derive(Clone, Debug)] pub struct CacheConfig { pub read_cache_size_mb: usize, pub write_cache_size_mb: usize, pub cache_ttl_secs: u64, } #[derive(Clone, Debug)] pub enum EncryptionConfig { Disabled, Aes128Ctr, Aes256Gcm, } impl Default for SmbConfig { fn default() -> Self { Self { port: 4445, root: PathBuf::from("/data/smb"), share_name: "share".to_string(), read_only: false, users: vec![("demo".to_string(), "demo123".to_string())], backend: SmbBackend::LocalFs, ldap: None, cache: CacheConfig::default(), encryption: EncryptionConfig::Aes128Ctr, } } } impl Default for LdapConfig { fn default() -> Self { Self { url: "ldap://localhost:389".to_string(), base_dn: "dc=example,dc=com".to_string(), bind_dn: "cn=admin,dc=example,dc=com".to_string(), bind_password: "".to_string(), user_search_base: "ou=users,dc=example,dc=com".to_string(), group_search_base: "ou=groups,dc=example,dc=com".to_string(), user_id_attr: "uid".to_string(), user_filter: "(objectClass=person)".to_string(), group_filter: "(objectClass=group)".to_string(), home_dir_attr: "homeDirectory".to_string(), home_dir_prefix: "/home".to_string(), user_groups_attr: "memberOf".to_string(), } } } impl Default for CacheConfig { fn default() -> Self { Self { read_cache_size_mb: 64, write_cache_size_mb: 32, cache_ttl_secs: 300, } } } impl SmbConfig { /// Generate TOML configuration template pub fn generate_template() -> String { let config = Self::default(); format!( "# === SMB Server Configuration === # MarkBase SMB2/3 File Server [smb] # === Network Settings === port = {} # SMB server port (default: 4445) share_name = \"{}\" # Share name visible to clients read_only = {} # Read-only mode (default: false) # === Storage Backend === # Options: localfs, s3 backend = \"localfs\" # Default: local filesystem root = \"{}\" # Local filesystem root path # === User Authentication === # Format: [[smb.users]] # name = \"username\" # password = \"password\" (bcrypt hashed in production) [[smb.users]] name = \"{}\" password = \"{}\" # ⚠️ Use bcrypt hash in production # === LDAP Integration (Optional) === # Uncomment to enable LDAP authentication # [smb.ldap] # url = \"ldap://localhost:389\" # LDAP server URL # base_dn = \"dc=example,dc=com\" # Base DN # bind_dn = \"cn=admin,dc=example,dc=com\" # Bind DN for search # bind_password = \"admin_password\" # Bind password # user_search_base = \"ou=users,dc=example,dc=com\" # group_search_base = \"ou=groups,dc=example,dc=com\" # user_id_attr = \"uid\" # User ID attribute # user_filter = \"(objectClass=person)\" # User object filter # group_filter = \"(objectClass=group)\" # Group object filter # home_dir_attr = \"homeDirectory\" # Home directory attribute # home_dir_prefix = \"/home\" # Home directory prefix # user_groups_attr = \"memberOf\" # Group membership attribute # === Performance Settings === [smb.cache] read_cache_size_mb = {} # Read cache size (default: 64MB) write_cache_size_mb = {} # Write cache size (default: 32MB) cache_ttl_secs = {} # Cache TTL (default: 300s) # === Security Settings === [smb.encryption] # Options: disabled, aes128-ctr, aes256-gcm mode = \"aes128-ctr\" # SMB3 encryption mode (default: AES-128-CTR) # === S3 Backend (Optional) === # Uncomment to use S3 backend instead of local filesystem # [smb.s3] # endpoint = \"https://s3.amazonaws.com\" # bucket = \"my-bucket\" # access_key = \"AKIAIOSFODNN7EXAMPLE\" # secret_key = \"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\" # region = \"us-east-1\" ", config.port, config.share_name, config.read_only, config.root.display(), config.users[0].0, config.users[0].1, config.cache.read_cache_size_mb, config.cache.write_cache_size_mb, config.cache.cache_ttl_secs, ) } /// Preset: Local File Server (simple deployment) pub fn preset_local_file_server() -> Self { Self { port: 4445, root: PathBuf::from("/data/smb"), share_name: "files".to_string(), read_only: false, users: vec![ ("alice".to_string(), "alice123".to_string()), ("bob".to_string(), "bob123".to_string()), ], backend: SmbBackend::LocalFs, ldap: None, cache: CacheConfig { read_cache_size_mb: 64, write_cache_size_mb: 32, cache_ttl_secs: 300, }, encryption: EncryptionConfig::Aes128Ctr, } } /// Preset: S3 Backend (cloud storage) pub fn preset_s3_backend() -> Self { Self { port: 4445, root: PathBuf::from("demo/"), share_name: "s3share".to_string(), read_only: false, users: vec![("demo".to_string(), "demo123".to_string())], backend: SmbBackend::S3 { endpoint: "https://s3.amazonaws.com".to_string(), bucket: "my-bucket".to_string(), access_key: "AKIAIOSFODNN7EXAMPLE".to_string(), secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY".to_string(), region: "us-east-1".to_string(), }, ldap: None, cache: CacheConfig { read_cache_size_mb: 128, write_cache_size_mb: 64, cache_ttl_secs: 600, }, encryption: EncryptionConfig::Aes256Gcm, } } /// Preset: LDAP Enterprise (Active Directory integration) pub fn preset_ldap_enterprise() -> Self { Self { port: 4445, root: PathBuf::from("/data/smb"), share_name: "enterprise".to_string(), read_only: false, users: vec![], // LDAP handles authentication backend: SmbBackend::LocalFs, ldap: Some(LdapConfig { url: "ldap://ad.example.com:389".to_string(), base_dn: "dc=example,dc=com".to_string(), bind_dn: "cn=admin,cn=users,dc=example,dc=com".to_string(), bind_password: "admin_password".to_string(), user_search_base: "cn=users,dc=example,dc=com".to_string(), group_search_base: "cn=groups,dc=example,dc=com".to_string(), user_id_attr: "sAMAccountName".to_string(), user_filter: "(objectClass=user)".to_string(), group_filter: "(objectClass=group)".to_string(), home_dir_attr: "homeDirectory".to_string(), home_dir_prefix: "/home".to_string(), user_groups_attr: "memberOf".to_string(), }), cache: CacheConfig { read_cache_size_mb: 128, write_cache_size_mb: 64, cache_ttl_secs: 300, }, encryption: EncryptionConfig::Aes256Gcm, } } /// Preset: Read-Only Archive (public documents) pub fn preset_read_only_archive() -> Self { Self { port: 4445, root: PathBuf::from("/data/archive"), share_name: "archive".to_string(), read_only: true, users: vec![("public".to_string(), "".to_string())], backend: SmbBackend::LocalFs, ldap: None, cache: CacheConfig { read_cache_size_mb: 256, write_cache_size_mb: 0, cache_ttl_secs: 3600, }, encryption: EncryptionConfig::Disabled, } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_default_config() { let config = SmbConfig::default(); assert_eq!(config.port, 4445); assert_eq!(config.share_name, "share"); assert!(!config.read_only); assert_eq!(config.users.len(), 1); } #[test] fn test_generate_template() { let template = SmbConfig::generate_template(); assert!(template.contains("port = 4445")); assert!(template.contains("share_name = \"share\"")); assert!(template.contains("backend = \"localfs\"")); assert!(template.contains("[smb.users]")); assert!(template.contains("[smb.cache]")); assert!(template.contains("[smb.encryption]")); } #[test] fn test_preset_local_file_server() { let config = SmbConfig::preset_local_file_server(); assert_eq!(config.port, 4445); assert_eq!(config.share_name, "files"); assert_eq!(config.users.len(), 2); assert!(config.ldap.is_none()); } #[test] fn test_preset_s3_backend() { let config = SmbConfig::preset_s3_backend(); assert_eq!(config.share_name, "s3share"); assert!(matches!(config.backend, SmbBackend::S3 { .. })); assert!(matches!(config.encryption, EncryptionConfig::Aes256Gcm)); } #[test] fn test_preset_ldap_enterprise() { let config = SmbConfig::preset_ldap_enterprise(); assert_eq!(config.share_name, "enterprise"); assert!(config.ldap.is_some()); assert_eq!(config.users.len(), 0); } #[test] fn test_preset_read_only_archive() { let config = SmbConfig::preset_read_only_archive(); assert!(config.read_only); assert_eq!(config.share_name, "archive"); assert!(matches!(config.encryption, EncryptionConfig::Disabled)); } }