1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
use crate::algorithm::Algorithm; use crate::builder::Builder; use crate::checker::Checker; use crate::hash::Hash; use std::fmt; use std::error::Error; use hex; #[derive(Clone, Debug)] pub struct Integrity { pub hashes: Vec<Hash> } impl fmt::Display for Integrity { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.hashes.iter() .map(|h| h.to_string()) .collect::<Vec<String>>() .join(" ")) } } impl std::str::FromStr for Integrity { type Err = ParseIntegrityError; fn from_str(s: &str) -> Result<Integrity, Self::Err> { let hashes = String::from(s) .split_whitespace() .map(|x| x.parse()) .collect::<Result<Vec<Hash>, Self::Err>>()?; Ok(Integrity { hashes }) } } impl Integrity { pub fn from<B: AsRef<[u8]>>(data: B, algorithm: Algorithm) -> Integrity { Builder::new() .algorithm(algorithm) .chain(&data) .result() } pub fn concat(&self, other: Integrity) -> Self { let mut hashes = [self.hashes.clone(), other.hashes.clone()].concat(); hashes.sort_unstable(); hashes.dedup(); Integrity { hashes } } pub fn check<B: AsRef<[u8]>>(self, data: B) -> Option<Algorithm> { let mut checker = Checker::new(self); checker.input(&data); checker.result() } pub fn to_hex(&self) -> (Algorithm, String) { let hash = self.hashes.get(0).unwrap(); ( hash.algorithm.clone(), hex::encode(base64::decode(&hash.digest).unwrap()) ) } } #[derive(Debug)] pub struct ParseIntegrityError {} impl fmt::Display for ParseIntegrityError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "failed to parse Subresource Integrity string") } } impl Error for ParseIntegrityError {} #[cfg(test)] mod tests { use super::Hash; use super::Algorithm; use super::Integrity; #[test] fn parse() { let sri: Integrity = "sha1-deadbeef=".parse().unwrap(); assert_eq!( sri.hashes.get(0).unwrap(), &Hash { algorithm: Algorithm::Sha1, digest: String::from("deadbeef=") } ) } #[test] fn to_hex() { let sri = Integrity::from(b"hello world", Algorithm::Sha1); assert_eq!( sri.to_hex(), ( Algorithm::Sha1, String::from("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed") ) ) } }