ffsend_api/file/
metadata.rs

1use mime_guess::Mime;
2use serde_json;
3
4use crate::crypto::b64;
5
6/// The MIME type string for a tar file.
7const MIME_TAR: &str = "application/x-tar";
8
9/// File metadata, which is send to the server.
10#[derive(Debug, Serialize, Deserialize)]
11#[serde(untagged)]
12pub enum Metadata {
13    /// Metadata using in Send v2.
14    V2 {
15        /// The file name.
16        name: String,
17
18        /// The input vector.
19        iv: String,
20
21        /// The file mimetype.
22        /// TODO: can we use the `Mime` type here?
23        #[serde(rename = "type")]
24        mime: String,
25    },
26
27    /// Metadata using in Send v3.
28    V3 {
29        /// The file name.
30        name: String,
31
32        /// The file mimetype.
33        /// TODO: can we use the `Mime` type here?
34        #[serde(rename = "type")]
35        mime: String,
36
37        /// The file size.
38        size: u64,
39
40        /// The share manifest.
41        manifest: Manifest,
42    },
43}
44
45impl Metadata {
46    /// Construct metadata from the given properties.
47    ///
48    /// Parameters:
49    /// * `iv`: initialisation vector
50    /// * `name`: file name
51    /// * `mime`: file mimetype
52    pub fn from_send2(iv: &[u8], name: String, mime: &Mime) -> Self {
53        Metadata::V2 {
54            iv: b64::encode(iv),
55            name,
56            mime: mime.to_string(),
57        }
58    }
59
60    /// Construct metadata from the given properties.
61    ///
62    /// Parameters:
63    /// * `name`: file name
64    /// * `mime`: file mimetype
65    /// * `size`: file size
66    pub fn from_send3(name: String, mime: String, size: u64) -> Self {
67        Metadata::V3 {
68            name: name.clone(),
69            mime: mime.clone(),
70            size,
71            manifest: Manifest::from_file(name, mime, size),
72        }
73    }
74
75    /// Convert this structure to a JSON string.
76    pub fn to_json(&self) -> String {
77        serde_json::to_string(&self).unwrap()
78    }
79
80    /// Get the file name.
81    pub fn name(&self) -> &str {
82        match self {
83            Metadata::V2 { name, .. } => &name,
84            Metadata::V3 { name, .. } => &name,
85        }
86    }
87
88    /// Get the file MIME type.
89    pub fn mime(&self) -> &str {
90        match self {
91            Metadata::V2 { mime, .. } => &mime,
92            Metadata::V3 { mime, .. } => &mime,
93        }
94    }
95
96    /// Get the input vector if set.
97    ///
98    /// For Firefox Send v3 and above `None` is returned as no input vector is used.
99    // TODO: use an input vector length from a constant
100    pub fn iv(&self) -> Option<[u8; 12]> {
101        // Get the input vector
102        let iv = match self {
103            Metadata::V2 { iv, .. } => iv,
104            Metadata::V3 { .. } => return None,
105        };
106
107        // Decode the input vector
108        let decoded = b64::decode(iv).unwrap();
109
110        // Create a sized array
111        Some(*array_ref!(decoded, 0, 12))
112    }
113
114    /// Get the file size if set (`>= Send v3`).
115    pub fn size(&self) -> Option<u64> {
116        match self {
117            Metadata::V2 { .. } => None,
118            Metadata::V3 { size, .. } => Some(*size),
119        }
120    }
121
122    /**
123     * Check whether this MIME type is recognized as supported archive type.
124     * `true` is returned if it's an archive, `false` if not.
125     */
126    pub fn is_archive(&self) -> bool {
127        self.mime().to_lowercase() == MIME_TAR.to_lowercase()
128    }
129}
130
131/// Metadata manifest, used in Send v3.
132#[derive(Debug, Serialize, Deserialize)]
133pub struct Manifest {
134    /// Files part of a share.
135    files: Vec<ManifestFile>,
136}
137
138impl Manifest {
139    /// Construct a new manifest for the given list of files.
140    pub fn from(files: Vec<ManifestFile>) -> Self {
141        Self { files }
142    }
143
144    /// Construct a manifest for a single file, with the given properties.
145    pub fn from_file(name: String, mime: String, size: u64) -> Self {
146        Self::from(vec![ManifestFile::from(name, mime, size)])
147    }
148}
149
150/// Metadata manifest file, used in Send v3.
151#[derive(Debug, Serialize, Deserialize)]
152pub struct ManifestFile {
153    /// The file name.
154    name: String,
155
156    /// The file mimetype.
157    /// TODO: can we use the `Mime` type here?
158    #[serde(rename = "type")]
159    mime: String,
160
161    /// The file size.
162    size: u64,
163}
164
165impl ManifestFile {
166    /// Construct a new manifest file.
167    pub fn from(name: String, mime: String, size: u64) -> Self {
168        ManifestFile { name, mime, size }
169    }
170}