Browse Source

Make owner token for info action optional

timvisee 6 years ago
parent
commit
ff93b13b22

+ 1 - 1
src/action/delete.rs

@@ -40,7 +40,7 @@ impl<'a> Delete<'a> {
         history_tool::derive_file_properties(&matcher_main, &mut file);
 
         // Ensure the owner token is set
-        ensure_owner_token(file.owner_token_mut(), &matcher_main);
+        ensure_owner_token(file.owner_token_mut(), &matcher_main, false);
 
         // Send the file deletion request
         let result = ApiDelete::new(&file, None).invoke(&client);

+ 1 - 1
src/action/download.rs

@@ -16,6 +16,7 @@ use ffsend_api::pipe::ProgressReporter;
 #[cfg(feature = "archive")]
 use tempfile::{Builder as TempBuilder, NamedTempFile};
 
+use super::select_api_version;
 #[cfg(feature = "archive")]
 use crate::archive::archive::Archive;
 use crate::client::create_transfer_client;
@@ -26,7 +27,6 @@ use crate::progress::ProgressBar;
 use crate::util::{
     ensure_enough_space, ensure_password, prompt_yes, quit, quit_error, quit_error_msg, ErrorHints,
 };
-use super::select_api_version;
 
 /// A file download action.
 pub struct Download<'a> {

+ 37 - 31
src/action/info.rs

@@ -44,8 +44,8 @@ impl<'a> Info<'a> {
         #[cfg(feature = "history")]
         history_tool::derive_file_properties(&matcher_main, &mut file);
 
-        // Ensure the owner token is set
-        ensure_owner_token(file.owner_token_mut(), &matcher_main);
+        // Ask the user to set the owner token for more detailed information
+        let has_owner = ensure_owner_token(file.owner_token_mut(), &matcher_main, true);
 
         // Check whether the file exists
         let exists = ApiExists::new(&file).invoke(&client)?;
@@ -57,14 +57,16 @@ impl<'a> Info<'a> {
             return Err(Error::Expired);
         }
 
-        // Get the password
+        // Get the password, ensure the password is set when required
         let mut password = matcher_info.password();
-
-        // Ensure a password is set when required
         ensure_password(&mut password, exists.requires_password(), &matcher_main);
 
         // Fetch both file info and metadata
-        let info = ApiInfo::new(&file, None).invoke(&client)?;
+        let info = if has_owner {
+            Some(ApiInfo::new(&file, None).invoke(&client)?)
+        } else {
+            None
+        };
         let metadata = ApiMetadata::new(&file, password, false)
             .invoke(&client)
             .map_err(|err| {
@@ -72,12 +74,12 @@ impl<'a> Info<'a> {
             })
             .ok();
 
-        // Get the TTL duration
-        let ttl_millis = info.ttl_millis() as i64;
-        let ttl = Duration::milliseconds(ttl_millis);
-
-        // Update file properties
-        file.set_expire_duration(ttl);
+        // Update history file TTL if info is known
+        if let Some(info) = &info {
+            let ttl_millis = info.ttl_millis() as i64;
+            let ttl = Duration::milliseconds(ttl_millis);
+            file.set_expire_duration(ttl);
+        }
 
         // Add the file to the history
         #[cfg(feature = "history")]
@@ -91,7 +93,7 @@ impl<'a> Info<'a> {
         table.add_row(Row::new(vec![Cell::new("ID:"), Cell::new(file.id())]));
 
         // Metadata related details
-        if let Some(metadata) = metadata {
+        if let Some(metadata) = &metadata {
             // The file name
             table.add_row(Row::new(vec![
                 Cell::new("Name:"),
@@ -117,24 +119,28 @@ impl<'a> Info<'a> {
         }
 
         // The download count
-        table.add_row(Row::new(vec![
-            Cell::new("Downloads:"),
-            Cell::new(&format!(
-                "{} of {}",
-                info.download_count(),
-                info.download_limit()
-            )),
-        ]));
-
-        // The time to live
-        table.add_row(Row::new(vec![
-            Cell::new("Expiry:"),
-            Cell::new(&if ttl_millis >= 60 * 1000 {
-                format!("{} ({}s)", format_duration(&ttl), ttl.num_seconds())
-            } else {
-                format_duration(&ttl)
-            }),
-        ]));
+        if let Some(info) = &info {
+            table.add_row(Row::new(vec![
+                Cell::new("Downloads:"),
+                Cell::new(&format!(
+                    "{} of {}",
+                    info.download_count(),
+                    info.download_limit()
+                )),
+            ]));
+
+            // The time to live
+            let ttl_millis = info.ttl_millis() as i64;
+            let ttl = Duration::milliseconds(ttl_millis);
+            table.add_row(Row::new(vec![
+                Cell::new("Expiry:"),
+                Cell::new(&if ttl_millis >= 60 * 1000 {
+                    format!("{} ({}s)", format_duration(&ttl), ttl.num_seconds())
+                } else {
+                    format_duration(&ttl)
+                }),
+            ]));
+        }
 
         // Print the info table
         table.printstd();

+ 7 - 3
src/action/mod.rs

@@ -10,7 +10,7 @@ pub mod password;
 pub mod upload;
 pub mod version;
 
-use ffsend_api::action::version::{Version as ApiVersion, Error as VersionError};
+use ffsend_api::action::version::{Error as VersionError, Version as ApiVersion};
 use ffsend_api::api::DesiredVersion;
 use ffsend_api::url::Url;
 
@@ -23,7 +23,11 @@ use crate::util::print_warning;
 /// If the current desired version is set to the `DesiredVersion::Lookup` variant, this method
 /// will look up the server API version. It it's `DesiredVersion::Use` it will return and
 /// attempt to use the specified version.
-fn select_api_version(client: &Client, host: Url, desired: &mut DesiredVersion) -> Result<(), VersionError> {
+fn select_api_version(
+    client: &Client,
+    host: Url,
+    desired: &mut DesiredVersion,
+) -> Result<(), VersionError> {
     // Break if already specified
     if let DesiredVersion::Use(_) = desired {
         return Ok(());
@@ -46,7 +50,7 @@ fn select_api_version(client: &Client, host: Url, desired: &mut DesiredVersion)
         }
 
         // Propegate other errors
-        Err(e) => return Err(e)
+        Err(e) => return Err(e),
     }
 
     Ok(())

+ 1 - 1
src/action/params.rs

@@ -39,7 +39,7 @@ impl<'a> Params<'a> {
         history_tool::derive_file_properties(&matcher_main, &mut file);
 
         // Ensure the owner token is set
-        ensure_owner_token(file.owner_token_mut(), &matcher_main);
+        ensure_owner_token(file.owner_token_mut(), &matcher_main, false);
 
         // Build the parameters data object
         let data = ParamsDataBuilder::default()

+ 1 - 1
src/action/password.rs

@@ -40,7 +40,7 @@ impl<'a> Password<'a> {
         history_tool::derive_file_properties(&matcher_main, &mut file);
 
         // Ensure the owner token is set
-        ensure_owner_token(file.owner_token_mut(), &matcher_main);
+        ensure_owner_token(file.owner_token_mut(), &matcher_main, false);
 
         // Get the password to use and whether it was generated
         let (password, password_generated) = matcher_password.password();

+ 3 - 2
src/action/upload.rs

@@ -15,6 +15,7 @@ use prettytable::{format::FormatBuilder, Cell, Row, Table};
 #[cfg(feature = "archive")]
 use tempfile::{Builder as TempBuilder, NamedTempFile};
 
+use super::select_api_version;
 #[cfg(feature = "archive")]
 use crate::archive::archiver::Archiver;
 use crate::client::create_transfer_client;
@@ -28,7 +29,6 @@ use crate::util::{
     format_bytes, open_url, print_error, print_error_msg, prompt_yes, quit, quit_error_msg,
     ErrorHintsBuilder,
 };
-use super::select_api_version;
 
 /// A file upload action.
 pub struct Upload<'a> {
@@ -224,7 +224,8 @@ impl<'a> Upload<'a> {
             file_name,
             password.clone(),
             params,
-        ).invoke(&transfer_client, reporter)?;
+        )
+        .invoke(&transfer_client, reporter)?;
         let url = file.download_url(true);
 
         // Report the result

+ 7 - 5
src/cmd/arg/api.rs

@@ -3,7 +3,7 @@ use ffsend_api::api::{DesiredVersion, Version};
 
 use super::{CmdArg, CmdArgOption};
 use crate::config::API_VERSION_DESIRED_DEFAULT;
-use crate::util::{ErrorHints, quit_error_msg};
+use crate::util::{quit_error_msg, ErrorHints};
 
 /// The api argument.
 pub struct ArgApi {}
@@ -22,10 +22,12 @@ impl CmdArg for ArgApi {
             .hide_env_values(true)
             .global(true)
             .help("Server API version to use, '-' to lookup")
-            .long_help("Server API version to use, one of:\n\
-                2, 3: Firefox Send API versions\n\
-                auto, -: probe server to determine\
-            ")
+            .long_help(
+                "Server API version to use, one of:\n\
+                 2, 3: Firefox Send API versions\n\
+                 auto, -: probe server to determine\
+                 ",
+            )
     }
 }
 

+ 2 - 1
src/cmd/arg/owner.rs

@@ -45,6 +45,7 @@ impl<'a> CmdArgOption<'a> for ArgOwner {
         let matcher_main = MainMatcher::with(matches).unwrap();
 
         // Prompt for the owner token
-        Some(prompt_owner_token(&matcher_main))
+        // TODO: should this be optional?
+        Some(prompt_owner_token(&matcher_main, false))
     }
 }

+ 40 - 10
src/util.rs

@@ -536,8 +536,15 @@ fn derive_bool(input: &str) -> Option<bool> {
 }
 
 /// Prompt the user to enter an owner token.
-pub fn prompt_owner_token(main_matcher: &MainMatcher) -> String {
-    prompt("Owner token", main_matcher)
+pub fn prompt_owner_token(main_matcher: &MainMatcher, optional: bool) -> String {
+    prompt(
+        if optional {
+            "Owner token (optional)"
+        } else {
+            "Owner token"
+        },
+        main_matcher,
+    )
 }
 
 /// Get the owner token.
@@ -545,20 +552,40 @@ pub fn prompt_owner_token(main_matcher: &MainMatcher) -> String {
 /// parameter.
 ///
 /// This method will prompt the user for the token, if it wasn't set.
-pub fn ensure_owner_token(token: &mut Option<String>, main_matcher: &MainMatcher) {
+///
+/// Returns if an owner token was set.
+/// If `optional` is false, this always returns true.
+///
+/// If in non-interactive or force mode, the user will not be prompted for a token if `optional` is
+/// set to true.
+pub fn ensure_owner_token(
+    token: &mut Option<String>,
+    main_matcher: &MainMatcher,
+    optional: bool,
+) -> bool {
     // Check whehter we allow interaction
     let interact = !main_matcher.no_interact();
 
     // Notify that an owner token is required
     if interact && token.is_none() {
-        println!("The file owner token is required for authentication.");
+        if optional {
+            println!("The file owner token is recommended for authentication.");
+        } else {
+            println!("The file owner token is required for authentication.");
+        }
     }
 
     loop {
-        // Prompt for an owner token
+        // Prompt for an owner token if not set yet
         if token.is_none() {
+            // Do not ask for a token if optional when non-interactive or forced
+            if optional && (!interact || main_matcher.force()) {
+                return false;
+            }
+
+            // Ask for the token, or quit with an error if non-interactive
             if interact {
-                *token = Some(prompt_owner_token(main_matcher));
+                *token = Some(prompt_owner_token(main_matcher, optional));
             } else {
                 quit_error_msg(
                     "missing owner token, must be specified in no-interact mode",
@@ -571,15 +598,18 @@ pub fn ensure_owner_token(token: &mut Option<String>, main_matcher: &MainMatcher
             }
         }
 
-        // The token must not be empty
-        if token.as_ref().unwrap().is_empty() {
+        // The token must not be empty, unless it's optional
+        let empty = token.as_ref().unwrap().is_empty();
+        if empty {
+            *token = None;
+        }
+        if empty && !optional {
             eprintln!(
                 "Empty owner token given, which is invalid. Use {} to cancel.",
                 highlight("[CTRL+C]"),
             );
-            *token = None;
         } else {
-            break;
+            return !empty;
         }
     }
 }