Stop search auto-pagination from looping on failure; accept CSRF in JSON body; make replication pause/resume idempotent

This commit is contained in:
2026-04-25 14:06:39 +08:00
parent 7e32ac2a46
commit dd1e6d0409
6 changed files with 169 additions and 61 deletions

View File

@@ -155,6 +155,8 @@ pub async fn csrf_layer(
extract_form_token(&bytes)
} else if content_type.starts_with("multipart/form-data") {
extract_multipart_token(&content_type, &bytes)
} else if content_type.starts_with("application/json") {
extract_json_token(&bytes)
} else {
None
};
@@ -194,7 +196,7 @@ pub async fn csrf_layer(
let mut resp = (
StatusCode::FORBIDDEN,
[(header::CONTENT_TYPE, "application/json")],
r#"{"error":"Invalid CSRF token"}"#,
r#"{"error":"Invalid CSRF token. Send it via the X-CSRF-Token header or a csrf_token field in the form/JSON body."}"#,
)
.into_response();
*resp.status_mut() = StatusCode::FORBIDDEN;
@@ -238,6 +240,14 @@ fn build_session_cookie(id: &str, secure: bool) -> Cookie<'static> {
cookie
}
fn extract_json_token(body: &[u8]) -> Option<String> {
let value: serde_json::Value = serde_json::from_slice(body).ok()?;
value
.get(CSRF_FIELD_NAME)
.and_then(|v| v.as_str())
.map(|s| s.to_string())
}
fn extract_form_token(body: &[u8]) -> Option<String> {
let text = std::str::from_utf8(body).ok()?;
let prefix = format!("{}=", CSRF_FIELD_NAME);