vv_agent/config/
api_keys.rs1use base64::{engine::general_purpose, Engine as _};
2
3pub fn decode_api_key(raw_value: &str) -> String {
4 let raw = raw_value.trim();
5 if raw.is_empty() {
6 return raw.to_string();
7 }
8
9 if let Some(direct) = extract_suffix_key(raw) {
10 return direct;
11 }
12
13 if std::env::var("V_AGENT_ENABLE_BASE64_KEY_DECODE").as_deref() == Ok("1") {
14 if let Some(decoded) = maybe_base64_decode(raw) {
15 if let Some(from_decoded) = extract_suffix_key(&decoded) {
16 return from_decoded;
17 }
18 if looks_like_api_key(&decoded) {
19 return decoded;
20 }
21 }
22 }
23
24 raw.to_string()
25}
26
27fn extract_suffix_key(value: &str) -> Option<String> {
28 let (_, suffix) = value.split_once(':')?;
29 let suffix = suffix.trim();
30 looks_like_api_key(suffix).then(|| suffix.to_string())
31}
32
33fn maybe_base64_decode(value: &str) -> Option<String> {
34 let mut padded = value.to_string();
35 let remainder = padded.len() % 4;
36 if remainder != 0 {
37 padded.extend(std::iter::repeat_n('=', 4 - remainder));
38 }
39 let decoded = general_purpose::STANDARD.decode(padded).ok()?;
40 String::from_utf8(decoded).ok()
41}
42
43fn looks_like_api_key(value: &str) -> bool {
44 !value.is_empty() && value.len() >= 10 && !value.chars().any(char::is_whitespace)
45}