mirror of
https://github.com/timvisee/ffsend.git
synced 2025-10-06 10:39:57 +02:00
Prompt for owner tokens, allow owner token flag
This commit is contained in:
parent
804455e13d
commit
5a4b1958e1
7 changed files with 91 additions and 20 deletions
|
@ -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;
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue