Merge branch 'master' of github.com:timvisee/ffsend

This commit is contained in:
timvisee 2018-03-08 17:00:15 +01:00
commit 9a1c480564
No known key found for this signature in database
GPG key ID: 109CBA0BF74036C2
5 changed files with 119 additions and 90 deletions

7
Cargo.lock generated
View file

@ -184,6 +184,7 @@ dependencies = [
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version-compare 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -949,6 +950,11 @@ name = "vec_map"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version-compare"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.3"
@ -1107,6 +1113,7 @@ dependencies = [
"checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum version-compare 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "78068add8bf1e4d37d13fa5867182fe4c03f8e525c831053733f83aaba942d37"
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"

View file

@ -17,3 +17,4 @@ serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
sha2 = "0.7"
version-compare = "0.0"

19
src/b64.rs Normal file
View file

@ -0,0 +1,19 @@
//! A simple module for encoding or decoding a base64 string from or to a
//! byte array.
//!
//! This module uses an URL-safe scheme, and doesn't add additional padding
//! to the encoded strings.
extern crate base64;
use self::base64::DecodeError;
/// Encode the given byte slice using base64, in an URL-safe manner.
pub fn encode(input: &[u8]) -> String {
base64::encode_config(input, base64::URL_SAFE_NO_PAD)
}
/// Decode the given string as base64, in an URL-safe manner.
pub fn decode(input: &str) -> Result<Vec<u8>, DecodeError> {
base64::decode_config(input, base64::URL_SAFE_NO_PAD)
}

View file

@ -1,4 +1,3 @@
extern crate base64;
extern crate clap;
extern crate hkdf;
extern crate hyper;
@ -9,32 +8,26 @@ extern crate rand;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate sha2;
mod b64;
mod metadata;
mod reader;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use clap::{App, Arg};
use hkdf::Hkdf;
use hyper::error::Error as HyperError;
use mime_guess::Mime;
use openssl::symm::{Cipher, encrypt_aead};
use rand::{Rng, thread_rng};
use reqwest::header::{
Authorization,
Formatter as HeaderFormatter,
Header,
Raw
};
use reqwest::header::Authorization;
use reqwest::mime::APPLICATION_OCTET_STREAM;
use reqwest::multipart::Part;
use sha2::Sha256;
use metadata::{Metadata, XFileMetadata};
use reader::EncryptedFileReaderTagged;
fn main() {
@ -124,7 +117,7 @@ fn main() {
// Make the request
let mut res = client.post("http://localhost:8080/api/upload")
.header(Authorization(format!("send-v1 {}", base64_encode(&auth_key))))
.header(Authorization(format!("send-v1 {}", b64::encode(&auth_key))))
.header(XFileMetadata::from(&metadata))
.multipart(form)
.send()
@ -136,7 +129,7 @@ fn main() {
// Print the response
let url = upload_res.download_url(&secret);
println!("Response: {:#?}", upload_res);
println!("Secret key: {}", base64_encode(&secret));
println!("Secret key: {}", b64::encode(&secret));
println!("Download URL: {}", url);
// Open the URL in the browser
@ -188,77 +181,6 @@ fn derive_meta_key(secret: &[u8]) -> Vec<u8> {
hkdf(16, secret, Some(b"metadata"))
}
/// File metadata, which is send to the server.
#[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()
}
}
/// A X-File-Metadata header for reqwest, that is used to pass encrypted
/// metadata to the server.
///
/// The encrypted metadata (bytes) is base64 encoded when constructing this
/// header using `from`.
#[derive(Clone)]
struct XFileMetadata {
/// The metadata, as a base64 encoded string.
metadata: String,
}
impl XFileMetadata {
/// Construct the header from the given encrypted metadata.
pub fn from(bytes: &[u8]) -> Self {
XFileMetadata {
metadata: 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)
}
}
/// The response from the server after a file has been uploaded.
/// This response contains the file ID and owner key, to manage the file.
///
@ -285,11 +207,6 @@ impl UploadResponse {
///
/// The secret bytes must be passed to `secret`.
pub fn download_url(&self, secret: &[u8]) -> String {
format!("{}#{}", self.url, base64_encode(secret))
format!("{}#{}", self.url, b64::encode(secret))
}
}
/// Encode the given byte slice using base64, in an URL-safe manner.
fn base64_encode(input: &[u8]) -> String {
base64::encode_config(input, base64::URL_SAFE_NO_PAD)
}

85
src/metadata.rs Normal file
View file

@ -0,0 +1,85 @@
extern crate serde_json;
use std::fmt;
use hyper::error::Error as HyperError;
use mime_guess::Mime;
use reqwest::header::{
Formatter as HeaderFormatter,
Header,
Raw,
};
use b64;
/// File metadata, which is send to the server.
#[derive(Serialize)]
pub 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: b64::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()
}
}
/// A X-File-Metadata header for reqwest, that is used to pass encrypted
/// metadata to the server.
///
/// The encrypted metadata (bytes) is base64 encoded when constructing this
/// header using `from`.
#[derive(Clone)]
pub struct XFileMetadata {
/// The metadata, as a base64 encoded string.
metadata: String,
}
impl XFileMetadata {
/// Construct the header from the given encrypted metadata.
pub fn from(bytes: &[u8]) -> Self {
XFileMetadata {
metadata: b64::encode(bytes),
}
}
}
/// Make this struct usable as reqwest header.
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)
}
}