Compare commits

...

2 commits

Author SHA1 Message Date
81347a7658
mime_extension_lookup takes essence_str directly, videos aliases to video
All checks were successful
continuous-integration/drone/push Build is passing
2021-05-08 00:32:44 +10:00
3b3a64c9ea
remove drone build status from readme 2021-05-07 02:53:25 +10:00
7 changed files with 23 additions and 25 deletions

View file

@ -5,6 +5,8 @@ Dates are given in YYYY-MM-DD format.
### v0.3.1 (2021-xx-yy) ### v0.3.1 (2021-xx-yy)
#### Features #### Features
- Added JSON output support via `-o json` - Added JSON output support via `-o json`
#### Other
- `videos` is now an alias for `video`
### v0.3.0 (2021-04-28) ### v0.3.0 (2021-04-28)
#### Features #### Features

View file

@ -11,9 +11,7 @@
](https://crates.io/crates/fif) ](https://crates.io/crates/fif)
[![License](https://img.shields.io/crates/l/fif.svg?style=flat-square) [![License](https://img.shields.io/crates/l/fif.svg?style=flat-square)
](https://gitlab.com/Lynnesbian/fif/-/blob/master/LICENSE) ](https://gitlab.com/Lynnesbian/fif/-/blob/master/LICENSE)
[![Drone build status](https://img.shields.io/drone/build/lynnesbian/fif?logo=drone&server=https%3A%2F%2Fdrone.bune.city&style=flat-square) [![Build status](https://img.shields.io/gitlab/pipeline/Lynnesbian/fif/master?logo=gitlab&style=flat-square)
](https://drone.bune.city/lynnesbian/fif)
[![GitLab build status](https://img.shields.io/gitlab/pipeline/Lynnesbian/fif/master?logo=gitlab&style=flat-square)
](https://gitlab.com/Lynnesbian/fif/-/pipelines/latest) ](https://gitlab.com/Lynnesbian/fif/-/pipelines/latest)
[![Unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg?style=flat-square) [![Unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg?style=flat-square)
](https://github.com/rust-secure-code/safety-dance/) ](https://github.com/rust-secure-code/safety-dance/)

View file

@ -38,7 +38,7 @@ impl<'a> serde::Serialize for Findings<'a> {
impl<'a> Findings<'a> { impl<'a> Findings<'a> {
pub fn recommended_extension(&self) -> Option<String> { pub fn recommended_extension(&self) -> Option<String> {
mime_extension_lookup(self.mime.clone()).map(|extensions| extensions[0].clone()) mime_extension_lookup(self.mime.essence_str().into()).map(|extensions| extensions[0].clone())
} }
} }

View file

@ -61,20 +61,17 @@ pub fn mime_type<T: MimeDb>(db: &T, path: &Path) -> io::Result<Option<Mime>> {
Ok(db.get_type(&buffer)) Ok(db.get_type(&buffer))
} }
// TODO: avoid cloning mime if possible, although i don't really see how it would be - maybe instead of passing the mime
// object, pass a hash of it?
cached! { cached! {
MIMEXT; MIMEXT;
fn mime_extension_lookup(mime: Mime) -> Option<Vec<String>> = { fn mime_extension_lookup(essence: String) -> Option<Vec<String>> = {
// Returns a list of known extensions for this mime type, if any. // Returns a list of known extensions for this mime type, if any.
// ↑ this is supposed to be a doc comment, but the cached! macro doesn't support that... maybe i should switch to // This function uses the [Mime]'s "essence" rather than the [Mime] itself - mime_guess::get_mime_extensions ignores
// the derive macro // the type suffix, treating "image/svg+xml" as "image/svg", and thus fails to find any extensions. Passing the
// essence_str (which includes the suffix) fixes this.
// ↑ this is supposed to be a doc comment, but the cached! macro doesn't support that... i would switch to the
// proc_macro version of cached, but it has a huge number of deps :c
// match on the mime's `essence_str` rather than the mime itself - mime_guess::get_mime_extensions ignores the type let essence = essence.as_str();
// suffix, treating "image/svg+xml" as "image/svg", and thus fails to find any extensions. passing the essence_str
// (which includes the suffix) fixes this.
let essence = mime.essence_str();
let mut exts = mime_guess::get_mime_extensions_str(essence); let mut exts = mime_guess::get_mime_extensions_str(essence);
if exts.is_none() { if exts.is_none() {
// no matches :c // no matches :c
@ -95,13 +92,13 @@ cached! {
Some(exts) => { Some(exts) => {
let possible_exts: Vec<String> = exts.iter().map(|e| String::from(*e)).collect(); let possible_exts: Vec<String> = exts.iter().map(|e| String::from(*e)).collect();
Some(if mime == mime_guess::mime::IMAGE_JPEG { Some(if essence == mime_guess::mime::IMAGE_JPEG.essence_str() {
// possible_exts starts with "jpe", because it's alphabetically before "jpeg" and "jpg". however, jpg/jpeg are // possible_exts starts with "jpe", because it's alphabetically before "jpeg" and "jpg". however, jpg/jpeg are
// far more common than jpe, so it makes sense to suggest one of those rather than jpe. to do this, we can // far more common than jpe, so it makes sense to suggest one of those rather than jpe. to do this, we can
// add "jpg" to the start of the possible_exts list, ensuring that it will be the extension suggested by fif. // add "jpg" to the start of the possible_exts list, ensuring that it will be the extension suggested by fif.
[vec![String::from("jpg")], possible_exts].concat() [vec![String::from("jpg")], possible_exts].concat()
} else if mime == mime_guess::mime::TEXT_XML || mime == Mime::from_str("application/xml").unwrap() { } else if essence == mime_guess::mime::TEXT_XML.essence_str() || essence == "application/xml" {
// a somewhat similar case arises with XML files - the first suggested extension is "asa", when it should // a somewhat similar case arises with XML files - the first suggested extension is "asa", when it should
// (in my opinion) be "xml". // (in my opinion) be "xml".
// there's also another problem: SVG files can easily be misidentified as XML files, because they usually // there's also another problem: SVG files can easily be misidentified as XML files, because they usually
@ -114,15 +111,15 @@ cached! {
// extension is classes as application/*+xml, consider it OK // extension is classes as application/*+xml, consider it OK
[vec![String::from("xml"), String::from("svg")], possible_exts].concat() [vec![String::from("xml"), String::from("svg")], possible_exts].concat()
} else if mime == Mime::from_str("application/msword").unwrap() { } else if essence == "application/msword" {
// classic office files considered harmful // classic office files considered harmful
vec![String::from("doc"), String::from("xls"), String::from("ppt")] vec![String::from("doc"), String::from("xls"), String::from("ppt")]
} else if mime == Mime::from_str("application/zip").unwrap() { } else if essence == "application/zip" {
// neither xdg-mime nor infer seem to be able to detect office XML files properly... // neither xdg-mime nor infer seem to be able to detect office XML files properly...
[vec![String::from("zip"), String::from("docx"), String::from("xlsx"), String::from("pptx")], possible_exts].concat() [vec![String::from("zip"), String::from("docx"), String::from("xlsx"), String::from("pptx")], possible_exts].concat()
} else if mime == Mime::from_str("application/x-ms-dos-executable").unwrap() { } else if essence == "application/x-ms-dos-executable" {
// both .dll and .exe files are given the same mime type... but you definitely don't want to rename one to the // both .dll and .exe files are given the same mime type... but you definitely don't want to rename one to the
// other! // other!
[vec![String::from("dll"), String::from("exe")], possible_exts].concat() [vec![String::from("dll"), String::from("exe")], possible_exts].concat()

View file

@ -254,7 +254,7 @@ fn scan_file(entry: &DirEntry) -> Result<Findings, ScanError> {
let result = result.unwrap(); let result = result.unwrap();
// set of known extensions for the given mimetype // set of known extensions for the given mimetype
let known_exts = inspectors::mime_extension_lookup(result.clone()); let known_exts = inspectors::mime_extension_lookup(result.essence_str().into());
// file extension for this particular file // file extension for this particular file
let entry_ext = extension_from_path(entry.path()); let entry_ext = extension_from_path(entry.path());

View file

@ -234,6 +234,7 @@ pub enum ExtensionSet {
/// Extensions used for audio file formats, such as `mp3`, `ogg`, `flac`, etc. /// Extensions used for audio file formats, such as `mp3`, `ogg`, `flac`, etc.
Audio, Audio,
/// Extensions used for video file formats, such as `mkv`, `mp4`, `mov`, etc. /// Extensions used for video file formats, such as `mkv`, `mp4`, `mov`, etc.
#[clap(alias = "videos")]
Video, Video,
/// Extensions used for media file formats. This acts as a combination of the [Images](ExtensionSet::Images), /// Extensions used for media file formats. This acts as a combination of the [Images](ExtensionSet::Images),
/// [Audio](ExtensionSet::Audio) and [Videos](ExtensionSet::Videos) variants. /// [Audio](ExtensionSet::Audio) and [Videos](ExtensionSet::Videos) variants.

View file

@ -67,14 +67,14 @@ fn detect_type() {
/// Ensure that `mime_extension_lookup` works as expected, and that the set of extensions for JPEG, PNG, PDF, and ZIP /// Ensure that `mime_extension_lookup` works as expected, and that the set of extensions for JPEG, PNG, PDF, and ZIP
/// contain "jpg", "png", "pdf", and "zip", respectively. /// contain "jpg", "png", "pdf", and "zip", respectively.
fn recommend_ext() { fn recommend_ext() {
assert!(mime_extension_lookup(IMAGE_JPEG) assert!(mime_extension_lookup(IMAGE_JPEG.essence_str().into())
.unwrap() .unwrap()
.contains(&String::from("jpg"))); .contains(&String::from("jpg")));
assert!(mime_extension_lookup(IMAGE_PNG).unwrap().contains(&String::from("png"))); assert!(mime_extension_lookup(IMAGE_PNG.essence_str().into()).unwrap().contains(&String::from("png")));
assert!(mime_extension_lookup(APPLICATION_PDF) assert!(mime_extension_lookup(APPLICATION_PDF.essence_str().into())
.unwrap() .unwrap()
.contains(&String::from("pdf"))); .contains(&String::from("pdf")));
assert!(mime_extension_lookup(application_zip()) assert!(mime_extension_lookup(application_zip().essence_str().into())
.unwrap() .unwrap()
.contains(&String::from("zip"))); .contains(&String::from("zip")));
} }
@ -142,7 +142,7 @@ fn simple_directory() {
// check if the recommended extension for this file is in the list of known extensions for its mimetype - for // check if the recommended extension for this file is in the list of known extensions for its mimetype - for
// example, if the file is determined to be an IMAGE_PNG, its recommended extension should be one of the extensions // example, if the file is determined to be an IMAGE_PNG, its recommended extension should be one of the extensions
// returned by `mime_extension_lookup(IMAGE_PNG)`. // returned by `mime_extension_lookup(IMAGE_PNG)`.
assert!(mime_extension_lookup(result.mime.clone()) assert!(mime_extension_lookup(result.mime.essence_str().into())
.unwrap() .unwrap()
.contains(&result.recommended_extension().unwrap())); .contains(&result.recommended_extension().unwrap()));