commit 2473fac05942475239202ea005c5751259a0690f
parent 43f25544b56ca7af494c23d072f579730f91b1f8
Author: triesap <tyson@radroots.org>
Date: Tue, 7 Jul 2026 20:56:57 +0000
transport: reject non-Reticulum preview behavior
- reject preview_behavior on non-Reticulum publish targets
- add a typed protocol validation error for invalid preview behavior
- cover Nostr explicit-target rejection in protocol tests
- keep Reticulum preview behavior handling unchanged
Diffstat:
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/crates/transport_publish_protocol/src/lib.rs b/crates/transport_publish_protocol/src/lib.rs
@@ -42,6 +42,9 @@ pub enum TransportPublishProtocolError {
EmptyEndpointUri {
index: usize,
},
+ InvalidPreviewBehavior {
+ index: usize,
+ },
InvalidReticulumPreviewEndpoint {
index: usize,
},
@@ -79,6 +82,10 @@ impl fmt::Display for TransportPublishProtocolError {
Self::EmptyEndpointUri { index } => {
write!(f, "transport target {index} endpoint_uri must not be empty")
}
+ Self::InvalidPreviewBehavior { index } => write!(
+ f,
+ "transport target {index} preview_behavior is only valid for Reticulum targets"
+ ),
Self::InvalidReticulumPreviewEndpoint { index } => write!(
f,
"transport target {index} Reticulum preview endpoint must be {RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI}"
@@ -180,6 +187,9 @@ impl TransportPublishTarget {
if self.endpoint_uri.trim().is_empty() {
return Err(TransportPublishProtocolError::EmptyEndpointUri { index });
}
+ if transport_kind != RadrootsTransportKind::Reticulum && self.preview_behavior.is_some() {
+ return Err(TransportPublishProtocolError::InvalidPreviewBehavior { index });
+ }
if transport_kind == RadrootsTransportKind::Reticulum
&& self.endpoint_uri != RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI
{
@@ -784,6 +794,18 @@ mod tests {
Err(TransportPublishProtocolError::InvalidTransportKind { index: 0 })
);
+ let mut nostr_preview_behavior = request.clone();
+ nostr_preview_behavior.target_policy =
+ TransportPublishTargetPolicy::explicit_targets(vec![TransportPublishTarget {
+ transport_kind: "nostr".to_owned(),
+ endpoint_uri: "wss://relay.example.com".to_owned(),
+ preview_behavior: Some(TransportPublishPreviewBehavior::RejectDeliveryAttempts),
+ }]);
+ assert_eq!(
+ nostr_preview_behavior.validate(1),
+ Err(TransportPublishProtocolError::InvalidPreviewBehavior { index: 0 })
+ );
+
for invalid in [
" reticulum:preview-unavailable",
"reticulum:preview-unavailable ",
@@ -932,8 +954,12 @@ mod tests {
"transport target 3 endpoint_uri must not be empty",
),
(
- TransportPublishProtocolError::InvalidReticulumPreviewEndpoint { index: 4 },
- "transport target 4 Reticulum preview endpoint must be reticulum:preview-unavailable",
+ TransportPublishProtocolError::InvalidPreviewBehavior { index: 4 },
+ "transport target 4 preview_behavior is only valid for Reticulum targets",
+ ),
+ (
+ TransportPublishProtocolError::InvalidReticulumPreviewEndpoint { index: 5 },
+ "transport target 5 Reticulum preview endpoint must be reticulum:preview-unavailable",
),
(
TransportPublishProtocolError::TargetLimitExceeded { max: 1, actual: 2 },