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}