diff --git a/.changelog/unreleased/improvements/ibc-relayer/4045-trim-whitespaces-channel-port-filter.md b/.changelog/unreleased/improvements/ibc-relayer/4045-trim-whitespaces-channel-port-filter.md new file mode 100644 index 0000000000..8cfcd2c1bc --- /dev/null +++ b/.changelog/unreleased/improvements/ibc-relayer/4045-trim-whitespaces-channel-port-filter.md @@ -0,0 +1,5 @@ +- Updated the channel and port filter parsing to ignore whitespaces. + This will prevent unintended channel scanning due to accidental + whitespaces when exact matches are specified in the `packet_filter` + configuration. + ([\#4045](https://github.com/informalsystems/hermes/issues/4045)) \ No newline at end of file diff --git a/crates/relayer/src/config/filter.rs b/crates/relayer/src/config/filter.rs index f6ff932797..576c62a8ee 100644 --- a/crates/relayer/src/config/filter.rs +++ b/crates/relayer/src/config/filter.rs @@ -384,11 +384,13 @@ pub(crate) mod port { } fn visit_str(self, v: &str) -> Result { - if let Ok(port_id) = PortId::from_str(v) { - Ok(PortFilterMatch::Exact(port_id)) - } else { - let wildcard = v.parse().map_err(E::custom)?; + let trimmed_v = v.trim(); + if trimmed_v.contains('*') { + let wildcard = trimmed_v.parse().map_err(E::custom)?; Ok(PortFilterMatch::Wildcard(wildcard)) + } else { + let port_id = PortId::from_str(trimmed_v).map_err(E::custom)?; + Ok(PortFilterMatch::Exact(port_id)) } } @@ -411,11 +413,13 @@ pub(crate) mod channel { } fn visit_str(self, v: &str) -> Result { - if let Ok(channel_id) = ChannelId::from_str(v) { - Ok(ChannelFilterMatch::Exact(channel_id)) - } else { - let wildcard = v.parse().map_err(E::custom)?; + let trimmed_v = v.trim(); + if trimmed_v.contains('*') { + let wildcard = trimmed_v.parse().map_err(E::custom)?; Ok(ChannelFilterMatch::Wildcard(wildcard)) + } else { + let channel_id = ChannelId::from_str(trimmed_v.trim()).map_err(E::custom)?; + Ok(ChannelFilterMatch::Exact(channel_id)) } } @@ -602,4 +606,21 @@ mod tests { let wildcard = "ica*".parse::().unwrap(); assert_eq!(wildcard.to_string(), "ica*".to_string()); } + + #[test] + fn test_exact_matches() { + let allow_policy = r#" + policy = "allow" + list = [ + [ "transfer", "channel-88", ], # Standard exact match + [ "transfer", "channel-476 ", ], # Whitespace abstraction + ] + "#; + + let pf: ChannelPolicy = + toml::from_str(allow_policy).expect("could not parse filter policy"); + + let assert_allow = matches!(pf, ChannelPolicy::Allow(filters) if filters.is_exact()); + assert!(assert_allow); + } }