commit f97b76407d4b3ee1a5085b4d0855754952823e75
parent 718cb65037a8b5336eb3063886c4a1cc69a9f14e
Author: triesap <tyson@radroots.org>
Date: Mon, 10 Aug 2026 18:03:02 +0000
feat: harden inbound Blossom retrieval
Verify canonical DNS, redirect, byte, media, and dimension bounds before accepting inbound images.
Persist exact artifacts atomically and revoke corrupt or obsolete cache receipts.
Diffstat:
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/core/crates/tera_ffi/src/error.rs b/core/crates/tera_ffi/src/error.rs
@@ -148,6 +148,13 @@ impl From<TodayError> for RadrootsAppError {
}
TodayError::RuntimeUnavailable => ("today_runtime_unavailable", true, &["retry"][..]),
TodayError::InboundMedia(_) => ("today_media_invalid", false, &["retry_media"][..]),
+ TodayError::InboundRetrieval(error) => {
+ if error.retryable() {
+ ("today_media_retrieval_failed", true, &["retry_media"][..])
+ } else {
+ ("today_media_retrieval_failed", false, &["review_media"][..])
+ }
+ }
TodayError::CorruptProjection | TodayError::Serialization | TodayError::Storage(_) => {
("today_state_failed", true, &["rebuild", "retry"][..])
}
diff --git a/core/crates/tera_ffi/tests/local_mvp_real_io.rs b/core/crates/tera_ffi/tests/local_mvp_real_io.rs
@@ -829,7 +829,7 @@ async fn prove_corrupted_media_fails(
assert_eq!(evidence.last_successful_state, "upload_verified");
assert_eq!(
evidence.error_code.as_deref(),
- Some("blossom_retrieved_bytes_mismatch")
+ Some("blossom_response_hash_mismatch")
);
assert_eq!(evidence.error_phase.as_deref(), Some("verification"));
assert!(evidence.possible_orphan);