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}