Skip to main content

gobby_code/
utils.rs

1use anyhow::Context as _;
2use sha2::{Digest, Sha256};
3
4pub fn api_key_fingerprint(api_key: &str) -> String {
5    let digest = Sha256::digest(api_key.as_bytes());
6    let mut fingerprint = String::with_capacity(16);
7    for byte in &digest[..8] {
8        use std::fmt::Write as _;
9        let _ = write!(fingerprint, "{byte:02x}");
10    }
11    fingerprint
12}
13
14pub fn short_id(id: &str) -> String {
15    id.chars().take(8).collect()
16}
17
18pub(crate) fn i64_to_usize(value: i64, column: &str) -> anyhow::Result<usize> {
19    value
20        .try_into()
21        .with_context(|| format!("column `{column}` contains negative or too-large value {value}"))
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn short_id_truncates_long_ids() {
30        assert_eq!(short_id("1234567890"), "12345678");
31    }
32
33    #[test]
34    fn short_id_returns_input_for_short_strings() {
35        assert_eq!(short_id("abc"), "abc");
36    }
37
38    #[test]
39    fn short_id_returns_input_for_exact_length() {
40        assert_eq!(short_id("12345678"), "12345678");
41    }
42
43    #[test]
44    fn short_id_handles_unicode() {
45        let value = "\u{00e9}".repeat(9);
46        let expected = "\u{00e9}".repeat(8);
47        assert_eq!(short_id(&value), expected);
48    }
49
50    #[test]
51    fn api_key_fingerprint_uses_stable_short_sha256() {
52        assert_eq!(api_key_fingerprint("secret-key"), "85dbe15d75ef9308");
53    }
54}