Validating sha3 of a dapp bundle (#1993)

* Validating sha3 of a file

* sha3 in utils

* Removing devtools
This commit is contained in:
Tomasz Drwięga 2016-08-24 16:53:07 +02:00 committed by Gav Wood
parent 3dd1bdda50
commit 33e0a234f2
7 changed files with 84 additions and 16 deletions

2
Cargo.lock generated
View File

@ -289,6 +289,7 @@ version = "1.4.0"
dependencies = [ dependencies = [
"clippy 0.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.4.0",
"ethcore-rpc 1.4.0", "ethcore-rpc 1.4.0",
"ethcore-util 1.4.0", "ethcore-util 1.4.0",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)", "hyper 0.9.4 (git+https://github.com/ethcore/hyper)",
@ -502,6 +503,7 @@ dependencies = [
"table 0.1.0", "table 0.1.0",
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"using_queue 0.1.0", "using_queue 0.1.0",
"vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -30,7 +30,8 @@ use hyper::Control;
use hyper::status::StatusCode; use hyper::status::StatusCode;
use random_filename; use random_filename;
use util::Mutex; use util::{Mutex, H256};
use util::sha3::sha3;
use page::LocalPageEndpoint; use page::LocalPageEndpoint;
use handlers::{ContentHandler, AppFetcherHandler, DappHandler}; use handlers::{ContentHandler, AppFetcherHandler, DappHandler};
use endpoint::{Endpoint, EndpointPath, Handler}; use endpoint::{Endpoint, EndpointPath, Handler};
@ -137,10 +138,12 @@ impl<R: URLHint> AppFetcher<R> {
#[derive(Debug)] #[derive(Debug)]
pub enum ValidationError { pub enum ValidationError {
ManifestNotFound,
ManifestSerialization(String),
Io(io::Error), Io(io::Error),
Zip(zip::result::ZipError), Zip(zip::result::ZipError),
InvalidDappId,
ManifestNotFound,
ManifestSerialization(String),
HashMismatch { expected: H256, got: H256, },
} }
impl From<io::Error> for ValidationError { impl From<io::Error> for ValidationError {
@ -198,8 +201,15 @@ impl DappHandler for DappInstaller {
fn validate_and_install(&self, app_path: PathBuf) -> Result<Manifest, ValidationError> { fn validate_and_install(&self, app_path: PathBuf) -> Result<Manifest, ValidationError> {
trace!(target: "dapps", "Opening dapp bundle at {:?}", app_path); trace!(target: "dapps", "Opening dapp bundle at {:?}", app_path);
// TODO [ToDr] Validate file hash let mut file = try!(fs::File::open(app_path));
let file = try!(fs::File::open(app_path)); let hash = try!(sha3(&mut file));
let dapp_id = try!(self.dapp_id.as_str().parse().map_err(|_| ValidationError::InvalidDappId));
if dapp_id != hash {
return Err(ValidationError::HashMismatch {
expected: dapp_id,
got: hash,
});
}
// Unpack archive // Unpack archive
let mut zip = try!(zip::ZipArchive::new(file)); let mut zip = try!(zip::ZipArchive::new(file));
// First find manifest file // First find manifest file

View File

@ -55,11 +55,11 @@ extern crate rand;
extern crate ethabi; extern crate ethabi;
extern crate jsonrpc_core; extern crate jsonrpc_core;
extern crate jsonrpc_http_server; extern crate jsonrpc_http_server;
extern crate mime_guess;
extern crate rustc_serialize;
extern crate parity_dapps; extern crate parity_dapps;
extern crate ethcore_rpc; extern crate ethcore_rpc;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate mime_guess;
extern crate rustc_serialize;
mod endpoint; mod endpoint;
mod apps; mod apps;

View File

@ -67,13 +67,21 @@ impl RandomTempPath {
} }
} }
impl AsRef<Path> for RandomTempPath {
fn as_ref(&self) -> &Path {
self.as_path()
}
}
impl Drop for RandomTempPath { impl Drop for RandomTempPath {
fn drop(&mut self) { fn drop(&mut self) {
if let Err(e) = fs::remove_dir_all(self.as_path()) { if let Err(_) = fs::remove_dir_all(&self) {
if let Err(e) = fs::remove_file(&self) {
panic!("Failed to remove temp directory. Here's what prevented this from happening: ({})", e); panic!("Failed to remove temp directory. Here's what prevented this from happening: ({})", e);
} }
} }
} }
}
pub struct GuardedTempResult<T> { pub struct GuardedTempResult<T> {
pub result: Option<T>, pub result: Option<T>,

View File

@ -32,6 +32,7 @@ parking_lot = "0.2.6"
using_queue = { path = "using_queue" } using_queue = { path = "using_queue" }
table = { path = "table" } table = { path = "table" }
ansi_term = "0.7" ansi_term = "0.7"
tiny-keccak= "1.0"
[features] [features]
default = [] default = []

View File

@ -112,6 +112,7 @@ extern crate parking_lot;
pub extern crate using_queue; pub extern crate using_queue;
pub extern crate table; pub extern crate table;
extern crate ansi_term; extern crate ansi_term;
extern crate tiny_keccak;
pub mod bloom; pub mod bloom;
pub mod standard; pub mod standard;

View File

@ -17,7 +17,9 @@
//! Wrapper around tiny-keccak crate. //! Wrapper around tiny-keccak crate.
extern crate sha3 as sha3_ext; extern crate sha3 as sha3_ext;
use std::io;
use std::mem::uninitialized; use std::mem::uninitialized;
use tiny_keccak::Keccak;
use bytes::{BytesConvertable, Populatable}; use bytes::{BytesConvertable, Populatable};
use hash::{H256, FixedHash}; use hash::{H256, FixedHash};
use self::sha3_ext::*; use self::sha3_ext::*;
@ -64,6 +66,31 @@ impl<T> Hashable for T where T: BytesConvertable {
} }
} }
/// Calculate SHA3 of given stream.
pub fn sha3<R: io::Read>(r: &mut R) -> Result<H256, io::Error> {
let mut output = [0u8; 32];
let mut input = [0u8; 1024];
let mut sha3 = Keccak::new_keccak256();
// read file
loop {
let some = try!(r.read(&mut input));
if some == 0 {
break;
}
sha3.update(&input[0..some]);
}
sha3.finalize(&mut output);
Ok(output.into())
}
#[cfg(test)]
mod tests {
use std::fs;
use std::io::Write;
use super::*;
#[test] #[test]
fn sha3_empty() { fn sha3_empty() {
assert_eq!([0u8; 0].sha3(), SHA3_EMPTY); assert_eq!([0u8; 0].sha3(), SHA3_EMPTY);
@ -73,3 +100,22 @@ fn sha3_as() {
assert_eq!([0x41u8; 32].sha3(), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8")); assert_eq!([0x41u8; 32].sha3(), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8"));
} }
#[test]
fn should_sha3_a_file() {
// given
use devtools::RandomTempPath;
let path = RandomTempPath::new();
// Prepare file
{
let mut file = fs::File::create(&path).unwrap();
file.write_all(b"something").unwrap();
}
let mut file = fs::File::open(&path).unwrap();
// when
let hash = sha3(&mut file).unwrap();
// then
assert_eq!(format!("{:?}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87");
}
}