Browse Source

Prompt password for info, move file checking to metadata action

timvisee 7 years ago
parent
commit
c79a2c2298
5 changed files with 71 additions and 54 deletions
  1. 10 36
      api/src/action/download.rs
  2. 44 1
      api/src/action/metadata.rs
  3. 1 0
      cli/src/action/download.rs
  4. 15 17
      cli/src/action/info.rs
  5. 1 0
      cli/src/util.rs

+ 10 - 36
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<Mutex<ProgressReporter>>,
     ) -> 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<ExistsError> for Error {
-    fn from(err: ExistsError) -> Error {
-        Error::Exists(err)
-    }
-}
-
 impl From<MetadataError> for Error {
     fn from(err: MetadataError) -> Error {
         Error::Meta(err)

+ 44 - 1
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<String>,
+
+    /// 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<String>) -> Self {
+    pub fn new(
+        file: &'a RemoteFile,
+        password: Option<String>,
+        check_exists: bool,
+    ) -> Self {
         Self {
             file,
             password,
+            check_exists,
         }
     }
 
     /// Invoke the metadata action.
     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
         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<ExistsError> for Error {
+    fn from(err: ExistsError) -> Error {
+        Error::Exists(err)
+    }
 }
 
 impl From<RequestError> for Error {

+ 1 - 0
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() {

+ 15 - 17
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",
             )))

+ 1 - 0
cli/src/util.rs

@@ -84,6 +84,7 @@ pub fn set_clipboard(content: String) -> Result<(), Box<StdError>> {
 }
 
 /// 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,