From c79a2c229820806cff2b1502ee4c273e02e66c47 Mon Sep 17 00:00:00 2001 From: timvisee Date: Wed, 11 Apr 2018 00:36:19 +0200 Subject: [PATCH] Prompt password for info, move file checking to metadata action --- api/src/action/download.rs | 46 +++++++++----------------------------- api/src/action/metadata.rs | 45 ++++++++++++++++++++++++++++++++++++- cli/src/action/download.rs | 1 + cli/src/action/info.rs | 32 +++++++++++++------------- cli/src/util.rs | 1 + 5 files changed, 71 insertions(+), 54 deletions(-) diff --git a/api/src/action/download.rs b/api/src/action/download.rs index 04fff14..6e7a758 100644 --- a/api/src/action/download.rs +++ b/api/src/action/download.rs @@ -17,10 +17,6 @@ use crypto::sig::signature_encoded; use ext::status_code::StatusCodeExt; use file::remote_file::RemoteFile; use reader::{EncryptedFileWriter, ProgressReporter, ProgressWriter}; -use super::exists::{ - Error as ExistsError, - Exists as ExistsAction, -}; use super::metadata::{ Error as MetadataError, Metadata as MetadataAction, @@ -65,29 +61,18 @@ impl<'a> Download<'a> { client: &Client, reporter: Arc>, ) -> 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 let mut key = KeySet::from(self.file, self.password.as_ref()); // 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) .map_err(|err| match err { + MetadataError::PasswordRequired => Error::PasswordRequired, MetadataError::Expired => Error::Expired, _ => err.into(), })?; @@ -258,26 +243,21 @@ impl<'a> Download<'a> { #[derive(Fail, Debug)] 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. /// This step is required in order to succsessfully decrypt the /// file that will be downloaded. #[fail(display = "Failed to fetch file metadata")] 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. /// Therefore the file could not be downloaded. #[fail(display = "The file has expired or did never exist")] Expired, + /// A password is required, but was not given. + #[fail(display = "Missing password, password required")] + PasswordRequired, + /// An error occurred while downloading the file. #[fail(display = "Failed to download the file")] Download(#[cause] DownloadError), @@ -292,12 +272,6 @@ pub enum Error { File(String, #[cause] FileError), } -impl From for Error { - fn from(err: ExistsError) -> Error { - Error::Exists(err) - } -} - impl From for Error { fn from(err: MetadataError) -> Error { Error::Meta(err) diff --git a/api/src/action/metadata.rs b/api/src/action/metadata.rs index d170a0e..5c2d70c 100644 --- a/api/src/action/metadata.rs +++ b/api/src/action/metadata.rs @@ -12,6 +12,10 @@ use crypto::sig::signature_encoded; use ext::status_code::StatusCodeExt; use file::metadata::Metadata as MetadataData; use file::remote_file::RemoteFile; +use super::exists::{ + Error as ExistsError, + Exists as ExistsAction, +}; /// The HTTP status code that is returned for expired files. const FILE_EXPIRED_STATUS: StatusCode = StatusCode::NotFound; @@ -23,19 +27,43 @@ pub struct Metadata<'a> { /// An optional password to decrypt a protected file. password: Option, + + /// Check whether the file exists (recommended). + check_exists: bool, } impl<'a> Metadata<'a> { /// Construct a new metadata action. - pub fn new(file: &'a RemoteFile, password: Option) -> Self { + pub fn new( + file: &'a RemoteFile, + password: Option, + check_exists: bool, + ) -> Self { Self { file, password, + check_exists, } } /// Invoke the metadata action. pub fn invoke(self, client: &Client) -> Result { + // 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 let mut key = KeySet::from(self.file, self.password.as_ref()); @@ -173,6 +201,11 @@ impl<'a> MetadataResponse { #[derive(Fail, Debug)] 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. /// This may be because authentication failed, because decrypting the /// 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. #[fail(display = "The file has expired or did never exist")] Expired, + + /// A password is required, but was not given. + #[fail(display = "Missing password, password required")] + PasswordRequired, +} + +impl From for Error { + fn from(err: ExistsError) -> Error { + Error::Exists(err) + } } impl From for Error { diff --git a/cli/src/action/download.rs b/cli/src/action/download.rs index 62e7c47..1fcceb3 100644 --- a/cli/src/action/download.rs +++ b/cli/src/action/download.rs @@ -48,6 +48,7 @@ impl<'a> Download<'a> { let mut password = matcher_download.password(); // Check whether the file requires a password + // TODO: do not unwrap let exists = ApiExists::new(&file).invoke(&client).unwrap(); if exists.has_password() != password.is_some() { if exists.has_password() { diff --git a/cli/src/action/info.rs b/cli/src/action/info.rs index f4f6d11..6a9eca5 100644 --- a/cli/src/action/info.rs +++ b/cli/src/action/info.rs @@ -19,7 +19,7 @@ use cmd::matcher::{ Matcher, info::InfoMatcher, }; -use util::print_error; +use util::{print_error, prompt_password}; /// A file info action. pub struct Info<'a> { @@ -48,34 +48,32 @@ impl<'a> Info<'a> { // Parse the remote file based on the share URL, get the password 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 - // Make sure the file exists - let exists_response = ApiExists::new(&file) - .invoke(&client)?; - - // Make sure the file exists - if !exists_response.exists() { + // Check whether the file exists + // TODO: do not unwrap + let exists = ApiExists::new(&file).invoke(&client).unwrap(); + if !exists.exists() { return Err(Error::Expired); } - // Make sure a password is given when it is required - let has_password = password.is_some(); - if has_password != exists_response.has_password() { - if has_password { - // TODO: show a proper message here - println!("file not password protected, ignoring password"); + // Check whether the file requires a password + if exists.has_password() != password.is_some() { + if exists.has_password() { + println!("This file is protected with a password."); + password = Some(prompt_password()); } else { - // TODO: show a propper error here, or prompt for the password - panic!("password required"); + println!("Ignoring password, it is not required"); + password = None; } } // Fetch both file info and metadata 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( "Failed to fetch file metadata, showing limited info", ))) diff --git a/cli/src/util.rs b/cli/src/util.rs index fcb466f..697e06a 100644 --- a/cli/src/util.rs +++ b/cli/src/util.rs @@ -84,6 +84,7 @@ pub fn set_clipboard(content: String) -> Result<(), Box> { } /// Prompt the user to enter a password. +// TODO: do not prompt if no-interactive pub fn prompt_password() -> String { match prompt_password_stderr("Password: ") { Ok(password) => password,