#[cfg(feature = "pump")]
pub mod pump;
pub mod sign_in;
#[cfg(feature = "sold-door")]
pub mod sold_door;
pub fn now_unix_ms() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0)
}
pub fn hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{b:02x}")).collect()
}
pub fn key32(text: &str) -> Option<[u8; 32]> {
let t = text.trim();
if t.len() == 64 {
return unhex32(t, "the key").ok();
}
monetize_embed::signing::base64_decode(t)?.try_into().ok()
}
pub fn unhex32(s: &str, what: &str) -> Result<[u8; 32], String> {
let s = s.trim();
if s.len() != 64 || !s.is_ascii() {
return Err(format!("{what} is not 64 hex"));
}
let v: Result<Vec<u8>, _> = (0..64)
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
.collect();
v.map_err(|_| format!("{what} is not 64 hex"))?
.try_into()
.map_err(|_| format!("{what} is not 32 bytes"))
}
#[cfg(feature = "pump")]
pub(crate) fn write_atomic(
path: &std::path::Path,
bytes: &[u8],
secret: bool,
) -> std::io::Result<()> {
use std::io::Write;
let dir = path.parent().unwrap_or(std::path::Path::new("."));
std::fs::create_dir_all(dir)?;
let tmp = path.with_extension("tmp");
let mut opts = std::fs::OpenOptions::new();
opts.write(true).create(true).truncate(true);
#[cfg(unix)]
if secret {
use std::os::unix::fs::OpenOptionsExt;
opts.mode(0o600);
}
#[cfg(not(unix))]
let _ = secret;
let mut f = opts.open(&tmp)?;
f.write_all(bytes)?;
f.sync_all()?;
std::fs::rename(&tmp, path)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_key_is_64_hex_or_44_base64_and_anything_else_is_none() {
let k = [0x11u8; 32];
assert_eq!(key32(&hex(&k)), Some(k));
assert_eq!(key32(&format!(" {}\n", hex(&k))), Some(k), "trimmed");
assert_eq!(key32(&monetize_embed::signing::base64_encode(&k)), Some(k));
assert_eq!(key32("11"), None);
assert_eq!(key32(&"zz".repeat(32)), None);
assert!(unhex32(&"1".repeat(63), "the client key")
.unwrap_err()
.contains("the client key is not 64 hex"));
assert!(
unhex32(&"é".repeat(32), "k").is_err(),
"a non-ASCII text never panics on a char boundary"
);
assert!(now_unix_ms() > 1_700_000_000_000);
}
}