Implement Payload structured information

This commit is contained in:
Till Wegmueller 2020-06-04 19:03:51 +02:00
parent f9ede380b1
commit c42812c4bd
4 changed files with 159 additions and 51 deletions

View file

@ -11,6 +11,8 @@ use std::io::BufReader;
use failure::Error; use failure::Error;
use crate::payload::Payload; use crate::payload::Payload;
use std::clone::Clone; use std::clone::Clone;
use crate::digest::Digest;
use std::str::FromStr;
trait FacetedAction { trait FacetedAction {
// Add a facet to the action if the facet is already present the function returns false. // Add a facet to the action if the facet is already present the function returns false.
@ -70,7 +72,7 @@ impl FacetedAction for Dir {
} }
} }
#[derive(Debug)] #[derive(Debug, Default)]
pub struct File { pub struct File {
pub payload: Payload, pub payload: Payload,
pub path: String, pub path: String,
@ -147,6 +149,10 @@ enum ActionKind {
Unknown{action: String}, Unknown{action: String},
} }
impl Default for ActionKind {
fn default() -> Self { ActionKind::Unknown {action: String::new()} }
}
//TODO Multierror and no failure for these cases //TODO Multierror and no failure for these cases
#[derive(Debug, Fail)] #[derive(Debug, Fail)]
pub enum ManifestError { pub enum ManifestError {
@ -295,9 +301,9 @@ fn parse_file_action(line: String, line_nr: usize) -> Result<File, Error> {
for (pat, idx) in regex_set.matches(line.trim_start()).into_iter().map(|match_idx| (&regex_set.patterns()[match_idx], match_idx)) { for (pat, idx) in regex_set.matches(line.trim_start()).into_iter().map(|match_idx| (&regex_set.patterns()[match_idx], match_idx)) {
let regex = Regex::new(&pat)?; let regex = Regex::new(&pat)?;
for cap in regex.captures_iter(line.trim_start()) { for cap in regex.captures_iter(line.clone().trim_start()) {
if idx == 0 { if idx == 0 {
act.payload = String::from(&cap[1]); act.payload.primary_identifier = Digest::from_str(&cap[1])?;
continue; continue;
} }
@ -325,7 +331,7 @@ fn parse_file_action(line: String, line_nr: usize) -> Result<File, Error> {
let key_val_string = clean_string_value(&cap[full_cap_idx]); let key_val_string = clean_string_value(&cap[full_cap_idx]);
if key_val_string.contains("facet.") { if key_val_string.contains("facet.") {
match add_facet_to_action(&mut act, key_val_string, line, line_nr) { match add_facet_to_action(&mut act, key_val_string, line.clone(), line_nr) {
Ok(_) => continue, Ok(_) => continue,
Err(e) => return Err(e)?, Err(e) => return Err(e)?,
} }
@ -359,7 +365,7 @@ fn parse_dir_action(line: String, line_nr: usize) -> Result<Dir, Error> {
for pat in regex_set.matches(line.trim_start()).into_iter().map(|match_idx| &regex_set.patterns()[match_idx]) { for pat in regex_set.matches(line.trim_start()).into_iter().map(|match_idx| &regex_set.patterns()[match_idx]) {
let regex = Regex::new(&pat)?; let regex = Regex::new(&pat)?;
for cap in regex.captures_iter(line.trim_start()) { for cap in regex.captures_iter(line.clone().trim_start()) {
let full_cap_idx = 0; let full_cap_idx = 0;
let key_cap_idx = 1; let key_cap_idx = 1;
let val_cap_idx = 2; let val_cap_idx = 2;
@ -375,7 +381,7 @@ fn parse_dir_action(line: String, line_nr: usize) -> Result<Dir, Error> {
_ => { _ => {
let key_val_string = clean_string_value(&cap[full_cap_idx]); let key_val_string = clean_string_value(&cap[full_cap_idx]);
if key_val_string.contains("facet.") { if key_val_string.contains("facet.") {
match add_facet_to_action(&mut act, key_val_string, line, line_nr) { match add_facet_to_action(&mut act, key_val_string, line.clone(), line_nr) {
Ok(_) => continue, Ok(_) => continue,
Err(e) => return Err(e)?, Err(e) => return Err(e)?,
} }

View file

@ -3,6 +3,8 @@
// MPL was not distributed with this file, You can // MPL was not distributed with this file, You can
// obtain one at https://mozilla.org/MPL/2.0/. // obtain one at https://mozilla.org/MPL/2.0/.
use std::str::FromStr;
#[derive(Debug)] #[derive(Debug)]
pub enum DigestAlgorithm { pub enum DigestAlgorithm {
SHA1, //Default, sadly SHA1, //Default, sadly
@ -12,6 +14,7 @@ pub enum DigestAlgorithm {
SHA3256, // Sha3 version of sha256t SHA3256, // Sha3 version of sha256t
SHA3512Half, // Sha3 version of sha512t_256 SHA3512Half, // Sha3 version of sha512t_256
SHA3512, // Sha3 version of sha512t SHA3512, // Sha3 version of sha512t
Unknown,
} }
impl Default for DigestAlgorithm { impl Default for DigestAlgorithm {
@ -23,45 +26,62 @@ pub enum DigestSource {
GzipCompressed, GzipCompressed,
GNUElf, GNUElf,
GNUElfUnsigned, GNUElfUnsigned,
UncompressedFile UncompressedFile,
Unknown,
PrimaryPayloadHash,
} }
impl Default for DigestSource { impl Default for DigestSource {
fn default() -> Self { DigestSource::UncompressedFile } fn default() -> Self { DigestSource::PrimaryPayloadHash }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Digest { pub struct Digest {
hash: String, pub hash: String,
algorithm: DigestAlgorithm, pub algorithm: DigestAlgorithm,
source: DigestSource, pub source: DigestSource,
} }
impl FromStr for Digest { impl FromStr for Digest {
type Err = DigestError;
fn from_str(s: &str) -> Result<Self, failure::Error> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let str = String::from(s);
if !s.contains(":") { if !s.contains(":") {
Ok(Digest{ return Ok(Digest{
hash: String::from(s), hash: String::from(s),
algorithm: DigestAlgorithm::SHA1, algorithm: DigestAlgorithm::SHA1,
source: "primary".to_string(), source: DigestSource::PrimaryPayloadHash,
}) });
} }
let parts = String::from(s).split(':').collect(); let parts: Vec<&str> = str.split(':').collect();
if parts.len() < 3 { if parts.len() < 3 {
Err(DigestError::InvalidDigestFormat{ return Err(DigestError::InvalidDigestFormat{
digest: String::from(s), digest: String::from(s),
details: "cannot split into 3 parts".to_string(), details: "cannot split into 3 parts".to_string(),
}); });
} }
Ok(Digest{ Ok(Digest{
source: String::from(&parts[0]), source: match parts[0] {
algorithm: String::from(&parts[1]), "file" => DigestSource::UncompressedFile,
hash: String::from(&parts[2]), "gzip" => DigestSource::GzipCompressed,
"gelf" => DigestSource::GNUElf,
"gelf.unsigned" => DigestSource::GNUElfUnsigned,
_ => DigestSource::Unknown,
},
algorithm: match parts[1] {
"sha1" => DigestAlgorithm::SHA1,
"sha256t" => DigestAlgorithm::SHA256,
"sha512t_256" => DigestAlgorithm::SHA512Half,
"sha512t" => DigestAlgorithm::SHA512,
"sha3256t" => DigestAlgorithm::SHA3256,
"sha3512t_256" => DigestAlgorithm::SHA3512Half,
"sha3512t" => DigestAlgorithm::SHA3512,
_ => DigestAlgorithm::Unknown,
},
hash: String::from(parts[2]),
}) })
} }
} }

View file

@ -15,6 +15,9 @@ mod tests {
use crate::actions::{Manifest, Property, Dir, File}; use crate::actions::{Manifest, Property, Dir, File};
use crate::actions::{parse_manifest_string, Attr}; use crate::actions::{parse_manifest_string, Attr};
use std::collections::HashSet; use std::collections::HashSet;
use crate::payload::Payload;
use crate::digest::Digest;
use std::str::FromStr;
#[test] #[test]
fn parse_attributes() { fn parse_attributes() {
@ -232,7 +235,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
let test_results = vec![ let test_results = vec![
File{ File{
payload: "4b76e83bb4bb7c87176b72ef805fe78ecae60d2c".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("4b76e83bb4bb7c87176b72ef805fe78ecae60d2c"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "555".to_string(), mode: "555".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -257,7 +266,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "72e0496a02e72e7380b0b62cdc8410108302876f".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("72e0496a02e72e7380b0b62cdc8410108302876f"),
..Digest::default()
},
..Payload::default()
},
group: "sys".to_string(), group: "sys".to_string(),
mode: "0444".to_string(), mode: "0444".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -285,7 +300,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "95de71d58b37f9f74bede0e91bc381d6059fc2d7".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("95de71d58b37f9f74bede0e91bc381d6059fc2d7"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0444".to_string(), mode: "0444".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -310,7 +331,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "7dd71afcfb14e105e80b0c0d7fce370a28a41f0a".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("7dd71afcfb14e105e80b0c0d7fce370a28a41f0a"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0444".to_string(), mode: "0444".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -335,7 +362,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "cbf596ddb3433a8e0d325f3c188bec9c1bb746b3".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("cbf596ddb3433a8e0d325f3c188bec9c1bb746b3"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -361,7 +394,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "da38e2a0dded838afbe0eade6cb837ac30fd8046".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("da38e2a0dded838afbe0eade6cb837ac30fd8046"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -387,7 +426,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "407cb51b397ba4ad90a2246640a81af18e2e917a".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("407cb51b397ba4ad90a2246640a81af18e2e917a"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -413,7 +458,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "19ec7fb71e7f00d7e8a1cfc1013490f0cfee572b".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("19ec7fb71e7f00d7e8a1cfc1013490f0cfee572b"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -439,7 +490,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "e39dbc36680b717ec902fadc805a302f1cf62245".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("e39dbc36680b717ec902fadc805a302f1cf62245"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -465,7 +522,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "d143ca7a6aac765d28724af54d969a4bd2202383".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("d143ca7a6aac765d28724af54d969a4bd2202383"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -491,7 +554,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "379c1e2a2a5ffb8c91a07328d4c9be2bc58799fd".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("379c1e2a2a5ffb8c91a07328d4c9be2bc58799fd"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -517,7 +586,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "cc2fcdb4605dcac23d59f667889ccbdfdc6e3668".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("cc2fcdb4605dcac23d59f667889ccbdfdc6e3668"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -543,7 +618,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "e10f2d42c9e581901d810928d01a3bf8f3372838".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("e10f2d42c9e581901d810928d01a3bf8f3372838"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0644".to_string(), mode: "0644".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -569,7 +650,13 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
], ],
..File::default() ..File::default()
}, File{ }, File{
payload: "6d5f820bb1d67594c7b757c79ef6f9242df49e98".to_string(), payload: Payload{
primary_identifier: Digest {
hash: String::from("6d5f820bb1d67594c7b757c79ef6f9242df49e98"),
..Digest::default()
},
..Payload::default()
},
group: "bin".to_string(), group: "bin".to_string(),
mode: "0555".to_string(), mode: "0555".to_string(),
owner: "root".to_string(), owner: "root".to_string(),
@ -612,24 +699,20 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7
]; ];
let mut manifest = Manifest::new(); let mut manifest = Manifest::new();
match parse_manifest_string(manifest_string) { let res = parse_manifest_string(manifest_string);
Ok(m) => manifest = m, assert!(res.is_ok(), "error during Manifest parsing: {:?}", res);
Err(e) => { let manifest = res.unwrap();
println!("{}", e);
assert!(false, "caught error");
}
};
assert_eq!(manifest.files.len(), test_results.len()); assert_eq!(manifest.files.len(), test_results.len());
for (pos, file) in manifest.files.iter().enumerate() { for (pos, file) in manifest.files.iter().enumerate() {
println!("action: {}", file.payload); println!("action: {}", file.payload.primary_identifier.hash);
assert_eq!(file.group, test_results[pos].group); assert_eq!(file.group, test_results[pos].group);
assert_eq!(file.mode, test_results[pos].mode); assert_eq!(file.mode, test_results[pos].mode);
assert_eq!(file.owner, test_results[pos].owner); assert_eq!(file.owner, test_results[pos].owner);
assert_eq!(file.path, test_results[pos].path); assert_eq!(file.path, test_results[pos].path);
assert_eq!(file.preserve, test_results[pos].preserve); assert_eq!(file.preserve, test_results[pos].preserve);
assert_eq!(file.payload, test_results[pos].payload); assert_eq!(file.payload.primary_identifier.hash, test_results[pos].payload.primary_identifier.hash);
for (vpos, val) in file.properties.iter().enumerate() { for (vpos, val) in file.properties.iter().enumerate() {
assert_eq!(val.key, test_results[pos].properties[vpos].key); assert_eq!(val.key, test_results[pos].properties[vpos].key);

View file

@ -4,7 +4,6 @@
// obtain one at https://mozilla.org/MPL/2.0/. // obtain one at https://mozilla.org/MPL/2.0/.
use crate::digest::Digest; use crate::digest::Digest;
use std::str::FromStr;
#[derive(Debug)] #[derive(Debug)]
pub enum PayloadCompressionAlgorithm { pub enum PayloadCompressionAlgorithm {
@ -42,9 +41,9 @@ impl Default for PayloadArchitecture {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Payload { pub struct Payload {
primary_identifier: Digest, pub primary_identifier: Digest,
additional_identifiers: Vec<Digest>, pub additional_identifiers: Vec<Digest>,
compression_algorithm: PayloadCompressionAlgorithm, pub compression_algorithm: PayloadCompressionAlgorithm,
bitness: PayloadBits, pub bitness: PayloadBits,
architecture: PayloadArchitecture, pub architecture: PayloadArchitecture,
} }