mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-12 23:09:33 +01:00
seaweed-volume: read security.toml values as TOML strings (#12582)
The line parser only trimmed quotes, so `key = "abc\n"` gave the Rust volume server the bytes `abc\n` with a literal backslash while the Go servers sign with a newline, and every JWT failed. Literal strings kept their quotes and a trailing comment stayed part of the value. Decode each value with the TOML parser; text it rejects keeps the old quote trimming. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b7d6b48921
commit
c2625ddf00
1 file changed
+43
-1
@@ -1175,7 +1175,7 @@ fn parse_security_config_with_env(path: &str, env: EnvLookup<'_>) -> SecurityCon
|
||||
|
||||
if let Some((key, value)) = trimmed.split_once('=') {
|
||||
let key = key.trim();
|
||||
let value = value.trim().trim_matches('"');
|
||||
let value: &str = &toml_value_text(value);
|
||||
match section {
|
||||
Section::JwtSigningRead => match key {
|
||||
"key" => cfg.jwt_read_signing_key = value.as_bytes().to_vec(),
|
||||
@@ -1265,6 +1265,20 @@ fn parse_security_config_with_env(path: &str, env: EnvLookup<'_>) -> SecurityCon
|
||||
cfg
|
||||
}
|
||||
|
||||
/// Reads the right-hand side of `key = value` the way TOML (and so Go) does:
|
||||
/// escapes decoded, literal strings kept as written, a trailing comment
|
||||
/// dropped. Text TOML rejects keeps the plain quote trimming.
|
||||
fn toml_value_text(raw: &str) -> String {
|
||||
match format!("v = {raw}").parse::<toml::Table>() {
|
||||
Ok(mut table) => match table.remove("v") {
|
||||
Some(toml::Value::String(text)) => text,
|
||||
Some(other) => other.to_string(),
|
||||
None => String::new(),
|
||||
},
|
||||
Err(_) => raw.trim().trim_matches('"').to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_security_config_path(path: &str, env: EnvLookup<'_>) -> Option<PathBuf> {
|
||||
if !path.is_empty() {
|
||||
return Some(PathBuf::from(path));
|
||||
@@ -1868,6 +1882,34 @@ ui = true
|
||||
assert!(cfg.access_ui);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_security_config_reads_toml_strings() {
|
||||
for (encoded, expected) in [
|
||||
(r#""plain""#, "plain"),
|
||||
(r#""key\n""#, "key\n"),
|
||||
(r#""quote\"slash\\tab\t""#, "quote\"slash\\tab\t"),
|
||||
(r#""key""#, "key"),
|
||||
("'literal\\key'", "literal\\key"),
|
||||
(r#""key" # comment"#, "key"),
|
||||
(r#""YWJj==""#, "YWJj=="),
|
||||
("unquoted", "unquoted"),
|
||||
] {
|
||||
let tmp = tempfile::NamedTempFile::new().unwrap();
|
||||
std::fs::write(
|
||||
tmp.path(),
|
||||
format!(
|
||||
"[jwt.signing]\nkey = {encoded}\n\n[jwt.signing.read]\nkey = {encoded}\n\
|
||||
expires_after_seconds = 30 # seconds\n"
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let cfg = parse_security_config_with_env(tmp.path().to_str().unwrap(), &|_| None);
|
||||
assert_eq!(cfg.jwt_signing_key, expected.as_bytes(), "{encoded}");
|
||||
assert_eq!(cfg.jwt_read_signing_key, expected.as_bytes(), "{encoded}");
|
||||
assert_eq!(cfg.jwt_read_signing_expires, 30, "{encoded}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_security_config_discovers_current_directory_default() {
|
||||
let _guard = process_state_lock();
|
||||
|
||||
Reference in new issue
Block a user