use zeroize::{ZeroizeOnDrop, Zeroizing};
pub const LEN: usize = 108;
type Arr = [u8; LEN];
#[derive(Debug, thiserror::Error)]
#[error("Invalid key length: {actual} (expected {LEN})")]
pub struct InvalidKeyLength {
pub actual: usize,
}
#[derive(Debug, ZeroizeOnDrop)]
pub struct Key {
mem: Arr,
}
impl Key {
pub fn read(&self) -> &[u8] {
&self.mem
}
}
impl TryFrom<String> for Key {
type Error = InvalidKeyLength;
fn try_from(s: String) -> Result<Self, Self::Error> {
let v = Zeroizing::new(s.into_bytes());
let mut arr: Arr = [0; LEN];
if v.len() != LEN {
let actual = v.len();
return Err(InvalidKeyLength { actual });
}
arr.copy_from_slice(&v);
Ok(Key { mem: arr })
}
}
impl std::fmt::Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let key_str = std::str::from_utf8(self.read()).unwrap();
write!(f, "{}", key_str)
}
}
#[cfg(test)]
mod tests {
use super::*;
const API_KEY: &str = "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";
#[test]
fn test_key() {
let key = Key::try_from(API_KEY.to_string()).unwrap();
let key_str = key.to_string();
assert_eq!(key_str, API_KEY);
}
#[test]
fn test_invalid_key_length() {
let key = "test_key".to_string();
let err = Key::try_from(key).unwrap_err();
assert_eq!(err.to_string(), "Invalid key length: 8 (expected 108)");
}
}