86 lines
2.3 KiB
Rust
86 lines
2.3 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum TransferProtocol {
|
|
Sftp,
|
|
Zmodem,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum TransferDirection {
|
|
Upload,
|
|
Download,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct TransferRequest {
|
|
pub protocol: TransferProtocol,
|
|
pub direction: TransferDirection,
|
|
pub local_path: String,
|
|
pub remote_path: String,
|
|
}
|
|
|
|
impl TransferRequest {
|
|
pub fn validate(&self) -> Result<(), String> {
|
|
if self.local_path.trim().is_empty() {
|
|
return Err("local path is required".to_string());
|
|
}
|
|
if self.remote_path.trim().is_empty() {
|
|
return Err("remote path is required".to_string());
|
|
}
|
|
if self.local_path.contains("..") {
|
|
return Err("local path traversal is not allowed".to_string());
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum TransferEvent {
|
|
Queued,
|
|
Progress { bytes_done: u64, bytes_total: u64 },
|
|
Completed,
|
|
Failed(String),
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn validates_sftp_download_request() {
|
|
let request = TransferRequest {
|
|
protocol: TransferProtocol::Sftp,
|
|
direction: TransferDirection::Download,
|
|
local_path: "downloads/file.txt".to_string(),
|
|
remote_path: "/home/tom/file.txt".to_string(),
|
|
};
|
|
|
|
assert!(request.validate().is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn validates_zmodem_upload_request() {
|
|
let request = TransferRequest {
|
|
protocol: TransferProtocol::Zmodem,
|
|
direction: TransferDirection::Upload,
|
|
local_path: "uploads/firmware.bin".to_string(),
|
|
remote_path: "firmware.bin".to_string(),
|
|
};
|
|
|
|
assert!(request.validate().is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_local_path_traversal() {
|
|
let request = TransferRequest {
|
|
protocol: TransferProtocol::Sftp,
|
|
direction: TransferDirection::Download,
|
|
local_path: "../secret".to_string(),
|
|
remote_path: "/tmp/secret".to_string(),
|
|
};
|
|
|
|
assert!(request.validate().unwrap_err().contains("traversal"));
|
|
}
|
|
}
|