mirror of
https://github.com/vectorize-io/hindsight.git
synced 2026-09-14 19:31:49 +08:00
fix(cli): preserve base64 '=' padding when parsing config-file api_key (#3909)
The config parser used line.split('=').nth(1), which splits on every
'=' in the line and silently strips the trailing padding characters
from base64 API keys read from ~/.hindsight/config. Keys ending in '='
were corrupted, so the CLI failed authentication when relying on the
config file instead of HINDSIGHT_API_KEY.
Use split_once('=') so the value keeps any literal '=' it contains, and
delegate the config-file loop to parse_config_value to share the logic
with profile loading. Add regression tests for base64 padding and
values containing multiple '='.
Co-authored-by: 2anoubis <2anoubis@users.noreply.github.com>
This commit is contained in:
+30
-26
@@ -125,21 +125,10 @@ impl Config {
|
||||
|
||||
// Simple TOML parsing for api_url and api_key
|
||||
for line in content.lines() {
|
||||
let line = line.trim();
|
||||
if line.starts_with("api_url") {
|
||||
if let Some(value) = line.split('=').nth(1) {
|
||||
let value = value.trim().trim_matches('"').trim_matches('\'');
|
||||
if !value.is_empty() {
|
||||
api_url = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
} else if line.starts_with("api_key") {
|
||||
if let Some(value) = line.split('=').nth(1) {
|
||||
let value = value.trim().trim_matches('"').trim_matches('\'');
|
||||
if !value.is_empty() {
|
||||
api_key = Some(value.to_string());
|
||||
}
|
||||
}
|
||||
if let Some(v) = parse_config_value(line, "api_url") {
|
||||
api_url = Some(v);
|
||||
} else if let Some(v) = parse_config_value(line, "api_key") {
|
||||
api_key = Some(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,21 +364,21 @@ pub fn generate_doc_id() -> String {
|
||||
|
||||
/// Parse a simple TOML-like config line and extract value.
|
||||
/// Handles both quoted and unquoted values.
|
||||
///
|
||||
/// Uses `split_once('=')` so the value keeps any literal `=` characters it
|
||||
/// contains (e.g. the trailing padding of a base64 API key).
|
||||
pub fn parse_config_value(line: &str, key: &str) -> Option<String> {
|
||||
let line = line.trim();
|
||||
if !line.starts_with(key) {
|
||||
let (k, v) = line.split_once('=')?;
|
||||
if k.trim() != key {
|
||||
return None;
|
||||
}
|
||||
line.split('=')
|
||||
.nth(1)
|
||||
.map(|value| {
|
||||
value
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.trim_matches('\'')
|
||||
.to_string()
|
||||
})
|
||||
.filter(|v| !v.is_empty())
|
||||
let value = v.trim().trim_matches('"').trim_matches('\'');
|
||||
if value.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -613,6 +602,21 @@ mod tests {
|
||||
assert_eq!(parse_config_value("api_url = \"\"", "api_url"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_config_value_preserves_base64_padding() {
|
||||
let key = "dCcxYDq+Bg0G268UuJIIHvQG4Cp5GnJWR+HIm8WRAIM=";
|
||||
let line = format!("api_key = \"{}\"", key);
|
||||
assert_eq!(parse_config_value(&line, "api_key").as_deref(), Some(key));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_config_value_key_with_equals() {
|
||||
assert_eq!(
|
||||
parse_config_value("api_key = a=b=c", "api_key").as_deref(),
|
||||
Some("a=b=c")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_api_url_accessor() {
|
||||
let config = Config {
|
||||
|
||||
Reference in New Issue
Block a user