Support optional passwords as well for info command

This commit is contained in:
timvisee 2019-03-06 15:19:52 +01:00
parent ff93b13b22
commit e1d0ddee0d
No known key found for this signature in database
GPG key ID: B8DB720BC383E172
4 changed files with 98 additions and 29 deletions

View file

@ -76,7 +76,12 @@ impl<'a> Download<'a> {
}
// Ensure a password is set when required
ensure_password(&mut password, exists.requires_password(), &matcher_main);
ensure_password(
&mut password,
exists.requires_password(),
&matcher_main,
false,
);
// Fetch the file metadata
let metadata = ApiMetadata::new(&file, password.clone(), false).invoke(&client)?;

View file

@ -59,7 +59,12 @@ impl<'a> Info<'a> {
// Get the password, ensure the password is set when required
let mut password = matcher_info.password();
ensure_password(&mut password, exists.requires_password(), &matcher_main);
let has_password = ensure_password(
&mut password,
exists.requires_password(),
&matcher_main,
true,
);
// Fetch both file info and metadata
let info = if has_owner {
@ -67,12 +72,16 @@ impl<'a> Info<'a> {
} else {
None
};
let metadata = ApiMetadata::new(&file, password, false)
.invoke(&client)
.map_err(|err| {
print_error(err.context("failed to fetch file metadata, showing limited info"))
})
.ok();
let metadata = if has_password {
ApiMetadata::new(&file, password, false)
.invoke(&client)
.map_err(|err| {
print_error(err.context("failed to fetch file metadata, showing limited info"))
})
.ok()
} else {
None
};
// Update history file TTL if info is known
if let Some(info) = &info {
@ -92,7 +101,7 @@ impl<'a> Info<'a> {
// Add the ID
table.add_row(Row::new(vec![Cell::new("ID:"), Cell::new(file.id())]));
// Metadata related details
// Show file metadata if available
if let Some(metadata) = &metadata {
// The file name
table.add_row(Row::new(vec![
@ -118,8 +127,9 @@ impl<'a> Info<'a> {
]));
}
// The download count
// Show file info if available
if let Some(info) = &info {
// The download count
table.add_row(Row::new(vec![
Cell::new("Downloads:"),
Cell::new(&format!(

View file

@ -40,7 +40,7 @@ impl<'a> CmdArgOption<'a> for ArgPassword {
// Get the password argument value, or prompt
let password = match Self::value_raw(matches) {
Some(password) => password.into(),
None => prompt_password(&matcher_main),
None => prompt_password(&matcher_main, false).unwrap(),
};
// Check for empty passwords

View file

@ -376,9 +376,9 @@ pub fn check_empty_password(password: &str, matcher_main: &MainMatcher) {
/// Prompt the user to enter a password.
///
/// If `empty` is `false`, emtpy passwords aren't allowed unless forced.
pub fn prompt_password(main_matcher: &MainMatcher) -> String {
pub fn prompt_password(main_matcher: &MainMatcher, optional: bool) -> Option<String> {
// Quit with an error if we may not interact
if main_matcher.no_interact() {
if !optional && main_matcher.no_interact() {
quit_error_msg(
"missing password, must be specified in no-interact mode",
ErrorHintsBuilder::default()
@ -390,35 +390,89 @@ pub fn prompt_password(main_matcher: &MainMatcher) -> String {
}
// Prompt for the password
match prompt_password_stderr("Password: ") {
Ok(password) => password,
Err(err) => quit_error(
err.context("failed to read password from password prompt"),
ErrorHints::default(),
),
let prompt = if optional {
"Password (optional): "
} else {
"Password: "
};
match prompt_password_stderr(prompt) {
// If optional and nothing is entered, regard it as not defined
Ok(password) => {
if password.is_empty() && optional {
None
} else {
Some(password)
}
}
// On input error, propegate the error or don't use a password if optional
Err(err) => {
if !optional {
quit_error(
err.context("failed to read password from password prompt"),
ErrorHints::default(),
)
} else {
return None;
}
}
}
}
/// Get a password if required.
/// This method will ensure a password is set (or not) in the given `password`
/// parameter, as defined by `needs`.
/// If a password is needed, it may optionally be entered if `option` is set to true.
///
/// This method will prompt the user for a password, if one is required but
/// wasn't set. An ignore message will be shown if it was not required while it
/// was set.
pub fn ensure_password(password: &mut Option<String>, needs: bool, main_matcher: &MainMatcher) {
// Return if we're fine
///
/// Returns true if a password is now set, false if not.
pub fn ensure_password(
password: &mut Option<String>,
needs: bool,
main_matcher: &MainMatcher,
optional: bool,
) -> bool {
// Return if we're fine, ignore if set but we don't need it
if password.is_some() == needs {
return;
return needs;
}
if !needs {
// Notify the user a set password is ignored
if password.is_some() {
println!("Ignoring password, it is not required");
*password = None;
}
return false;
}
// Prompt for the password, or clear it if not required
if needs {
println!("This file is protected with a password.");
*password = Some(prompt_password(main_matcher));
} else {
println!("Ignoring password, it is not required");
*password = None;
// Check whehter we allow interaction
let interact = !main_matcher.no_interact();
loop {
// Prompt for an owner token if not set yet
if password.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 password
*password = prompt_password(main_matcher, optional);
}
// The token must not be empty, unless it's optional
let empty = password.is_none();
if empty && !optional {
eprintln!(
"No password given, which is required. Use {} to cancel.",
highlight("[CTRL+C]"),
);
} else {
return !empty;
}
}
}