debugbundle 1.0.0-alpha.1

Safe, bounded runtime error reporting for Rust, Axum and Actix Web
Documentation
use super::*;

fn head() -> RelayRequest {
    RelayRequest {
        method: "POST".into(),
        scheme: "http".into(),
        host: "internal:3000".into(),
        origin: Some("https://app.example.test".into()),
        peer: Some("192.0.2.4".parse().unwrap()),
        forwarded_host: Some("app.example.test".into()),
        forwarded_proto: Some("https".into()),
        forwarded_for: Some("203.0.113.8".into()),
        ..Default::default()
    }
}

#[test]
fn forwarded_identity_is_accepted_only_from_the_exact_configured_proxy_peer() {
    let mut request = head();
    let mut options = RelayOptions::default();
    assert_eq!(origin(&request, &options), None);
    assert_eq!(peer(&request, &options), request.peer);
    options.trusted_proxies.push(request.peer.unwrap());
    assert_eq!(
        origin(&request, &options).as_deref(),
        Some("https://app.example.test")
    );
    assert_eq!(
        peer(&request, &options),
        Some("203.0.113.8".parse().unwrap())
    );
    for invalid in [
        "203.0.113.8, 192.0.2.1",
        "not-an-ip",
        "",
        "a-very-long-untrusted-forwarded-peer-that-cannot-be-an-ip",
    ] {
        request.forwarded_for = Some(invalid.into());
        assert_eq!(peer(&request, &options), request.peer);
    }
    for host in [
        "app.example.test/",
        "app.example.test@evil.test",
        "app.example.test,evil.test",
        "app.example.test\\evil",
    ] {
        request.forwarded_host = Some(host.into());
        assert_eq!(origin(&request, &options), None);
    }
}

#[test]
fn referer_fallback_never_overrides_an_explicit_invalid_origin() {
    let mut request = head();
    let options = RelayOptions {
        allowed_origins: vec!["https://app.example.test".into()],
        ..Default::default()
    };
    request.origin = None;
    request.referer = Some("https://app.example.test/checkout?technical=1".into());
    assert_eq!(
        origin(&request, &options).as_deref(),
        Some("https://app.example.test")
    );
    for invalid in [
        "null",
        "https://app.example.test/path",
        "https://user:password@app.example.test",
        "https://app.example.test?x=1",
        "https://app.example.test#fragment",
        "ftp://app.example.test",
    ] {
        request.origin = Some(invalid.into());
        assert_eq!(origin(&request, &options), None);
    }
    request.origin = Some("x".repeat(8193));
    assert_eq!(origin(&request, &options), None);
}

#[test]
fn a_full_limiter_keeps_existing_counts_and_reclaims_only_expired_windows() {
    let now = Instant::now();
    let mut limiter = Limiter::default();
    for index in 0..4096u32 {
        limiter
            .entries
            .insert(Some(IpAddr::V4((0xc0000000 + index).into())), (now, 1));
    }
    assert!(!limiter.allow(None, 60, now));
    let known = Some(IpAddr::V4(0xc0000000u32.into()));
    assert!(!limiter.allow(known, 1, now + Duration::from_secs(59)));
    assert!(limiter.allow(None, 1, now + Duration::from_secs(60)));
    assert_eq!(limiter.entries.len(), 1);
    assert!(!limiter.allow(None, 1, now + Duration::from_secs(60)));
}