First working implementation, nicly handle upload response, cleanup

This commit is contained in:
timvisee 2018-03-05 18:17:14 +01:00
parent 9753f1e3cc
commit 0786ed5917
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2

View file

@ -31,6 +31,8 @@ use reqwest::header::{
use reqwest::mime::APPLICATION_OCTET_STREAM; use reqwest::mime::APPLICATION_OCTET_STREAM;
use reqwest::multipart::Part; use reqwest::multipart::Part;
const TAG_LEN: usize = 16;
fn main() { fn main() {
// TODO: a fixed path for now, as upload test // TODO: a fixed path for now, as upload test
let path = Path::new("/home/timvisee/Pictures/Avatar/1024x1024/Avatar.png"); let path = Path::new("/home/timvisee/Pictures/Avatar/1024x1024/Avatar.png");
@ -88,13 +90,121 @@ fn main() {
.send() .send()
.unwrap(); .unwrap();
let text = res.text().unwrap(); // Parse the response
let upload_res: UploadResponse = res.json().unwrap();
// TODO: remove after debugging // Print the response
println!("TEXT: {}", text); println!("Response: {:#?}", upload_res);
println!("Secret key: {}", base64::encode(&secret));
println!("Download URL: {}", upload_res.download_url(&secret));
} }
const TAG_LEN: usize = 16; fn hkdf<'a>(
length: usize,
ikm: &[u8],
salt: Option<&[u8]>,
info: Option<&[u8]>
) -> Vec<u8> {
// Get the salt and info parameters, use defaults if undefined
let salt = salt.unwrap_or(b"");
let info = info.unwrap_or(b"");
// Define the digest to use
let digest = Sha256::new();
let mut pkr: Vec<u8> = vec![0u8; digest.output_bytes()];
hkdf_extract(digest, salt, ikm, &mut pkr);
let mut okm: Vec<u8> = vec![0u8; length];
hkdf_expand(digest, &pkr, info, &mut okm);
okm
}
fn derive_file_key(secret: &[u8]) -> Vec<u8> {
hkdf(16, secret, None, Some(b"encryption"))
}
fn derive_auth_key(secret: &[u8], password: Option<String>, url: Option<String>) -> Vec<u8> {
if password.is_none() {
hkdf(64, secret, None, Some(b"authentication"))
} else {
// TODO: implement this
unimplemented!();
}
}
fn derive_meta_key(secret: &[u8]) -> Vec<u8> {
hkdf(16, secret, None, Some(b"metadata"))
}
#[derive(Serialize)]
struct Metadata {
/// The input vector
iv: String,
/// The file name
name: String,
/// The file mimetype
#[serde(rename="type")]
mime: String,
}
impl Metadata {
/// Construct metadata from the given properties.
///
/// Parameters:
/// * iv: initialisation vector
/// * name: file name
/// * mime: file mimetype
pub fn from(iv: &[u8], name: String, mime: Mime) -> Self {
Metadata {
iv: base64::encode(iv),
name,
mime: mime.to_string(),
}
}
/// Convert this structure to a JSON string.
pub fn to_json(&self) -> String {
serde_json::to_string(&self).unwrap()
}
}
#[derive(Clone)]
struct XFileMetadata {
/// The metadata, as a base64 encoded string.
metadata: String,
}
impl XFileMetadata {
pub fn new(metadata: String) -> Self {
XFileMetadata {
metadata,
}
}
pub fn from(bytes: &[u8]) -> Self {
XFileMetadata::new(base64::encode(bytes))
}
}
impl Header for XFileMetadata {
fn header_name() -> &'static str {
"X-File-Metadata"
}
fn parse_header(_raw: &Raw) -> Result<Self, HyperError> {
// TODO: implement this some time
unimplemented!();
}
fn fmt_header(&self, f: &mut HeaderFormatter) -> fmt::Result {
// TODO: is this encoding base64 for us?
f.fmt_line(&self.metadata)
}
}
/// A file reader, that encrypts the file with the given cipher, and appends /// A file reader, that encrypts the file with the given cipher, and appends
/// the raw cipher tag. /// the raw cipher tag.
@ -150,109 +260,32 @@ impl Read for EncryptedFileReaderTagged {
} }
} }
#[derive(Clone)] /// The response from the server after a file has been uploaded.
struct XFileMetadata { /// This response contains the file ID and owner key, to manage the file.
/// The metadata, as a base64 encoded string.
metadata: String,
}
impl XFileMetadata {
pub fn new(metadata: String) -> Self {
XFileMetadata {
metadata,
}
}
pub fn from(bytes: &[u8]) -> Self {
XFileMetadata::new(base64::encode(bytes))
}
}
impl Header for XFileMetadata {
fn header_name() -> &'static str {
"X-File-Metadata"
}
fn parse_header(_raw: &Raw) -> Result<Self, HyperError> {
// TODO: implement this some time
unimplemented!();
}
fn fmt_header(&self, f: &mut HeaderFormatter) -> fmt::Result {
// TODO: is this encoding base64 for us?
f.fmt_line(&self.metadata)
}
}
#[derive(Serialize)]
struct Metadata {
/// The input vector
iv: String,
/// The file name
name: String,
/// The file mimetype
#[serde(rename="type")]
mime: String,
}
impl Metadata {
/// Construct metadata from the given properties.
/// ///
/// Parameters: /// It also contains the download URL, although an additional secret is
/// * iv: initialisation vector /// required.
/// * name: file name ///
/// * mime: file mimetype /// The download URL can be generated using `download_url()` which will
pub fn from(iv: &[u8], name: String, mime: Mime) -> Self { /// include the required secret in the URL.
Metadata { #[derive(Debug, Deserialize)]
iv: base64::encode(iv), struct UploadResponse {
name, /// The URL the file is reachable at.
mime: mime.to_string(), /// This includes the file ID, but does not include the secret.
} url: String,
/// The owner key, used to do further file modifications.
owner: String,
/// The file ID.
id: String,
} }
/// Convert this structure to a JSON string. impl UploadResponse {
pub fn to_json(&self) -> String { /// Get the download URL, including the secret.
serde_json::to_string(&self).unwrap() ///
/// The secret bytes must be passed to `secret`.
pub fn download_url(&self, secret: &[u8]) -> String {
format!("{}#{}", self.url, base64::encode(secret))
} }
} }
fn derive_file_key(secret: &[u8]) -> Vec<u8> {
hkdf(16, secret, None, Some(b"encryption"))
}
fn derive_auth_key(secret: &[u8], password: Option<String>, url: Option<String>) -> Vec<u8> {
if password.is_none() {
hkdf(64, secret, None, Some(b"authentication"))
} else {
// TODO: implement this
unimplemented!();
}
}
fn derive_meta_key(secret: &[u8]) -> Vec<u8> {
hkdf(16, secret, None, Some(b"metadata"))
}
fn hkdf<'a>(
length: usize,
ikm: &[u8],
salt: Option<&[u8]>,
info: Option<&[u8]>
) -> Vec<u8> {
// Get the salt and info parameters, use defaults if undefined
let salt = salt.unwrap_or(b"");
let info = info.unwrap_or(b"");
// Define the digest to use
let digest = Sha256::new();
let mut pkr: Vec<u8> = vec![0u8; digest.output_bytes()];
hkdf_extract(digest, salt, ikm, &mut pkr);
let mut okm: Vec<u8> = vec![0u8; length];
hkdf_expand(digest, &pkr, info, &mut okm);
okm
}