Prompt password for info, move file checking to metadata action

This commit is contained in:
timvisee 2018-04-11 00:36:19 +02:00
parent 35c376ab82
commit c79a2c2298
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
5 changed files with 71 additions and 54 deletions

View file

@ -17,10 +17,6 @@ use crypto::sig::signature_encoded;
use ext::status_code::StatusCodeExt; use ext::status_code::StatusCodeExt;
use file::remote_file::RemoteFile; use file::remote_file::RemoteFile;
use reader::{EncryptedFileWriter, ProgressReporter, ProgressWriter}; use reader::{EncryptedFileWriter, ProgressReporter, ProgressWriter};
use super::exists::{
Error as ExistsError,
Exists as ExistsAction,
};
use super::metadata::{ use super::metadata::{
Error as MetadataError, Error as MetadataError,
Metadata as MetadataAction, Metadata as MetadataAction,
@ -65,29 +61,18 @@ impl<'a> Download<'a> {
client: &Client, client: &Client,
reporter: Arc<Mutex<ProgressReporter>>, reporter: Arc<Mutex<ProgressReporter>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Make sure the given file exists
if self.check_exists {
let exist_response = ExistsAction::new(&self.file)
.invoke(&client)?;
// Return an error if the file does not exist
if !exist_response.exists() {
return Err(Error::Expired);
}
// Make sure a password is given when it is required
if !self.password.is_some() && exist_response.has_password() {
return Err(Error::PasswordRequired);
}
}
// Create a key set for the file // Create a key set for the file
let mut key = KeySet::from(self.file, self.password.as_ref()); let mut key = KeySet::from(self.file, self.password.as_ref());
// Fetch the file metadata, update the input vector in the key set // Fetch the file metadata, update the input vector in the key set
let metadata = MetadataAction::new(self.file, self.password.clone()) let metadata = MetadataAction::new(
self.file,
self.password.clone(),
self.check_exists,
)
.invoke(&client) .invoke(&client)
.map_err(|err| match err { .map_err(|err| match err {
MetadataError::PasswordRequired => Error::PasswordRequired,
MetadataError::Expired => Error::Expired, MetadataError::Expired => Error::Expired,
_ => err.into(), _ => err.into(),
})?; })?;
@ -258,26 +243,21 @@ impl<'a> Download<'a> {
#[derive(Fail, Debug)] #[derive(Fail, Debug)]
pub enum Error { pub enum Error {
/// An error occurred while checking whether the file exists on the
/// server.
#[fail(display = "Failed to check whether the file exists")]
Exists(#[cause] ExistsError),
/// An error occurred while fetching the metadata of the file. /// An error occurred while fetching the metadata of the file.
/// This step is required in order to succsessfully decrypt the /// This step is required in order to succsessfully decrypt the
/// file that will be downloaded. /// file that will be downloaded.
#[fail(display = "Failed to fetch file metadata")] #[fail(display = "Failed to fetch file metadata")]
Meta(#[cause] MetadataError), Meta(#[cause] MetadataError),
/// A password is required, but was not given.
#[fail(display = "Missing password, password required")]
PasswordRequired,
/// The given Send file has expired, or did never exist in the first place. /// The given Send file has expired, or did never exist in the first place.
/// Therefore the file could not be downloaded. /// Therefore the file could not be downloaded.
#[fail(display = "The file has expired or did never exist")] #[fail(display = "The file has expired or did never exist")]
Expired, Expired,
/// A password is required, but was not given.
#[fail(display = "Missing password, password required")]
PasswordRequired,
/// An error occurred while downloading the file. /// An error occurred while downloading the file.
#[fail(display = "Failed to download the file")] #[fail(display = "Failed to download the file")]
Download(#[cause] DownloadError), Download(#[cause] DownloadError),
@ -292,12 +272,6 @@ pub enum Error {
File(String, #[cause] FileError), File(String, #[cause] FileError),
} }
impl From<ExistsError> for Error {
fn from(err: ExistsError) -> Error {
Error::Exists(err)
}
}
impl From<MetadataError> for Error { impl From<MetadataError> for Error {
fn from(err: MetadataError) -> Error { fn from(err: MetadataError) -> Error {
Error::Meta(err) Error::Meta(err)

View file

@ -12,6 +12,10 @@ use crypto::sig::signature_encoded;
use ext::status_code::StatusCodeExt; use ext::status_code::StatusCodeExt;
use file::metadata::Metadata as MetadataData; use file::metadata::Metadata as MetadataData;
use file::remote_file::RemoteFile; use file::remote_file::RemoteFile;
use super::exists::{
Error as ExistsError,
Exists as ExistsAction,
};
/// The HTTP status code that is returned for expired files. /// The HTTP status code that is returned for expired files.
const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound; const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound;
@ -23,19 +27,43 @@ pub struct Metadata<'a> {
/// An optional password to decrypt a protected file. /// An optional password to decrypt a protected file.
password: Option<String>, password: Option<String>,
/// Check whether the file exists (recommended).
check_exists: bool,
} }
impl<'a> Metadata<'a> { impl<'a> Metadata<'a> {
/// Construct a new metadata action. /// Construct a new metadata action.
pub fn new(file: &'a RemoteFile, password: Option<String>) -> Self { pub fn new(
file: &'a RemoteFile,
password: Option<String>,
check_exists: bool,
) -> Self {
Self { Self {
file, file,
password, password,
check_exists,
} }
} }
/// Invoke the metadata action. /// Invoke the metadata action.
pub fn invoke(self, client: &Client) -> Result<MetadataResponse, Error> { pub fn invoke(self, client: &Client) -> Result<MetadataResponse, Error> {
// Make sure the given file exists
if self.check_exists {
let exist_response = ExistsAction::new(&self.file)
.invoke(&client)?;
// Return an error if the file does not exist
if !exist_response.exists() {
return Err(Error::Expired);
}
// Make sure a password is given when it is required
if !self.password.is_some() && exist_response.has_password() {
return Err(Error::PasswordRequired);
}
}
// Create a key set for the file // Create a key set for the file
let mut key = KeySet::from(self.file, self.password.as_ref()); let mut key = KeySet::from(self.file, self.password.as_ref());
@ -173,6 +201,11 @@ impl<'a> MetadataResponse {
#[derive(Fail, Debug)] #[derive(Fail, Debug)]
pub enum Error { pub enum Error {
/// An error occurred while checking whether the file exists on the
/// server.
#[fail(display = "Failed to check whether the file exists")]
Exists(#[cause] ExistsError),
/// A general error occurred while requesting the file data. /// A general error occurred while requesting the file data.
/// This may be because authentication failed, because decrypting the /// This may be because authentication failed, because decrypting the
/// file metadata didn't succeed, or due to some other reason. /// file metadata didn't succeed, or due to some other reason.
@ -183,6 +216,16 @@ pub enum Error {
/// Therefore the file could not be downloaded. /// Therefore the file could not be downloaded.
#[fail(display = "The file has expired or did never exist")] #[fail(display = "The file has expired or did never exist")]
Expired, Expired,
/// A password is required, but was not given.
#[fail(display = "Missing password, password required")]
PasswordRequired,
}
impl From<ExistsError> for Error {
fn from(err: ExistsError) -> Error {
Error::Exists(err)
}
} }
impl From<RequestError> for Error { impl From<RequestError> for Error {

View file

@ -48,6 +48,7 @@ impl<'a> Download<'a> {
let mut password = matcher_download.password(); let mut password = matcher_download.password();
// Check whether the file requires a password // Check whether the file requires a password
// TODO: do not unwrap
let exists = ApiExists::new(&file).invoke(&client).unwrap(); let exists = ApiExists::new(&file).invoke(&client).unwrap();
if exists.has_password() != password.is_some() { if exists.has_password() != password.is_some() {
if exists.has_password() { if exists.has_password() {

View file

@ -19,7 +19,7 @@ use cmd::matcher::{
Matcher, Matcher,
info::InfoMatcher, info::InfoMatcher,
}; };
use util::print_error; use util::{print_error, prompt_password};
/// A file info action. /// A file info action.
pub struct Info<'a> { pub struct Info<'a> {
@ -48,34 +48,32 @@ impl<'a> Info<'a> {
// 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 file = RemoteFile::parse_url(url, matcher_info.owner())?;
let password = matcher_info.password(); let mut password = matcher_info.password();
// TODO: show an informative error if the owner token isn't set // TODO: show an informative error if the owner token isn't set
// Make sure the file exists // Check whether the file exists
let exists_response = ApiExists::new(&file) // TODO: do not unwrap
.invoke(&client)?; let exists = ApiExists::new(&file).invoke(&client).unwrap();
if !exists.exists() {
// Make sure the file exists
if !exists_response.exists() {
return Err(Error::Expired); return Err(Error::Expired);
} }
// Make sure a password is given when it is required // Check whether the file requires a password
let has_password = password.is_some(); if exists.has_password() != password.is_some() {
if has_password != exists_response.has_password() { if exists.has_password() {
if has_password { println!("This file is protected with a password.");
// TODO: show a proper message here password = Some(prompt_password());
println!("file not password protected, ignoring password");
} else { } else {
// TODO: show a propper error here, or prompt for the password println!("Ignoring password, it is not required");
panic!("password required"); password = None;
} }
} }
// Fetch both file info and metadata // Fetch both file info and metadata
let info = ApiInfo::new(&file, None).invoke(&client)?; let info = ApiInfo::new(&file, None).invoke(&client)?;
let metadata = ApiMetadata::new(&file, password).invoke(&client) let metadata = ApiMetadata::new(&file, password, false)
.invoke(&client)
.map_err(|err| print_error(err.context( .map_err(|err| print_error(err.context(
"Failed to fetch file metadata, showing limited info", "Failed to fetch file metadata, showing limited info",
))) )))

View file

@ -84,6 +84,7 @@ pub fn set_clipboard(content: String) -> Result<(), Box<StdError>> {
} }
/// Prompt the user to enter a password. /// Prompt the user to enter a password.
// TODO: do not prompt if no-interactive
pub fn prompt_password() -> String { pub fn prompt_password() -> String {
match prompt_password_stderr("Password: ") { match prompt_password_stderr("Password: ") {
Ok(password) => password, Ok(password) => password,