# It is not intended for manual editing.
version = 3
-[[package]]
-name = "aho-corasick"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
-dependencies = [
- "memchr",
-]
-
[[package]]
name = "ansi_term"
-version = "0.11.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
"winapi",
]
-[[package]]
-name = "autocfg"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
-
[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
[[package]]
name = "cfg-if"
version = "1.0.0"
[[package]]
name = "clap"
-version = "2.33.3"
+version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
[[package]]
name = "crossbeam-channel"
-version = "0.4.4"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
+checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
+ "cfg-if",
"crossbeam-utils",
- "maybe-uninit",
]
[[package]]
name = "crossbeam-utils"
-version = "0.7.2"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
+checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
- "autocfg",
- "cfg-if 0.1.10",
+ "cfg-if",
"lazy_static",
]
"clipboard",
"crossbeam-channel",
"hex",
- "regex",
"rust-crypto",
"structopt",
"termcolor",
[[package]]
name = "heck"
-version = "0.3.2"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
-version = "0.1.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "libc"
-version = "0.2.91"
+version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "log"
-version = "0.4.14"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
]
[[package]]
"libc",
]
-[[package]]
-name = "maybe-uninit"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
-
-[[package]]
-name = "memchr"
-version = "2.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
-
[[package]]
name = "objc"
version = "0.2.7"
[[package]]
name = "proc-macro2"
-version = "1.0.24"
+version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
dependencies = [
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.9"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
"rand_core 0.3.1",
]
-[[package]]
-name = "regex"
-version = "1.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
-
[[package]]
name = "rust-crypto"
version = "0.2.36"
[[package]]
name = "structopt"
-version = "0.3.21"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c"
+checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
dependencies = [
"clap",
"lazy_static",
[[package]]
name = "structopt-derive"
-version = "0.4.14"
+version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
[[package]]
name = "syn"
-version = "1.0.65"
+version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
+checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
dependencies = [
"proc-macro2",
"quote",
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "termcolor"
-version = "1.1.2"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
]
[[package]]
-name = "unicode-segmentation"
-version = "1.7.1"
+name = "unicode-ident"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
+checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
[[package]]
-name = "unicode-width"
-version = "0.1.8"
+name = "unicode-segmentation"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
-name = "unicode-xid"
-version = "0.2.1"
+name = "unicode-width"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "vec_map"
[[package]]
name = "version_check"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
structopt = "0.3.4"
hex = "0.4.0"
rust-crypto = "0.2.36"
-crossbeam-channel = "0.4.0"
-termcolor = "1.0.12"
-regex = "1"
+crossbeam-channel = "0.5"
+termcolor = "1.1"
[dependencies.clipboard]
version = "0.5.0"
}
/// The method by which one or more hashes were supplied to verify the calculated digest
+#[derive(Debug, PartialEq)]
pub enum VerificationSource {
CommandArgument,
Clipboard,
}
/// A possible hash to match against. The algorithm is assumed.
+#[derive(Debug, PartialEq)]
pub struct CandidateHash {
bytes: Vec<u8>,
filename: Option<String>,
/// A list of candidate hashes that our input could potentially match. At this point it is
/// assumed that we will be verifying a digest of a particular, single algorithm.
+#[derive(Debug, PartialEq)]
pub struct CandidateHashes {
alg: Algorithm,
hashes: Vec<CandidateHash>,
};
#[cfg(feature = "paste")]
use clipboard::{ClipboardContext, ClipboardProvider};
-use regex::Regex;
use std::fs::File;
use std::io;
use std::io::prelude::*;
))
}
+fn try_parse_hash(s: &str) -> Option<(Algorithm, Vec<u8>)> {
+ let bytes = match hex::decode(s.trim()) {
+ Ok(bytes) => bytes,
+ _ => return None,
+ };
+ let alg = match Algorithm::from_len(bytes.len()) {
+ Ok(alg) => alg,
+ _ => return None,
+ };
+ Some((alg, bytes))
+}
+
fn read_raw_candidate_from_file(line: &str, path: &PathBuf) -> Option<CandidateHashes> {
- // It is a little sad to use a dynamic regex in an otherwise nice Rust program
- // These deserve to be replaced with a good old fashioned static parser
- // But let's be honest: the impact is negligible
- let re = Regex::new(r"^([[:xdigit:]]{32}|[[:xdigit:]]{40}|[[:xdigit:]]{64})$").unwrap();
- if re.is_match(line) {
- // These should both always succeed due to the matching
- let bytes = match hex::decode(line) {
- Ok(bytes) => bytes,
- _ => return None,
- };
- let alg = match Algorithm::from_len(bytes.len()) {
- Ok(alg) => alg,
- _ => return None,
- };
- return Some(CandidateHashes {
- alg,
- source: VerificationSource::RawFile(path.clone()),
- hashes: vec![CandidateHash {
- bytes,
- filename: None,
- }],
- });
- }
- None
+ let (alg, bytes) = try_parse_hash(line)?;
+ Some(CandidateHashes {
+ alg,
+ source: VerificationSource::RawFile(path.clone()),
+ hashes: vec![CandidateHash {
+ bytes,
+ filename: None,
+ }],
+ })
}
-fn read_coreutils_digests_from_file<I>(lines: I, path: &PathBuf) -> Option<CandidateHashes>
+fn read_coreutils_digests_from_file<I, S>(lines: I, path: &PathBuf) -> Option<CandidateHashes>
where
- I: Iterator<Item = io::Result<String>>,
+ I: Iterator<Item = io::Result<S>>,
+ S: AsRef<str>,
{
- let re = Regex::new(
- r"^(?P<hash>([[:xdigit:]]{32}|[[:xdigit:]]{40}|[[:xdigit:]]{64})) .(?P<filename>.+)$",
- )
- .unwrap();
-
let mut hashes = vec![];
let mut alg: Option<Algorithm> = None;
for l in lines {
if let Ok(l) = l {
- let l = l.trim();
+ let l = l.as_ref().trim();
// Allow (ignore) blank lines
if l.is_empty() {
continue;
}
- // If we can capture a valid line, use it
- if let Some(captures) = re.captures(&l) {
- let hash = &captures["hash"];
- let filename = &captures["filename"];
- // Decode the hex and algorithm for this line
- let line_bytes = match hex::decode(hash) {
- Ok(bytes) => bytes,
- _ => return None,
- };
- let line_alg = match Algorithm::from_len(line_bytes.len()) {
- Ok(alg) => alg,
- _ => return None,
- };
- if alg.is_some() && alg != Some(line_alg) {
- // Different algorithms in the same digest file are not supported
+ // Expected format
+ // <valid-hash><space><space-or-*><filename>
+ let (line_alg, bytes, filename) = match l
+ .find(' ')
+ .and_then(|space_pos| (l.get(0..space_pos)).zip(l.get(space_pos + 2..)))
+ .and_then(|(maybe_hash, filename)| {
+ try_parse_hash(maybe_hash).map(|(alg, bytes)| (alg, bytes, filename))
+ }) {
+ Some(t) => t,
+ None => {
+ // if we have a line with content we cannot parse, this is an error
return None;
- } else {
- // If we are the first line, we define the overall algorithm
- alg = Some(line_alg);
}
- // So far so good - create an entry for this line
- hashes.push(CandidateHash {
- bytes: line_bytes,
- filename: Some(filename.to_owned()),
- });
- } else {
- // But if we have a line with content we cannot parse, this is an error
+ };
+ if alg.is_some() && alg != Some(line_alg) {
+ // Different algorithms in the same digest file are not supported
return None;
+ } else {
+ // If we are the first line, we define the overall algorithm
+ alg = Some(line_alg);
}
+ // So far so good - create an entry for this line
+ hashes.push(CandidateHash {
+ bytes,
+ filename: Some(filename.to_owned()),
+ });
}
}
#[cfg(test)]
mod tests {
+ use std::path::Path;
+
use super::*;
#[test]
assert!(read_raw_candidate_from_file(*i, &example_path).is_none());
}
}
+
+ #[test]
+ fn test_read_shasums() {
+ let shasums = "4b91f7a387a6edd4a7c0afb2897f1ca968c9695b *cp
+ 75eb7420a9f5a260b04a3e8ad51e50f2838a17fc lel.txt
+
+ fe6c26d485a3573a1cb0ad0682f5105325a1905f shasums";
+ let lines = shasums.lines().map(|l| std::io::Result::Ok(l));
+ let path = Path::new("SHASUMS").to_owned();
+ let candidates = read_coreutils_digests_from_file(lines, &path);
+
+ assert_eq!(
+ candidates,
+ Some(CandidateHashes {
+ alg: Algorithm::Sha1,
+ hashes: vec![
+ CandidateHash {
+ bytes: hex::decode("4b91f7a387a6edd4a7c0afb2897f1ca968c9695b").unwrap(),
+ filename: Some("cp".to_owned()),
+ },
+ CandidateHash {
+ bytes: hex::decode("75eb7420a9f5a260b04a3e8ad51e50f2838a17fc").unwrap(),
+ filename: Some("lel.txt".to_owned()),
+ },
+ CandidateHash {
+ bytes: hex::decode("fe6c26d485a3573a1cb0ad0682f5105325a1905f").unwrap(),
+ filename: Some("shasums".to_owned()),
+ }
+ ],
+ source: VerificationSource::DigestsFile(path),
+ })
+ );
+ }
}