From cb2d5f7844cc6c366aa603205a84c356d885bc32 Mon Sep 17 00:00:00 2001 From: timvisee Date: Mon, 23 Apr 2018 14:03:42 +0200 Subject: [PATCH] Check for expired files everywehere, propogate their errors --- api/src/action/delete.rs | 44 +++++++++++++++++++++++++------------- api/src/action/download.rs | 17 ++++++++------- api/src/action/info.rs | 37 +++++++++++++++++++++++--------- api/src/action/metadata.rs | 13 +++++++++-- api/src/action/params.rs | 36 +++++++++++++++++++++++-------- api/src/action/password.rs | 34 ++++++++++++++++++++++------- api/src/api/nonce.rs | 19 +++++++++++++--- cli/src/action/delete.rs | 17 ++++++++++++--- 8 files changed, 159 insertions(+), 58 deletions(-) diff --git a/api/src/action/delete.rs b/api/src/action/delete.rs index 093d44c..0dd1447 100644 --- a/api/src/action/delete.rs +++ b/api/src/action/delete.rs @@ -37,7 +37,9 @@ impl<'a> Delete<'a> { // Create owned data, to send to the server for authentication let data = OwnedData::from(DeleteData::new(), &self.file) - .map_err(|err| -> PrepareError { err.into() })?; + .map_err(|err| PrepareError::DeleteData( + DeleteDataError::Owned(err), + ))?; // Send the delete request self.request_delete(client, data).map_err(|err| err.into()) @@ -45,12 +47,12 @@ impl<'a> Delete<'a> { /// Fetch the authentication nonce for the file from the remote server. fn fetch_auth_nonce(&self, client: &Client) - -> Result, PrepareError> + -> Result, Error> { request_nonce( client, UrlBuilder::download(self.file, false), - ).map_err(|err| PrepareError::Auth(err)) + ).map_err(|err| err.into()) } /// Send a request to delete the remote file, with the given data. @@ -58,7 +60,7 @@ impl<'a> Delete<'a> { &self, client: &Client, data: OwnedData, - ) -> Result<(), DeleteError> { + ) -> Result<(), Error> { // Get the delete URL, and send the request let url = UrlBuilder::api_delete(self.file); let response = client.post(url) @@ -68,7 +70,7 @@ impl<'a> Delete<'a> { // Ensure the status code is succesful ensure_success(&response) - .map_err(|err| DeleteError::Response(err)) + .map_err(|err| err.into()) } } @@ -91,16 +93,25 @@ pub enum Error { #[fail(display = "Failed to prepare the action")] Prepare(#[cause] PrepareError), - // /// 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, + /// 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, /// An error has occurred while sending the filedeletion request. #[fail(display = "Failed to send the file deletion request")] Delete(#[cause] DeleteError), } +impl From for Error { + fn from(err: NonceError) -> Error { + match err { + NonceError::Expired => Error::Expired, + err => Error::Prepare(PrepareError::Auth(err)), + } + } +} + impl From for Error { fn from(err: PrepareError) -> Error { Error::Prepare(err) @@ -134,12 +145,6 @@ pub enum PrepareError { DeleteData(#[cause] DeleteDataError), } -impl From for PrepareError { - fn from(err: DataError) -> PrepareError { - PrepareError::DeleteData(DeleteDataError::Owned(err)) - } -} - #[derive(Fail, Debug)] pub enum DeleteError { /// Sending the file deletion request failed. @@ -150,3 +155,12 @@ pub enum DeleteError { #[fail(display = "Bad response from server while deleting file")] Response(#[cause] ResponseError), } + +impl From for Error { + fn from(err: ResponseError) -> Self { + match err { + ResponseError::Expired => Error::Expired, + err => Error::Delete(DeleteError::Response(err)), + } + } +} diff --git a/api/src/action/download.rs b/api/src/action/download.rs index df902d4..ebc5fe5 100644 --- a/api/src/action/download.rs +++ b/api/src/action/download.rs @@ -81,12 +81,7 @@ impl<'a> Download<'a> { self.password.clone(), self.check_exists, ) - .invoke(&client) - .map_err(|err| match err { - MetadataError::PasswordRequired => Error::PasswordRequired, - MetadataError::Expired => Error::Expired, - _ => err.into(), - })? + .invoke(&client)? }; key.set_iv(metadata.metadata().iv()); @@ -149,6 +144,7 @@ impl<'a> Download<'a> { return self.target.clone(); } + // TODO: are these todos below already implemented in CLI client? // TODO: canonicalize the path when possible // TODO: allow using `file.toml` as target without directory indication // TODO: return a nice error here as the path may be invalid @@ -235,7 +231,8 @@ impl<'a> Download<'a> { .start(len); // Write to the output file - io::copy(&mut reader, &mut writer).map_err(|_| DownloadError::Download)?; + io::copy(&mut reader, &mut writer) + .map_err(|_| DownloadError::Download)?; // Finish reporter.lock() @@ -284,7 +281,11 @@ pub enum Error { impl From for Error { fn from(err: MetadataError) -> Error { - Error::Meta(err) + match err { + MetadataError::Expired => Error::Expired, + MetadataError::PasswordRequired => Error::PasswordRequired, + err => Error::Meta(err), + } } } diff --git a/api/src/action/info.rs b/api/src/action/info.rs index b7a0647..5a803e7 100644 --- a/api/src/action/info.rs +++ b/api/src/action/info.rs @@ -50,12 +50,12 @@ impl<'a> Info<'a> { /// Fetch the authentication nonce for the file from the remote server. fn fetch_auth_nonce(&self, client: &Client) - -> Result, PrepareError> + -> Result, Error> { request_nonce( client, UrlBuilder::download(self.file, false), - ).map_err(|err| PrepareError::Auth(err)) + ).map_err(|err| err.into()) } /// Send the request for fetching the remote file info. @@ -63,7 +63,7 @@ impl<'a> Info<'a> { &self, client: &Client, data: OwnedData, - ) -> Result { + ) -> Result { // Get the info URL, and send the request let url = UrlBuilder::api_info(self.file); let mut response = client.post(url) @@ -72,13 +72,12 @@ impl<'a> Info<'a> { .map_err(|_| InfoError::Request)?; // Ensure the response is successful - ensure_success(&response) - .map_err(|err| InfoError::Response(err))?; + ensure_success(&response)?; // Decode the JSON response let response: InfoResponse = match response.json() { Ok(response) => response, - Err(err) => return Err(InfoError::Decode(err)), + Err(err) => return Err(InfoError::Decode(err).into()), }; Ok(response) @@ -143,22 +142,40 @@ pub enum Error { #[fail(display = "Failed to prepare the action")] Prepare(#[cause] PrepareError), - // /// 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, + /// 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, /// An error has occurred while sending the info request to the server. #[fail(display = "Failed to send the file info request")] Info(#[cause] InfoError), } +impl From for Error { + fn from(err: NonceError) -> Error { + match err { + NonceError::Expired => Error::Expired, + err => Error::Prepare(PrepareError::Auth(err)), + } + } +} + impl From for Error { fn from(err: PrepareError) -> Error { Error::Prepare(err) } } +impl From for Error { + fn from(err: ResponseError) -> Error { + match err { + ResponseError::Expired => Error::Expired, + err => Error::Info(InfoError::Response(err)), + } + } +} + impl From for Error { fn from(err: InfoError) -> Error { Error::Info(err) diff --git a/api/src/action/metadata.rs b/api/src/action/metadata.rs index 201198d..c487a92 100644 --- a/api/src/action/metadata.rs +++ b/api/src/action/metadata.rs @@ -74,12 +74,12 @@ impl<'a> Metadata<'a> { /// Fetch the authentication nonce for the file from the remote server. fn fetch_auth_nonce(&self, client: &Client) - -> Result, RequestError> + -> Result, Error> { request_nonce( client, UrlBuilder::download(self.file, false), - ).map_err(|err| RequestError::Auth(err)) + ).map_err(|err| err.into()) } /// Create a metadata nonce, and fetch the metadata for the file from the @@ -235,6 +235,15 @@ impl From for Error { } } +impl From for Error { + fn from(err: NonceError) -> Error { + match err { + NonceError::Expired => Error::Expired, + err => Error::Request(RequestError::Auth(err)), + } + } +} + #[derive(Fail, Debug)] pub enum RequestError { /// Failed authenticating, in order to fetch the file data. diff --git a/api/src/action/params.rs b/api/src/action/params.rs index 855802c..6da2116 100644 --- a/api/src/action/params.rs +++ b/api/src/action/params.rs @@ -67,12 +67,12 @@ impl<'a> Params<'a> { /// Fetch the authentication nonce for the file from the remote server. fn fetch_auth_nonce(&self, client: &Client) - -> Result, PrepareError> + -> Result, Error> { request_nonce( client, UrlBuilder::download(self.file, false), - ).map_err(|err| PrepareError::Auth(err)) + ).map_err(|err| err.into()) } /// Send the request for changing the parameters. @@ -80,7 +80,7 @@ impl<'a> Params<'a> { &self, client: &Client, data: OwnedData, - ) -> Result<(), ChangeError> { + ) -> Result<(), Error> { // Get the params URL, and send the change let url = UrlBuilder::api_params(self.file); let response = client.post(url) @@ -90,7 +90,7 @@ impl<'a> Params<'a> { // Ensure the response is successful ensure_success(&response) - .map_err(|err| ChangeError::Response(err)) + .map_err(|err| err.into()) } } @@ -165,10 +165,10 @@ pub enum Error { #[fail(display = "Failed to prepare setting the parameters")] Prepare(#[cause] PrepareError), - // /// 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, + /// 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, /// An error has occurred while sending the parameter change request to /// the server. @@ -176,6 +176,15 @@ pub enum Error { Change(#[cause] ChangeError), } +impl From for Error { + fn from(err: NonceError) -> Error { + match err { + NonceError::Expired => Error::Expired, + err => Error::Prepare(PrepareError::Auth(err)), + } + } +} + impl From for Error { fn from(err: PrepareError) -> Error { Error::Prepare(err) @@ -183,11 +192,20 @@ impl From for Error { } impl From for Error { - fn from(err: ChangeError) -> Error { + fn from(err:ChangeError) -> Error { Error::Change(err) } } +impl From for Error { + fn from(err: ResponseError) -> Error { + match err { + ResponseError::Expired => Error::Expired, + err => Error::Change(ChangeError::Response(err)), + } + } +} + #[derive(Debug, Fail)] pub enum ParamsDataError { /// The number of downloads is invalid, as it was out of the allowed diff --git a/api/src/action/password.rs b/api/src/action/password.rs index 7028951..91e4589 100644 --- a/api/src/action/password.rs +++ b/api/src/action/password.rs @@ -61,12 +61,12 @@ impl<'a> Password<'a> { /// Fetch the authentication nonce for the file from the Send server. fn fetch_auth_nonce(&self, client: &Client) - -> Result, PrepareError> + -> Result, Error> { request_nonce( client, UrlBuilder::download(self.file, false), - ).map_err(|err| PrepareError::Auth(err)) + ).map_err(|err| err.into()) } /// Send the request for changing the file password. @@ -74,7 +74,7 @@ impl<'a> Password<'a> { &self, client: &Client, data: OwnedData, - ) -> Result<(), ChangeError> { + ) -> Result<(), Error> { // Get the password URL, and send the change let url = UrlBuilder::api_password(self.file); let response = client.post(url) @@ -84,7 +84,7 @@ impl<'a> Password<'a> { // Ensure the response is successful ensure_success(&response) - .map_err(|err| ChangeError::Response(err)) + .map_err(|err| err.into()) } } @@ -111,10 +111,10 @@ pub enum Error { #[fail(display = "Failed to prepare setting the password")] Prepare(#[cause] PrepareError), - // /// 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, + /// 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, /// An error has occurred while sending the password change request to /// the server. @@ -122,6 +122,15 @@ pub enum Error { Change(#[cause] ChangeError), } +impl From for Error { + fn from(err: NonceError) -> Error { + match err { + NonceError::Expired => Error::Expired, + err => Error::Prepare(PrepareError::Auth(err)), + } + } +} + impl From for Error { fn from(err: PrepareError) -> Error { Error::Prepare(err) @@ -134,6 +143,15 @@ impl From for Error { } } +impl From for Error { + fn from(err: ResponseError) -> Error { + match err { + ResponseError::Expired => Error::Expired, + err => Error::Change(ChangeError::Response(err)), + } + } +} + #[derive(Fail, Debug)] pub enum PrepareError { /// Failed authenticating, needed to set a new password. diff --git a/api/src/api/nonce.rs b/api/src/api/nonce.rs index b4954f6..cfb3a4a 100644 --- a/api/src/api/nonce.rs +++ b/api/src/api/nonce.rs @@ -15,11 +15,10 @@ pub fn request_nonce(client: &Client, url: Url) // Make the request let response = client.get(url) .send() - .map_err(|_| NonceError::Request)?; + .map_err(|_| NonceError::Request)?; // Ensure the response is successful - ensure_success(&response) - .map_err(|err| NonceError::Response(err))?; + ensure_success(&response)?; // Extract the nonce header_nonce(&response) @@ -48,6 +47,11 @@ pub fn header_nonce(response: &Response) #[derive(Fail, Debug)] pub enum NonceError { + /// Sending the request to fetch a nonce failed, + /// as the file has expired or did never exist. + #[fail(display = "The file has expired or did never exist")] + Expired, + /// Sending the request to fetch a nonce failed. #[fail(display = "Failed to request encryption nonce")] Request, @@ -67,3 +71,12 @@ pub enum NonceError { #[fail(display = "Received malformed nonce")] MalformedNonce, } + +impl From for NonceError { + fn from(err: ResponseError) -> Self { + match err { + ResponseError::Expired => NonceError::Expired, + err => NonceError::Response(err), + } + } +} diff --git a/cli/src/action/delete.rs b/cli/src/action/delete.rs index 082bebd..e9125da 100644 --- a/cli/src/action/delete.rs +++ b/cli/src/action/delete.rs @@ -51,10 +51,14 @@ impl<'a> Delete<'a> { ensure_owner_token(file.owner_token_mut(), &matcher_main); // Send the file deletion request - ApiDelete::new(&file, None).invoke(&client)?; + let result = ApiDelete::new(&file, None).invoke(&client); + if let Err(DeleteError::Expired) = result { + // Remove the file from the history manager if it does not exist + history_tool::remove(&matcher_main, &file); + } + result?; // Remove the file from the history manager - // TODO: also remove if it was expired history_tool::remove(&matcher_main, &file); // Print a success message @@ -71,6 +75,10 @@ pub enum Error { #[fail(display = "Invalid share URL")] InvalidUrl(#[cause] FileParseError), + /// Could not delete, the file has expired or did never exist. + #[fail(display = "The file has expired or did never exist")] + Expired, + /// An error occurred while deleting the remote file. #[fail(display = "Failed to delete the shared file")] Delete(#[cause] DeleteError), @@ -84,6 +92,9 @@ impl From for Error { impl From for Error { fn from(err: DeleteError) -> Error { - Error::Delete(err) + match err { + DeleteError::Expired => Error::Expired, + err => Error::Delete(err), + } } }