Prompt for owner tokens, allow owner token flag

This commit is contained in:
timvisee 2018-04-11 15:42:14 +02:00
parent 804455e13d
commit 5a4b1958e1
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
7 changed files with 91 additions and 20 deletions

View file

@ -171,6 +171,11 @@ impl RemoteFile {
self.owner_token.as_ref() self.owner_token.as_ref()
} }
/// Get the owner token if set.
pub fn owner_token_mut(&mut self) -> &mut Option<String> {
&mut self.owner_token
}
/// Set the owner token. /// Set the owner token.
pub fn set_owner_token(&mut self, token: Option<String>) { pub fn set_owner_token(&mut self, token: Option<String>) {
self.owner_token = token; self.owner_token = token;

View file

@ -14,7 +14,7 @@ use cmd::matcher::{
delete::DeleteMatcher, delete::DeleteMatcher,
}; };
use error::ActionError; use error::ActionError;
use util::print_success; use util::{ensure_owner_token, print_success};
/// A file delete action. /// A file delete action.
pub struct Delete<'a> { pub struct Delete<'a> {
@ -41,10 +41,11 @@ impl<'a> Delete<'a> {
// Create a reqwest client // Create a reqwest client
let client = Client::new(); let client = Client::new();
// Parse the remote file based on the share URL, get the password // Parse the remote file based on the share URL, get the owner token
let file = RemoteFile::parse_url(url, matcher_delete.owner())?; let mut file = RemoteFile::parse_url(url, matcher_delete.owner())?;
// TODO: show an informative error if the owner token isn't set // Ensure the owner token is set
ensure_owner_token(file.owner_token_mut());
// Send the file deletion request // Send the file deletion request
ApiDelete::new(&file, None).invoke(&client)?; ApiDelete::new(&file, None).invoke(&client)?;

View file

@ -19,7 +19,7 @@ use cmd::matcher::{
Matcher, Matcher,
info::InfoMatcher, info::InfoMatcher,
}; };
use util::{print_error, ensure_password}; use util::{ensure_owner_token, ensure_password, print_error};
/// A file info action. /// A file info action.
pub struct Info<'a> { pub struct Info<'a> {
@ -47,10 +47,11 @@ impl<'a> Info<'a> {
let client = Client::new(); let client = Client::new();
// Parse the remote file based on the share URL, get the password // Parse the remote file based on the share URL, get the password
let file = RemoteFile::parse_url(url, matcher_info.owner())?; let mut file = RemoteFile::parse_url(url, matcher_info.owner())?;
let mut password = matcher_info.password(); let mut password = matcher_info.password();
// TODO: show an informative error if the owner token isn't set // Ensure the owner token is set
ensure_owner_token(file.owner_token_mut());
// Check whether the file exists // Check whether the file exists
let exists = ApiExists::new(&file).invoke(&client)?; let exists = ApiExists::new(&file).invoke(&client)?;

View file

@ -11,7 +11,7 @@ use cmd::matcher::{
params::ParamsMatcher, params::ParamsMatcher,
}; };
use error::ActionError; use error::ActionError;
use util::print_success; use util::{ensure_owner_token, print_success};
/// A file parameters action. /// A file parameters action.
pub struct Params<'a> { pub struct Params<'a> {
@ -39,10 +39,10 @@ impl<'a> Params<'a> {
let client = Client::new(); let client = Client::new();
// Parse the remote file based on the share URL // Parse the remote file based on the share URL
// TODO: handle error here let mut file = RemoteFile::parse_url(url, matcher_params.owner())?;
let file = RemoteFile::parse_url(url, matcher_params.owner())?;
// TODO: show an informative error if the owner token isn't set // Ensure the owner token is set
ensure_owner_token(file.owner_token_mut());
// Build the parameters data object // Build the parameters data object
let data = ParamsDataBuilder::default() let data = ParamsDataBuilder::default()

View file

@ -8,7 +8,7 @@ use cmd::matcher::{
password::PasswordMatcher, password::PasswordMatcher,
}; };
use error::ActionError; use error::ActionError;
use util::print_success; use util::{ensure_owner_token, print_success};
/// A file password action. /// A file password action.
pub struct Password<'a> { pub struct Password<'a> {
@ -36,10 +36,10 @@ impl<'a> Password<'a> {
let client = Client::new(); let client = Client::new();
// Parse the remote file based on the share URL // Parse the remote file based on the share URL
// TODO: handle error here let mut file = RemoteFile::parse_url(url, matcher_password.owner())?;
let file = RemoteFile::parse_url(url, matcher_password.owner())?;
// TODO: show an informative error if the owner token isn't set // Ensure the owner token is set
ensure_owner_token(file.owner_token_mut());
// Execute an password action // Execute an password action
ApiPassword::new(&file, &matcher_password.password(), None).invoke(&client)?; ApiPassword::new(&file, &matcher_password.password(), None).invoke(&client)?;

View file

@ -1,6 +1,7 @@
use clap::{Arg, ArgMatches}; use clap::{Arg, ArgMatches};
use super::{CmdArg, CmdArgOption}; use super::{CmdArg, CmdArgFlag, CmdArgOption};
use util::prompt_owner_token;
/// The owner argument. /// The owner argument.
pub struct ArgOwner { } pub struct ArgOwner { }
@ -18,14 +19,30 @@ impl CmdArg for ArgOwner {
.alias("owner-token") .alias("owner-token")
.alias("token") .alias("token")
.value_name("TOKEN") .value_name("TOKEN")
.min_values(0)
.max_values(1)
.help("Specify the file owner token") .help("Specify the file owner token")
} }
} }
impl CmdArgFlag for ArgOwner { }
impl<'a> CmdArgOption<'a> for ArgOwner { impl<'a> CmdArgOption<'a> for ArgOwner {
type Value = Option<&'a str>; type Value = Option<String>;
fn value<'b: 'a>(matches: &'a ArgMatches<'b>) -> Self::Value { fn value<'b: 'a>(matches: &'a ArgMatches<'b>) -> Self::Value {
Self::value_raw(matches) // The owner token flag must be present
if !Self::is_present(matches) {
return None;
}
// Get the owner token from the argument if set
match Self::value_raw(matches) {
None => {},
p => return p.map(|p| p.into()),
}
// Prompt for the owner token
Some(prompt_owner_token())
} }
} }

View file

@ -6,7 +6,12 @@ extern crate open;
#[cfg(feature = "clipboard")] #[cfg(feature = "clipboard")]
use std::error::Error as StdError; use std::error::Error as StdError;
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::io::Error as IoError; use std::io::{
Error as IoError,
stdin,
stderr,
Write,
};
use std::process::{exit, ExitStatus}; use std::process::{exit, ExitStatus};
#[cfg(feature = "clipboard")] #[cfg(feature = "clipboard")]
@ -89,7 +94,7 @@ pub fn prompt_password() -> String {
match prompt_password_stderr("Password: ") { match prompt_password_stderr("Password: ") {
Ok(password) => password, Ok(password) => password,
Err(err) => quit_error(err.context( Err(err) => quit_error(err.context(
"Failed to read password from stdin with password prompt" "Failed to read password from password prompt"
)), )),
} }
} }
@ -116,3 +121,45 @@ pub fn ensure_password(password: &mut Option<String>, needs: bool) {
*password = None; *password = None;
} }
} }
/// Prompt the user to enter some value.
/// The prompt that is shown should be passed to `prompt`,
/// excluding the `:` suffix.
// TODO: do not prompt if no-interactive
pub fn prompt(prompt: &str) -> String {
// Show the prompt
eprint!("{}: ", prompt);
let _ = stderr().flush();
// Get the input
let mut input = String::new();
if let Err(err) = stdin().read_line(&mut input) {
quit_error(err.context(
"Failed to read input from prompt"
));
}
// Trim and return
input.trim().into()
}
/// Prompt the user to enter an owner token.
pub fn prompt_owner_token() -> String {
prompt("Owner token")
}
/// Get the owner token.
/// This method will ensure an owner token is set in the given `token`
/// parameter.
///
/// This method will prompt the user for the token, if it wasn't set.
pub fn ensure_owner_token(token: &mut Option<String>) {
// Return if we're fine
if token.is_some() {
return;
}
// Ask for the owner token
println!("The file owner token is required for authentication.");
*token = Some(prompt_owner_token());
}