From 52c38b191974cb3c7ed6efd8c60997a4f07d5e00 Mon Sep 17 00:00:00 2001 From: Warren Date: Mon, 22 Jun 2026 05:22:14 +0800 Subject: [PATCH] Add SMB Configuration Templates (Phase 6) --- markbase-core/src/lib.rs | 1 + markbase-core/src/smb_config.rs | 339 ++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 markbase-core/src/smb_config.rs diff --git a/markbase-core/src/lib.rs b/markbase-core/src/lib.rs index 1ebe040..629b406 100644 --- a/markbase-core/src/lib.rs +++ b/markbase-core/src/lib.rs @@ -19,6 +19,7 @@ pub mod s3_config; pub mod s3_policy; pub mod s3_xml; pub mod scan; +pub mod smb_config; pub mod server; pub mod ssh_server; pub mod sync; diff --git a/markbase-core/src/smb_config.rs b/markbase-core/src/smb_config.rs new file mode 100644 index 0000000..a35dd6d --- /dev/null +++ b/markbase-core/src/smb_config.rs @@ -0,0 +1,339 @@ +//! 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)); + } +} \ No newline at end of file