Skip to main content

keys_lib/
lib.rs

1use std::fmt::Display;
2
3use base64::{engine::general_purpose::URL_SAFE_NO_PAD, DecodeSliceError, Engine as _};
4use rand::Rng;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct KeyValue {
9    key: String,
10    value: Option<String>,
11}
12
13impl KeyValue {
14    pub fn new<K: Into<String>, V: Into<String>>(
15        key: K,
16        value: Option<V>,
17    ) -> Self {
18        Self {
19            key: key.into(),
20            value: value.map(|value| value.into()),
21        }
22    }
23
24    pub fn get_key(&self) -> &str {
25        &self.key
26    }
27
28    pub fn get_value(&self) -> Option<&str> {
29        self.value.as_deref()
30    }
31}
32
33impl Display for KeyValue {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self.get_value() {
36            Some(value) => write!(f, "{}: {}", self.get_key(), value),
37            None => write!(f, "{}", self.get_key()),
38        }
39    }
40}
41
42#[derive(Debug, Clone)]
43pub struct ApiKey {
44    bytes: [u8; 32],
45}
46
47impl ApiKey {
48    pub fn random<R: Rng>(rng: &mut R) -> Self {
49        let mut bytes = [0u8; 32];
50        rng.fill_bytes(&mut bytes);
51        Self::from_bytes(bytes)
52    }
53
54    pub fn from_bytes(bytes: [u8; 32]) -> Self {
55        Self { bytes }
56    }
57
58    pub fn from_base64<S: AsRef<str>>(base64_api_key: S) -> Result<Self, DecodeSliceError> {
59        let mut bytes = [0u8; 32];
60        URL_SAFE_NO_PAD.decode_slice(base64_api_key.as_ref(), &mut bytes)?;
61        Ok(Self::from_bytes(bytes))
62    }
63
64    pub fn to_base64(&self) -> String {
65        URL_SAFE_NO_PAD.encode(self.bytes)
66    }
67
68    pub fn hash(&self) -> Vec<u8> {
69        hex::decode(sha256::digest(&self.bytes)).expect("SHA256 digest contained invalid hex")
70    }
71}