Files
authy-oidc/src/utils.rs

140 lines
4.2 KiB
Rust

pub mod web {
/// Macro shenanigans to format a str at compile time
pub macro make_static_cache_header($max_age:expr, $stale_revalidate:expr) {{
// type guards lmfao
const _: ::std::time::Duration = $max_age;
const _: ::std::time::Duration = $stale_revalidate;
// hopefully ident encapsulation will save my ass here
const MAX_AGE: u64 = $max_age.as_secs();
const STALE_REVALIDATE: u64 = $stale_revalidate.as_secs();
const_str::format!(
"public, max-age={}, stale-while-revalidate={}",
MAX_AGE,
STALE_REVALIDATE
)
}}
#[cfg(test)]
mod test {
use std::time::Duration;
#[test]
fn const_concat_worked() {
const MA: Duration = Duration::from_mins(15);
const SR: Duration = Duration::from_hours(1);
const NAME: &str = super::make_static_cache_header!(MA, SR);
assert_eq!(
NAME,
format!(
"public, max-age={}, stale-while-revalidate={}",
MA.as_secs(),
SR.as_secs()
)
);
}
}
}
pub mod shasum {
#[must_use]
pub fn sha256sum_to_hex_string(sha256sum: &[u8]) -> String {
let mut out = String::with_capacity(sha256sum.len() * 2);
for &b in sha256sum {
/// Only correct as long as `n` is ranged within a nibble
#[inline]
const fn nibble_to_hex(n: u8) -> char {
(match n {
0..=9 => b'0' + n,
_ => b'a' + (n - 10),
}) as char
}
let hi = (b >> 4) & 0x0f;
let lo = b & 0x0f;
out.push(nibble_to_hex(hi));
out.push(nibble_to_hex(lo));
}
out
}
#[cfg(test)]
mod test {
use crate::utils::shasum::sha256sum_to_hex_string;
#[test]
fn sha256sum_string() {
let null_sha = sha256sum_to_hex_string(&[0; 32]);
let full_sha = sha256sum_to_hex_string(&[0xff; 32]);
assert_eq!(
null_sha,
"0000000000000000000000000000000000000000000000000000000000000000"
);
assert_eq!(
full_sha,
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
);
}
}
}
pub mod fs {
use std::{io, os::unix::fs::MetadataExt as _, path::Path};
use tokio::{fs::File, io::AsyncReadExt};
/// # Errors
///
/// On any underlaying file i/o error.
///
/// # Panics
///
/// If a file's [`u64`] doesn't fit in memory.
pub async fn read_limited_path<const MAXSIZE: u64>(path: &Path) -> io::Result<Vec<u8>> {
let f = File::open(path).await?;
let size = f.metadata().await?.size();
if size > MAXSIZE {
return Err(io::Error::new(
io::ErrorKind::FileTooLarge,
"filesize is bigger than MAXSIZE",
));
}
let mut buf = Vec::with_capacity(size.try_into().expect("u64 to fit in usize"));
// `.take()` just in case an open fd happens to grow, `.metadata()` SHOULD take
// properties from the fd and lock the read fd until its closed but still
f.take(MAXSIZE).read_to_end(&mut buf).await?;
Ok(buf)
}
/// # Errors
///
/// On any underlaying file i/o error.
///
/// # Panics
///
/// If a file's [`u64`] doesn't fit in memory.
pub async fn read_limited_path_str<const MAXSIZE: u64>(path: &Path) -> io::Result<String> {
let f = File::open(path).await?;
let size = f.metadata().await?.size();
if size > MAXSIZE {
return Err(io::Error::new(
io::ErrorKind::FileTooLarge,
"filesize is bigger than MAXSIZE",
));
}
let mut buf = String::with_capacity(size.try_into().expect("u64 to fit in usize"));
// `.take()` just in case an open fd happens to grow, `.metadata()` SHOULD take
// properties from the fd and lock the read fd until its closed but still
f.take(MAXSIZE).read_to_string(&mut buf).await?;
Ok(buf)
}
}