Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for base64-encoded hash values to 'get_file_hash' #1339

Merged
merged 4 commits into from
Feb 20, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 78 additions & 8 deletions components/templates/src/global_fns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock};
use std::{fs, io, result};

use base64::encode as encode_b64;
use sha2::{Digest, Sha256, Sha384, Sha512};
use svg_metadata as svg;
use tera::{from_value, to_value, Error, Function as TeraFn, Result, Value};
Expand Down Expand Up @@ -95,18 +96,36 @@ fn compute_file_sha256(mut file: fs::File) -> result::Result<String, io::Error>
Ok(format!("{:x}", hasher.finalize()))
}

fn compute_file_sha256_base64(mut file: fs::File) -> result::Result<String, io::Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be cleaner to pass the base64 arg to those functions than to duplicate them all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it but there were already 3 different functions for the 3 possible values of sha_type so I opted for keeping it consistent.

Wouldn't it be even better to pass sha_type and base64 to one unique function handling all the possible combinations?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be even better to pass sha_type and base64 to one unique function handling all the possible combinations?

Even better!

let mut hasher = Sha256::new();
io::copy(&mut file, &mut hasher)?;
Ok(format!("{}", encode_b64(hasher.finalize())))
}

fn compute_file_sha384(mut file: fs::File) -> result::Result<String, io::Error> {
let mut hasher = Sha384::new();
io::copy(&mut file, &mut hasher)?;
Ok(format!("{:x}", hasher.finalize()))
}

fn compute_file_sha384_base64(mut file: fs::File) -> result::Result<String, io::Error> {
let mut hasher = Sha384::new();
io::copy(&mut file, &mut hasher)?;
Ok(format!("{}", encode_b64(hasher.finalize())))
}

fn compute_file_sha512(mut file: fs::File) -> result::Result<String, io::Error> {
let mut hasher = Sha512::new();
io::copy(&mut file, &mut hasher)?;
Ok(format!("{:x}", hasher.finalize()))
}

fn compute_file_sha512_base64(mut file: fs::File) -> result::Result<String, io::Error> {
let mut hasher = Sha512::new();
io::copy(&mut file, &mut hasher)?;
Ok(format!("{}", encode_b64(hasher.finalize())))
}

fn file_not_found_err(search_paths: &[PathBuf], url: &str) -> Result<Value> {
Err(format!(
"file `{}` not found; searched in{}",
Expand Down Expand Up @@ -178,6 +197,7 @@ impl GetFileHash {
}

const DEFAULT_SHA_TYPE: u16 = 384;
const DEFAULT_BASE64: bool = false;

impl TeraFn for GetFileHash {
fn call(&self, args: &HashMap<String, Value>) -> Result<Value> {
Expand All @@ -192,12 +212,21 @@ impl TeraFn for GetFileHash {
"`get_file_hash`: `sha_type` must be 256, 384 or 512"
)
.unwrap_or(DEFAULT_SHA_TYPE);

let compute_hash_fn = match sha_type {
256 => compute_file_sha256,
384 => compute_file_sha384,
512 => compute_file_sha512,
_ => return Err("`get_file_hash`: `sha_type` must be 256, 384 or 512".into()),
let base64 = optional_arg!(
bool,
args.get("base64"),
"`get_file_hash`: `base64` must be true or false"
)
.unwrap_or(DEFAULT_BASE64);

let compute_hash_fn = match (sha_type, base64) {
(256, true) => compute_file_sha256_base64,
(256, false) => compute_file_sha256,
(384, true) => compute_file_sha384_base64,
(384, false) => compute_file_sha384,
(512, true) => compute_file_sha512_base64,
(512, false) => compute_file_sha512,
_ => return Err("`get_file_hash`: bad arguments".into()),
};

let hash = open_file(&self.search_paths, &path).and_then(compute_hash_fn);
Expand Down Expand Up @@ -819,12 +848,37 @@ title = "A title"
);
}

#[test]
fn can_get_file_hash_sha256_base64() {
let static_fn = GetFileHash::new(vec![TEST_CONTEXT.static_path.clone()]);
let mut args = HashMap::new();
args.insert("path".to_string(), to_value("app.css").unwrap());
args.insert("sha_type".to_string(), to_value(256).unwrap());
args.insert("base64".to_string(), to_value(true).unwrap());
assert_eq!(static_fn.call(&args).unwrap(), "Vy5pHcaMP81lOuRjJhvbOPNdxvAXFdnOaHmTGd0ViEA=");
}

#[test]
fn can_get_file_hash_sha384() {
let static_fn = GetFileHash::new(vec![TEST_CONTEXT.static_path.clone()]);
let mut args = HashMap::new();
args.insert("path".to_string(), to_value("app.css").unwrap());
assert_eq!(static_fn.call(&args).unwrap(), "141c09bd28899773b772bbe064d8b718fa1d6f2852b7eafd5ed6689d26b74883b79e2e814cd69d5b52ab476aa284c414");
assert_eq!(
static_fn.call(&args).unwrap(),
"141c09bd28899773b772bbe064d8b718fa1d6f2852b7eafd5ed6689d26b74883b79e2e814cd69d5b52ab476aa284c414"
);
}

#[test]
fn can_get_file_hash_sha384_base64() {
let static_fn = GetFileHash::new(vec![TEST_CONTEXT.static_path.clone()]);
let mut args = HashMap::new();
args.insert("path".to_string(), to_value("app.css").unwrap());
args.insert("base64".to_string(), to_value(true).unwrap());
assert_eq!(
static_fn.call(&args).unwrap(),
"FBwJvSiJl3O3crvgZNi3GPodbyhSt+r9XtZonSa3SIO3ni6BTNadW1KrR2qihMQU"
);
}

#[test]
Expand All @@ -833,7 +887,23 @@ title = "A title"
let mut args = HashMap::new();
args.insert("path".to_string(), to_value("app.css").unwrap());
args.insert("sha_type".to_string(), to_value(512).unwrap());
assert_eq!(static_fn.call(&args).unwrap(), "379dfab35123b9159d9e4e92dc90e2be44cf3c2f7f09b2e2df80a1b219b461de3556c93e1a9ceb3008e999e2d6a54b4f1d65ee9be9be63fa45ec88931623372f");
assert_eq!(
static_fn.call(&args).unwrap(),
"379dfab35123b9159d9e4e92dc90e2be44cf3c2f7f09b2e2df80a1b219b461de3556c93e1a9ceb3008e999e2d6a54b4f1d65ee9be9be63fa45ec88931623372f"
);
}

#[test]
fn can_get_file_hash_sha512_base64() {
let static_fn = GetFileHash::new(vec![TEST_CONTEXT.static_path.clone()]);
let mut args = HashMap::new();
args.insert("path".to_string(), to_value("app.css").unwrap());
args.insert("sha_type".to_string(), to_value(512).unwrap());
args.insert("base64".to_string(), to_value(true).unwrap());
assert_eq!(
static_fn.call(&args).unwrap(),
"N536s1EjuRWdnk6S3JDivkTPPC9/CbLi34Chshm0Yd41Vsk+GpzrMAjpmeLWpUtPHWXum+m+Y/pF7IiTFiM3Lw=="
);
}

#[test]
Expand Down