Browse Source

Create owned data structure for improved authentication on generic data

timvisee 7 years ago
parent
commit
b62ba8b8fc
3 changed files with 75 additions and 21 deletions
  1. 24 21
      api/src/action/password.rs
  2. 50 0
      api/src/api/data.rs
  3. 1 0
      api/src/api/mod.rs

+ 24 - 21
api/src/action/password.rs

@@ -3,6 +3,10 @@
 use reqwest::{Client, StatusCode};
 use reqwest::header::Authorization;
 
+use api::data::{
+    Error as DataError,
+    OwnedData,
+};
 use crypto::b64;
 use crypto::key_set::KeySet;
 use crypto::sig::signature_encoded;
@@ -56,8 +60,9 @@ impl<'a> Password<'a> {
         // Derive a new authentication key
         key.derive_auth_password(self.password, &self.file.download_url(true));
 
-        // Build the password data
-        let data = PasswordData::from(self.file, &key)?;
+        // Build the password data, wrap it as owned
+        let data = OwnedData::from(PasswordData::from(&key), &self.file)
+            .map_err(|err| -> PrepareError { err.into() })?;
 
         // Send the request to change the password
         self.change_password(client, data, sig)
@@ -107,7 +112,7 @@ impl<'a> Password<'a> {
     fn change_password(
         &self,
         client: &Client,
-        data: PasswordData,
+        data: OwnedData<PasswordData>,
         sig: String,
     ) -> Result<(), ChangeError> {
         // Get the password URL, and send the change
@@ -132,28 +137,18 @@ impl<'a> Password<'a> {
 
 /// The data object to send to the password endpoint,
 /// which sets the file password.
-#[derive(Debug, Serialize)]
+#[derive(Debug, Serialize, Deserialize)]
 struct PasswordData {
-    /// The file owner token
-    owner_token: String,
-
     /// The authentication key
     auth: String,
 }
 
 impl PasswordData {
     /// Create the password data object from the given key set.
-    pub fn from(file: &RemoteFile, key: &KeySet)
-        -> Result<PasswordData, PrepareError>
-    {
-        Ok(
-            PasswordData {
-                owner_token: file.owner_token()
-                    .ok_or(PrepareError::NoOwnerToken)?
-                    .to_owned(),
-                auth: key.auth_key_encoded().unwrap(),
-            }
-        )
+    pub fn from(key: &KeySet) -> PasswordData {
+        PasswordData {
+            auth: key.auth_key_encoded().unwrap(),
+        }
     }
 }
 
@@ -202,9 +197,17 @@ pub enum PrepareError {
     #[fail(display = "Failed to compute cryptographic signature")]
     ComputeSignature,
 
-    /// The owner token was missing from the file, and is required.
-    #[fail(display = "Missing owner token, must be specified")]
-    NoOwnerToken,
+    /// Some error occurred while building the data that will be sent.
+    /// The owner token might possibly be missing, the wrapped error will
+    /// describe this further.
+    #[fail(display = "")]
+    Data(#[cause] DataError),
+}
+
+impl From<DataError> for PrepareError {
+    fn from(err: DataError) -> PrepareError {
+        PrepareError::Data(err)
+    }
 }
 
 #[derive(Fail, Debug)]

+ 50 - 0
api/src/api/data.rs

@@ -0,0 +1,50 @@
+use serde::{Deserialize, Serialize};
+
+use file::remote_file::RemoteFile;
+
+/// An owned data structure, that wraps generic data.
+/// This structure is used to send owned data to the Send server.  
+/// This owned data is authenticated using an `owner_token`,
+/// wwhich this structure manages.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct OwnedData<D> {
+    /// The owner token, used for request authentication purposes.
+    owner_token: String,
+
+    /// The wrapped data structure.
+    #[serde(flatten)]
+    inner: D,
+}
+
+impl<'a, D> OwnedData<D>
+    where
+        D: Serialize + Deserialize<'a>,
+{
+    /// Constructor.
+    pub fn new(owner_token: String, inner: D) -> Self {
+        OwnedData {
+            owner_token,
+            inner,
+        }
+    }
+
+    /// Wrap the given data structure with this owned data structure.
+    /// A `file` must be given, having a set owner token.
+    pub fn from(inner: D, file: &RemoteFile) -> Result<Self, Error> {
+        Ok(
+            Self::new(
+                file.owner_token()
+                    .ok_or(Error::NoOwnerToken)?
+                    .to_owned(),
+                inner,
+            )
+        )
+    }
+}
+
+#[derive(Debug, Fail)]
+pub enum Error {
+    /// Missing owner token, which is required.
+    #[fail(display = "Missing owner token, must be specified")]
+    NoOwnerToken,
+}

+ 1 - 0
api/src/api/mod.rs

@@ -0,0 +1 @@
+pub mod data;