diff --git a/Cargo.lock b/Cargo.lock index 63caf7b12..2ba3c1786 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "0.2.16" @@ -649,6 +658,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "1.8.1" @@ -1040,6 +1058,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "dirs" version = "3.0.2" @@ -1458,6 +1485,16 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -1978,9 +2015,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.98" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libflate" @@ -2567,6 +2604,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "openssl-probe" version = "0.1.4" @@ -3183,6 +3226,7 @@ dependencies = [ "rayon", "ruffle_core", "serde", + "sha2", "swf", "walkdir", ] @@ -3336,6 +3380,19 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "shlex" version = "0.1.1" @@ -3763,6 +3820,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +[[package]] +name = "typenum" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" + [[package]] name = "unicode-bidi" version = "0.3.5" diff --git a/scanner/Cargo.toml b/scanner/Cargo.toml index 96e65d830..3d1758494 100644 --- a/scanner/Cargo.toml +++ b/scanner/Cargo.toml @@ -17,4 +17,5 @@ indicatif = "0.16" path-slash = "0.1.4" swf = { path = "../swf" } rayon = "1.5.1" -crossbeam-channel = "0.5" \ No newline at end of file +crossbeam-channel = "0.5" +sha2 = "0.9.8" \ No newline at end of file diff --git a/scanner/src/execute.rs b/scanner/src/execute.rs index 98a08c280..1d11edd66 100644 --- a/scanner/src/execute.rs +++ b/scanner/src/execute.rs @@ -13,6 +13,7 @@ use ruffle_core::backend::video::NullVideoBackend; use ruffle_core::swf::{decompress_swf, parse_swf}; use ruffle_core::tag_utils::SwfMovie; use ruffle_core::Player; +use sha2::{Digest, Sha256}; use swf::{FileAttributes, Tag}; use std::path::Path; @@ -87,6 +88,7 @@ pub fn execute_report_main(execute_report_opt: ExecuteReportOpt) -> Result<(), s let mut file_result = FileResults { progress: Progress::Nothing, + hash: vec![], testing_time: start.elapsed().as_millis(), name, error: None, @@ -106,6 +108,10 @@ pub fn execute_report_main(execute_report_opt: ExecuteReportOpt) -> Result<(), s } }; + let mut hash = Sha256::new(); + hash.update(&data[..]); + + file_result.hash = hash.finalize().to_vec(); file_result.progress = Progress::Read; checkpoint(&mut file_result, &start, &mut writer)?; diff --git a/scanner/src/file_results.rs b/scanner/src/file_results.rs index a60a6fedf..65bda1cf8 100644 --- a/scanner/src/file_results.rs +++ b/scanner/src/file_results.rs @@ -2,7 +2,11 @@ //! //! The `FileResults` type in this module is used to report results of a scan. -use serde::{Deserialize, Serialize}; +use serde::de::{Error as DesError, Unexpected, Visitor}; +use serde::ser::Error as SerError; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; +use std::fmt::Write; #[derive(Serialize, Deserialize, Debug)] pub enum AvmType { @@ -28,8 +32,62 @@ pub enum Progress { #[derive(Serialize, Deserialize, Debug)] pub struct FileResults { pub name: String, + + #[serde(serialize_with = "into_hex", deserialize_with = "from_hex")] + pub hash: Vec, pub progress: Progress, pub testing_time: u128, pub error: Option, pub vm_type: Option, } + +/// Formats data as capital hex +fn into_hex(hash: &[u8], s: S) -> Result +where + S: Serializer, +{ + let mut out = String::with_capacity(2 * hash.len()); + for byte in hash { + write!(out, "{:02X}", byte).map_err(|e| SerError::custom(e.to_string()))?; + } + + s.serialize_str(&out) +} + +/// Parses hex strings into data +fn from_hex<'de, D>(d: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + struct HexVisitor(); + + impl Visitor<'_> for HexVisitor { + type Value = Vec; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "A string of hex digits with even length") + } + + fn visit_str(self, v: &str) -> Result + where + E: DesError, + { + let mut result = Vec::with_capacity(v.len() / 2); + + for i in (0..v.len()).step_by(2) { + result.push( + u8::from_str_radix( + v.get(i..i + 2) + .ok_or_else(|| DesError::invalid_length(v.len(), &self))?, + 16, + ) + .map_err(|_| DesError::invalid_value(Unexpected::Str(v), &self))?, + ); + } + + Ok(result) + } + } + + d.deserialize_str(HexVisitor()) +} diff --git a/scanner/src/scan.rs b/scanner/src/scan.rs index b9a2118d8..d9726aa4f 100644 --- a/scanner/src/scan.rs +++ b/scanner/src/scan.rs @@ -41,6 +41,7 @@ pub fn scan_file>(exec_path: P, file: DirEntry, name: String) -> let start = Instant::now(); let mut file_results = FileResults { name, + hash: vec![], progress: Progress::Nothing, testing_time: start.elapsed().as_millis(), error: None, @@ -109,6 +110,7 @@ pub fn scan_main(opt: ScanOpt) -> Result<(), std::io::Error> { writer.write_record(&[ "Filename", + "SHA256 Hash", "Progress", "Test Duration", "Error",