Preserve FTP password and filename whitespace

This commit is contained in:
Danny Kim
2026-09-30 15:24:28 +09:00
parent d412eb1d13
commit e4f427fa9d
5 changed files with 76 additions and 4 deletions
Generated
+28
View File
@@ -99,6 +99,7 @@ name = "memona-plugin-ftp"
version = "0.1.2"
dependencies = [
"memona-plugin-sdk",
"tokio",
]
[[package]]
@@ -108,6 +109,12 @@ dependencies = [
"wit-bindgen",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "prettyplease"
version = "0.3.0"
@@ -195,6 +202,27 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tokio"
version = "1.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
dependencies = [
"pin-project-lite",
"tokio-macros",
]
[[package]]
name = "tokio-macros"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.26"
+3
View File
@@ -10,6 +10,9 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
memona-plugin-sdk = { path = "sdk" }
[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt"] }
[lints]
workspace = true
+7 -2
View File
@@ -64,7 +64,9 @@ fn names_a_conflict(text: &str) -> bool {
.collect();
words.contains(&"exists")
|| words.contains(&"nonempty")
|| words.windows(2).any(|pair| matches!(pair, ["not" | "non", "empty"]))
|| words
.windows(2)
.any(|pair| matches!(pair, ["not" | "non", "empty"]))
}
/// What the first reply to a transfer command means. A transfer answers with
@@ -255,7 +257,10 @@ mod tests {
));
// The same two conditions as other servers phrase them.
assert!(matches!(
refusal(550, "550 Cannot create a file when that file already exists."),
refusal(
550,
"550 Cannot create a file when that file already exists."
),
Err(ErrorCode::Conflict)
));
assert!(matches!(
+23 -1
View File
@@ -31,10 +31,11 @@ struct Ftp;
fn text(setting: Option<&Setting>) -> Option<String> {
match setting {
Some(Setting::Text(value)) | Some(Setting::Secret(value)) => {
Some(Setting::Text(value)) => {
let value = value.trim().to_owned();
(!value.is_empty()).then_some(value)
}
Some(Setting::Secret(value)) => Some(value.clone()),
Some(Setting::Toggle(_)) | None => None,
}
}
@@ -394,3 +395,24 @@ impl Guest for Ftp {
}
memona_plugin_sdk::export!(Ftp);
#[cfg(test)]
mod tests {
use super::text;
use memona_plugin_sdk::Setting;
#[tokio::test]
async fn secret_credentials_preserve_significant_whitespace() {
for password in [" ftp fixture secret ", " ", ""] {
assert_eq!(
text(Some(&Setting::Secret(password.to_owned()))),
Some(password.to_owned())
);
}
assert_eq!(
text(Some(&Setting::Text(" server.example ".to_owned()))),
Some("server.example".to_owned())
);
assert_eq!(text(Some(&Setting::Text(" ".to_owned()))), None);
}
}
+15 -1
View File
@@ -12,7 +12,6 @@ struct Facts<'a> {
fn facts(line: &str) -> Option<Facts<'_>> {
let (facts, name) = line.split_once(' ')?;
let name = name.trim();
if name.is_empty() {
return None;
}
@@ -106,6 +105,21 @@ mod tests {
use super::{machine_entry, machine_info, page};
use memona_plugin_sdk::{EntryKind, ErrorCode};
#[tokio::test]
async fn listing_names_preserve_significant_whitespace()
-> Result<(), ErrorCode> {
let listing = b"type=file;size=1; report.md \r\ntype=dir; spaced folder \r\ntype=file;size=2; \r\n";
let listed = page(listing, 0, 10)?;
let names: Vec<&str> = listed
.entries
.iter()
.map(|entry| entry.name.as_str())
.collect();
assert_eq!(names, [" report.md ", " spaced folder ", " "]);
assert!(listed.cursor.is_none());
Ok(())
}
#[test]
fn reads_kind_and_size_and_skips_the_directory_itself()
-> Result<(), &'static str> {