From eaea8b8cb0e6bb08e8a5da928d3a18b26959798b Mon Sep 17 00:00:00 2001 From: Sasha Mitchell Date: Fri, 9 Oct 2026 17:47:12 +0700 Subject: [PATCH] fix(geoblock): match country codes case-insensitively A blocked country written as cu did not match MaxMind's CU, so the request was allowed. Subdivision codes already ignore ASCII case. --- crates/geoip/src/block.rs | 2 +- crates/geoip/src/block/middleware/tests.rs | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/geoip/src/block.rs b/crates/geoip/src/block.rs index df18aaf..90c5b57 100644 --- a/crates/geoip/src/block.rs +++ b/crates/geoip/src/block.rs @@ -75,7 +75,7 @@ impl ZoneFilter { let country = geo_data.country.iso_code.ok_or(Error::CountryNotFound)?; let zone_blocked = self.blocked_zones.iter().any(|blocked_zone| { - if blocked_zone.country == country { + if blocked_zone.country.eq_ignore_ascii_case(country) { if blocked_zone.subdivisions.is_empty() { true } else { diff --git a/crates/geoip/src/block/middleware/tests.rs b/crates/geoip/src/block/middleware/tests.rs index 8eb6c6d..7a0136d 100644 --- a/crates/geoip/src/block/middleware/tests.rs +++ b/crates/geoip/src/block/middleware/tests.rs @@ -77,6 +77,27 @@ async fn test_country_blocked() { assert_eq!(response.status(), StatusCode::UNAUTHORIZED); } +/// A lowercase country code is the same block as the uppercase code MaxMind +/// returns. +#[tokio::test] +async fn test_country_blocked_ignores_ascii_case() { + let resolver = LocalResolver::new(Some(resolve_ip), None); + let blocked_countries = vec!["cu".into()]; + + let geoblock = GeoBlockLayer::new(resolver, blocked_countries, BlockingPolicy::Block); + + let mut service = ServiceBuilder::new().layer(geoblock).service_fn(handle); + + let request = Request::builder() + .header("X-Forwarded-For", "127.0.0.1") + .body(Body::empty()) + .unwrap(); + + let response = service.ready().await.unwrap().call(request).await.unwrap(); + + assert_eq!(response.status(), StatusCode::UNAUTHORIZED); +} + /// Test that a blocking list with no subdivisions doesn't block if the /// country doesn't match. #[tokio::test]