FTP connections preserve passwords and filenames, with CI checking every change #1
Generated
+28
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user