From 29a1c9cdea90e872e63397418fc34851b341f3a5 Mon Sep 17 00:00:00 2001 From: Oliver Breitwieser Date: Sat, 27 Mar 2021 17:45:55 +0100 Subject: [PATCH] Add setting for default expiration --- CHANGELOG.md | 2 ++ example-config/asfa/config.yaml | 4 +++- src/cfg.rs | 27 +++++++++++++++++++++++++++ src/cmd/push.rs | 8 +++++++- test-utils/ci-config/raw.yaml | 11 +++++++++++ tests/simple-file-upload.rs | 21 +++++++++++++-------- 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cb5b26..30f5a27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ Previously: `asfa push --alias my-alias.txt -- my-original-file.txt` Now: `asfa push --alias my-alias.txt my-original-file.txt` * Check response for errors regaring `atd` not running if `--expire` specified. + * Now supports a default setting for `--expire` in the config. Same as auth, + both a global setting and host-specific settings are supported. * `list`: * More informative message if no files are present on remote site. * tests: diff --git a/example-config/asfa/config.yaml b/example-config/asfa/config.yaml index 20a49b7..ab59636 100644 --- a/example-config/asfa/config.yaml +++ b/example-config/asfa/config.yaml @@ -1,6 +1,7 @@ default_host: my-remote-site # optional, if only one host is defined, that one # will be used. Can be overwritten by ASFA_HOST # environment variable. +expire: 3days # optional, expire all uploads with the given duration by default verify_via_hash: true # defaults to true prefix_length: 32 # optional, defaults to 32, how many hex-digits of the hash # to print @@ -27,7 +28,8 @@ hosts: # dictionary mapping host alias to host settings # openSSH and defaults to 22 otherwise user: my-remote-user # defaults to current user if not set folder: /var/www/default/asfa # target folder where to store data, - # needs to be writable + # needs to be writable + expire: 1day # host-specific setting for expiring all uploads url: https://my-domain.eu/asfa # URL that is prefixed when URLs are # printed, this is of no functional # relevance right now diff --git a/src/cfg.rs b/src/cfg.rs index 4602c3e..838b6a6 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -26,6 +26,14 @@ pub struct Config { /// List of all configured hosts. hosts: HashMap, + /// Expire the uploaded file after the given amount of time via `at`-scheduled remote job. + /// + /// Select files newer than the given duration. Durations can be: seconds (sec, s), minutes + /// (min, m), days (d), weeks (w), months (M) or years (y). + /// + /// Mininum time till expiration is a minute. + pub expire: Option, + /// Length of prefix to use unless overwritten in host pub prefix_length: u8, @@ -62,6 +70,16 @@ pub struct Host { /// Overwrite global authentication settings for this host. pub auth: Auth, + /// Expire the uploaded file after the given amount of time via `at`-scheduled remote job. + /// + /// Select files newer than the given duration. Durations can be: seconds (sec, s), minutes + /// (min, m), days (d), weeks (w), months (M) or years (y). + /// + /// Mininum time till expiration is a minute. + /// + /// Overrides the global setting. + pub expire: Option, + /// In which folder do we store files on the host. pub folder: PathBuf, @@ -123,6 +141,7 @@ impl Default for Config { Config { auth: Auth::default(), default_host: None, + expire: None, hosts: HashMap::new(), prefix_length: 32, verify_via_hash: true, @@ -244,6 +263,9 @@ impl Config { std::env::var("ASFA_HOST") .ok() .or(get_string_from(config_yaml, "default_host")?.cloned()); + + config.expire = get_string_from(config_yaml, "expire")?.cloned(); + config.verify_via_hash = get_bool_from(config_yaml, "verify_via_hash")? .cloned() .unwrap_or(config.verify_via_hash); @@ -312,6 +334,10 @@ impl Host { let user = get_string_from(dict, "user")?.cloned(); + let expire = get_string_from(dict, "expire")? + .cloned() + .or_else(|| config.expire.clone()); + let folder = expanduser(get_required(dict, "folder", get_string_from)?)?; let group = get_string_from(dict, "group")?.cloned(); @@ -334,6 +360,7 @@ impl Host { Ok(Host { alias, auth, + expire, folder, group, hostname, diff --git a/src/cmd/push.rs b/src/cmd/push.rs index 493a95e..1bfee4e 100644 --- a/src/cmd/push.rs +++ b/src/cmd/push.rs @@ -30,6 +30,8 @@ pub struct Push { /// (min, m), days (d), weeks (w), months (M) or years (y). /// /// Mininum time till expiration is a minute. + /// + /// Any setting specified via command line overwrites any settings from config files. #[clap(short, long)] expire: Option, @@ -90,7 +92,11 @@ impl Push { let hash = get_hash(to_upload, prefix_length) .with_context(|| format!("Could not read {} to compute hash.", to_upload.display()))?; - let expirer = if let Some(delay) = self.expire.as_ref() { + let expirer = if let Some(delay) = self + .expire + .as_ref() + .or_else(|| session.host.expire.as_ref()) + { Some(At::new(session, &delay)?) } else { None diff --git a/test-utils/ci-config/raw.yaml b/test-utils/ci-config/raw.yaml index f3db8ec..caf094d 100644 --- a/test-utils/ci-config/raw.yaml +++ b/test-utils/ci-config/raw.yaml @@ -21,3 +21,14 @@ hosts: auth: interactive: false use_agent: false + asfa-ci-pw-expire: + hostname: localhost:2222 + folder: /var/www/default/uploads + url: https://my-domain.eu/asfa + group: "1234" + user: asfa-ci-user + password: foobar + expire: 1min + auth: + interactive: false + use_agent: false diff --git a/tests/simple-file-upload.rs b/tests/simple-file-upload.rs index 9a9cc8a..bc1b00f 100644 --- a/tests/simple-file-upload.rs +++ b/tests/simple-file-upload.rs @@ -128,7 +128,7 @@ fn expiring_file_upload_begin(host: &str) -> Result<(PathBuf, Instant)> { let hash_b64 = base64::encode_config(hex::decode(hash)?, base64::URL_SAFE); // also test specifying alias for single file first run_cmd(format!( - "cargo run -- --loglevel debug -H {} push --alias {} {} --expire 1min", + "cargo run -- --loglevel debug -H {} push --alias {} {}", host, alias, local.display() @@ -155,14 +155,18 @@ fn expiring_file_upload_begin(host: &str) -> Result<(PathBuf, Instant)> { } fn expiring_file_upload_verify(path: &Path, uploaded_at: &Instant) -> Result<()> { - let need_to_wait = Duration::from_secs(61); // wait two minutes to be sure - let already_waited = Instant::now().duration_since(*uploaded_at); - if already_waited < need_to_wait { + let need_to_wait = Duration::from_secs(121); // wait two minutes to be sure + let mut already_waited = Instant::now().duration_since(*uploaded_at); + while Path::new(path).exists() && already_waited < need_to_wait { println!( - "Waiting for {}s to ensure upload expires.", - (need_to_wait - already_waited).as_secs() + "Waiting {}s for upload to expire.", + already_waited.as_secs() ); - std::thread::sleep(need_to_wait - already_waited); + std::thread::sleep(std::cmp::min( + need_to_wait - already_waited, + std::time::Duration::from_secs(10), + )); + already_waited = Instant::now().duration_since(*uploaded_at); } if Path::new(path).exists() { @@ -252,7 +256,8 @@ fn clean_all(host: &str) -> Result<()> { fn run_tests() -> Result<()> { fixture::ensure_env()?; - let (upload_to_expire, to_expire_uploaded_at) = expiring_file_upload_begin("asfa-ci-pw")?; + let (upload_to_expire, to_expire_uploaded_at) = + expiring_file_upload_begin("asfa-ci-pw-expire")?; simple_file_upload("asfa-ci-pw")?; simple_file_upload("asfa-ci-key")?; upload_with_prefix_suffix("asfa-ci-key")?;