ffsend_api/action/
delete.rs

1use thiserror::Error;
2
3use crate::api::data::{Error as DataError, OwnedData};
4use crate::api::nonce::{request_nonce, NonceError};
5use crate::api::request::{ensure_success, ResponseError};
6use crate::api::url::UrlBuilder;
7use crate::client::Client;
8use crate::file::remote_file::RemoteFile;
9
10/// An action to delete a remote file.
11///
12/// This API specification for this action is compatible with both Firefox Send v2 and v3.
13pub struct Delete<'a> {
14    /// The remote file to delete.
15    file: &'a RemoteFile,
16
17    /// The authentication nonce.
18    /// May be an empty vector if the nonce is unknown.
19    nonce: Vec<u8>,
20}
21
22impl<'a> Delete<'a> {
23    /// Construct a new delete action for the given file.
24    pub fn new(file: &'a RemoteFile, nonce: Option<Vec<u8>>) -> Self {
25        Self {
26            file,
27            nonce: nonce.unwrap_or_default(),
28        }
29    }
30
31    /// Invoke the delete action.
32    pub fn invoke(mut self, client: &Client) -> Result<(), Error> {
33        // Fetch the authentication nonce if not set yet
34        if self.nonce.is_empty() {
35            self.nonce = self.fetch_auth_nonce(client)?;
36        }
37
38        // Create owned data, to send to the server for authentication
39        let data = OwnedData::from(DeleteData::new(), &self.file)
40            .map_err(|err| PrepareError::DeleteData(DeleteDataError::Owned(err)))?;
41
42        // Send the delete request
43        self.request_delete(client, &data)
44    }
45
46    /// Fetch the authentication nonce for the file from the remote server.
47    fn fetch_auth_nonce(&self, client: &Client) -> Result<Vec<u8>, Error> {
48        request_nonce(client, UrlBuilder::download(self.file, false)).map_err(|err| err.into())
49    }
50
51    /// Send a request to delete the remote file, with the given data.
52    fn request_delete(&self, client: &Client, data: &OwnedData<DeleteData>) -> Result<(), Error> {
53        // Get the delete URL, and send the request
54        let url = UrlBuilder::api_delete(self.file);
55        let response = client
56            .post(url)
57            .json(&data)
58            .send()
59            .map_err(|_| DeleteError::Request)?;
60
61        // Ensure the status code is successful
62        ensure_success(&response).map_err(|err| err.into())
63    }
64}
65
66/// The delete data object.
67/// This object is currently empty, as no additional data is sent to the
68/// server.
69#[derive(Debug, Serialize, Default)]
70pub struct DeleteData {}
71
72impl DeleteData {
73    /// Constructor.
74    pub fn new() -> Self {
75        DeleteData::default()
76    }
77}
78
79#[derive(Error, Debug)]
80pub enum Error {
81    /// An error occurred while preparing the action.
82    #[error("failed to prepare the action")]
83    Prepare(#[from] PrepareError),
84
85    /// The given Send file has expired, or did never exist in the first place.
86    /// Therefore the file could not be downloaded.
87    #[error("the file has expired or did never exist")]
88    Expired,
89
90    /// An error has occurred while sending the file deletion request.
91    #[error("failed to send the file deletion request")]
92    Delete(#[from] DeleteError),
93}
94
95impl From<NonceError> for Error {
96    fn from(err: NonceError) -> Error {
97        match err {
98            NonceError::Expired => Error::Expired,
99            err => Error::Prepare(PrepareError::Auth(err)),
100        }
101    }
102}
103
104#[derive(Debug, Error)]
105pub enum DeleteDataError {
106    /// Some error occurred while trying to wrap the deletion data in an
107    /// owned object, which is required for authentication on the server.
108    /// The wrapped error further described the problem.
109    #[error("")]
110    Owned(#[from] DataError),
111}
112
113#[derive(Error, Debug)]
114pub enum PrepareError {
115    /// Failed to authenticate
116    #[error("failed to authenticate")]
117    Auth(#[from] NonceError),
118
119    /// An error occurred while building the deletion data that will be
120    /// send to the server.
121    #[error("invalid parameters")]
122    DeleteData(#[from] DeleteDataError),
123}
124
125#[derive(Error, Debug)]
126pub enum DeleteError {
127    /// Sending the file deletion request failed.
128    #[error("failed to send file deletion request")]
129    Request,
130
131    /// The server responded with an error while requesting file deletion.
132    #[error("bad response from server while deleting file")]
133    Response(#[from] ResponseError),
134}
135
136impl From<ResponseError> for Error {
137    fn from(err: ResponseError) -> Self {
138        match err {
139            ResponseError::Expired => Error::Expired,
140            err => Error::Delete(DeleteError::Response(err)),
141        }
142    }
143}