From db336184c382f36cd909586090692507a359920b Mon Sep 17 00:00:00 2001 From: Yakumo Hokori Date: Tue, 2 Sep 2025 22:46:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E7=9A=84=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 4 +++- src/server/mod.rs | 33 ++++++++++++++++++++++++++++++--- src/ui/mod.rs | 29 ++++++++++++++++++++++++++--- 6 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock index 115a0a1..da49006 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,6 +552,7 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" name = "ftphack" version = "0.1.0" dependencies = [ + "async-trait", "gtk", "libunftp", "tokio", diff --git a/Cargo.toml b/Cargo.toml index c5a6a1c..e818338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ gtk = "0.18.2" libunftp = "0.21.0" tokio = { version = "1.47.1", features = ["rt-multi-thread"] } unftp-sbe-fs = "0.3.0" +async-trait = "0.1.50" diff --git a/src/main.rs b/src/main.rs index e72e959..b477308 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,8 @@ fn main() { let ip = ui_clone.ip_entry.text(); let port: u16 = ui_clone.port_entry.text().parse().unwrap_or(2121); let dir = ui_clone.dir_entry.text(); + let username = ui_clone.username_entry.text(); + let password = ui_clone.password_entry.text(); // Validate directory let dir_path = PathBuf::from(&dir); @@ -40,7 +42,7 @@ fn main() { let addr: SocketAddr = format!("{}:{}", ip, port).parse().unwrap(); // Create and start server - match server::FtpServer::new(addr, dir_path) { + match server::FtpServer::new(addr, dir_path, username.to_string(), password.to_string()) { Ok(mut srv) => { // First start the server (initialize it) if let Err(e) = srv.start() { diff --git a/src/server/mod.rs b/src/server/mod.rs index 09d76df..ae0d517 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -2,18 +2,39 @@ use std::net::SocketAddr; use libunftp::{Server, ServerBuilder}; use unftp_sbe_fs::Filesystem; use std::sync::Arc; -use libunftp::auth::{AnonymousAuthenticator, DefaultUser}; +use libunftp::auth::{DefaultUser, Authenticator, Credentials, AuthenticationError}; use std::sync::atomic::{AtomicBool, Ordering}; +use async_trait::async_trait; pub struct FtpServer { server: Option>, addr: SocketAddr, root_dir: std::path::PathBuf, shutdown_flag: Arc, + username: String, + password: String, +} + +#[derive(Debug)] +struct CustomAuthenticator { + username: String, + password: String, +} + +#[async_trait] +impl Authenticator for CustomAuthenticator { + #[allow(clippy::type_complexity)] + async fn authenticate(&self, username: &str, creds: &Credentials) -> Result { + if username == self.username && creds.password.as_ref().map_or(false, |p| p == &self.password) { + Ok(DefaultUser {}) + } else { + Err(AuthenticationError::BadPassword) + } + } } impl FtpServer { - pub fn new(addr: SocketAddr, root_dir: std::path::PathBuf) -> Result> { + pub fn new(addr: SocketAddr, root_dir: std::path::PathBuf, username: String, password: String) -> Result> { if !root_dir.exists() { return Err(format!("Directory does not exist: {:?}", root_dir).into()); } @@ -22,15 +43,21 @@ impl FtpServer { addr, root_dir, shutdown_flag: Arc::new(AtomicBool::new(false)), + username, + password, }) } pub fn start(&mut self) -> Result<(), Box> { let root_dir = self.root_dir.clone(); + let username = self.username.clone(); + let password = self.password.clone(); + let authenticator = CustomAuthenticator { username, password }; + let server = ServerBuilder::new(Box::new(move || -> Filesystem { Filesystem::new(&root_dir).unwrap() })) .greeting("Welcome to FTP server") .passive_ports(50000..=60000) - .authenticator(Arc::new(AnonymousAuthenticator)) + .authenticator(Arc::new(authenticator)) .build()?; diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 754ebdf..48232b6 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -10,6 +10,8 @@ pub struct FtpUi { pub port_entry: gtk::Entry, pub dir_entry: gtk::Entry, pub dir_button: gtk::Button, + pub username_entry: gtk::Entry, + pub password_entry: gtk::Entry, } impl FtpUi { @@ -55,6 +57,19 @@ impl FtpUi { .build(); let dir_button = gtk::Button::with_label("浏览"); + // Username + let username_label = gtk::Label::new(Some("用户名:")); + let username_entry = gtk::Entry::builder() + .text("admin") + .build(); + + // Password + let password_label = gtk::Label::new(Some("密码:")); + let password_entry = gtk::Entry::builder() + .text("password") + .visibility(false) // Hide password input + .build(); + // Status let status_label = gtk::Label::new(Some("Status: Stopped")); @@ -74,10 +89,16 @@ impl FtpUi { grid.attach(&dir_entry, 1, 2, 1, 1); grid.attach(&dir_button, 2, 2, 1, 1); - grid.attach(&status_label, 0, 3, 3, 1); + grid.attach(&username_label, 0, 3, 1, 1); + grid.attach(&username_entry, 1, 3, 1, 1); - grid.attach(&start_button, 0, 4, 1, 1); - grid.attach(&stop_button, 1, 4, 1, 1); + grid.attach(&password_label, 0, 4, 1, 1); + grid.attach(&password_entry, 1, 4, 1, 1); + + grid.attach(&status_label, 0, 5, 3, 1); + + grid.attach(&start_button, 0, 6, 1, 1); + grid.attach(&stop_button, 1, 6, 1, 1); window.add(&grid); @@ -90,6 +111,8 @@ impl FtpUi { port_entry, dir_entry, dir_button, + username_entry, + password_entry, } } } \ No newline at end of file