use std::io::BufReader;
use exif;
use exif::{Error, Tag, Value};
use errors::ArmorlibError;
use scan_module::ScanModule;
use scan_object::ScanObject;
use finding::{Finding, Severity};
pub struct ExifScanModule;
impl ScanModule for ExifScanModule {
fn scan(&self, scan_object: &ScanObject) -> Result<Vec<Finding>, ArmorlibError> {
if scan_object.get_metadata("filtype/tiff").is_err()
&& scan_object.get_metadata("filetype/jpg").is_err()
{
return Ok(vec![]);
}
let reader = match exif::Reader::new(&mut BufReader::new(&*scan_object.binary_object.data))
{
Ok(reader) => reader,
Err(error) => match error {
Error::NotFound("No Exif data found") => return Ok(vec![]),
_ => return Err(ArmorlibError::ParseError(format!("{:?}", error))),
},
};
let fields = reader.fields();
let mut findings: Vec<Finding> = Vec::new();
for field in fields {
let tag: &Tag = &field.tag;
let value: &Value = &field.value;
if tag.default_value().is_some() {
if format!("{}", value.display_as(*tag))
== format!("{}", tag.default_value().unwrap().display_as(*tag))
{
continue; }
}
let description = match tag.description() {
Some(description) => description,
None => "<unknown tag>",
};
let level = match tag.number() {
271 | 272 | 305 => Severity::Danger(format!( "'{}' tag can be used to identify origin device",
description
)),
306 => Severity::Danger(format!( "'{}' tag can be used to track creator",
description
)),
315 | 42032 | 42033 | 42034 => {
Severity::Danger(format!( "'{}' tag can be used to identify creator",
description
))
}
36867 | 36868 => Severity::Danger(format!( "'{}' tag can be used to track creator",
description
)),
36880 | 36881 | 36882 => Severity::Danger(format!( "'{}' tag can be used to determine creator's region",
description
)),
37888 | 37889 | 37890 | 37891 => {
Severity::Danger(format!( "'{}' tag can be used to determine creator's general location",
description
))
}
41492 | 0...31 => Severity::Danger(format!( "'{}' tag can be used to determine creator's location",
description
)),
_ => Severity::Warn(format!( "'{}' tag could reveal private information",
description
)),
};
let finding = Finding {
title: format!("'{}' EXIF metadata detected", description),
id: String::from("EXIF_METADATA"),
description: format!(
"The '{}' tag ({}) was found in the EXIF metadata: {}",
description,
tag.number(),
value.display_as(*tag)
),
severity: level,
};
findings.push(finding);
}
Ok(findings)
}
fn info(&self) -> (&'static str, &'static str) {
("exif", "detects dangerous EXIF metadata")
}
fn required_preprocessors(&self) -> Vec<&'static str> {
vec!["filetype"]
}
fn subscribed_filetypes(&self) -> Option<Vec<&'static str>> {
Some(vec!["tiff", "jpg"])
}
}