Harden auth/vault path sanitization and clean WeKnora docs

This commit is contained in:
Agent Board
2026-07-28 17:04:27 +08:00
parent 2deaf59f7b
commit 26ff1a9c9a
190 changed files with 13454 additions and 4987 deletions
+14 -1
View File
@@ -23,11 +23,13 @@ pub fn ai_vault_actor_id() -> String {
}
/// Encode actor id for managed path segment (aligned with mnote-web).
///
/// 不保留 `.` / `/` 等路径元字符,避免 actor=`..` 时穿越 `users/` 目录。
pub fn encode_actor_segment(actor_id: &str) -> String {
actor_id
.chars()
.map(|c| match c {
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' => c.to_string(),
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' => c.to_string(),
other => format!("~{:02x}", other as u32),
})
.collect()
@@ -786,6 +788,17 @@ mod tests {
static AI_TEST_LOCK: Mutex<()> = Mutex::new(());
#[test]
fn encode_actor_segment_rejects_path_traversal_dots() {
// `..` 不得原样保留,否则 join("users", "..") 可穿越目录。
let encoded = encode_actor_segment("..");
assert!(!encoded.contains('.'), "encoded={encoded}");
assert_eq!(encoded, "~2e~2e");
let dotted = encode_actor_segment("a.b");
assert!(!dotted.contains('.'), "encoded={dotted}");
assert_eq!(dotted, "a~2eb");
}
fn with_temp_workspace<F, R>(f: F) -> R
where
F: FnOnce(&Path) -> R,
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -108,10 +108,11 @@ pub fn load_or_create_hmac_key(path: &Path) -> Result<Vec<u8>, VaultError> {
)
})?;
let hex = raw.trim();
if hex.len() < 32 {
// 生成侧写 32 字节 → 64 hex;读取侧要求一致,拒绝弱 key。
if hex.len() < 64 {
return Err(VaultError::bad_request_code(
"vault_hmac_key_invalid",
"HMAC key 过短",
"HMAC key 过短(需要至少 32 字节 / 64 hex)",
));
}
return hex::decode(hex).map_err(|e| {