Files
scrabble-game/gateway/internal/connectsrv/peerip_test.go
T
Ilia Denisov 645df52c0b
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 32s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m8s
Round-6 follow-up: UX polish + client-IP fix
- Client IP: the compose caddy trusts X-Forwarded-For from private-range
  upstreams (trusted_proxies private_ranges), so the real client IP survives
  the host-caddy hop (it was logging the docker caddy hop 172.18.0.x for chat
  moderation and bucketing the gateway per-IP rate limiter on it). Correct and
  spoof-safe in both contours (prod has no host caddy); peerIP unit-tested.
- Ad banner gated off behind a compile-time SHOW_AD_BANNER=false (the if-branch,
  the AdBanner import and banner.ts are tree-shaken out of the prod bundle).
- Landing: the Telegram entry is just the 64px logo (clickable, no button/text).
- TG-fullscreen header: title + menu centred as a pair (hamburger right of the
  title), pinned to the bottom of the TG nav band.
- Edge-swipe back (Screen): a left-edge rightward drag navigates to back
  (touch/pen only, armed from <=24px; skipped inside Telegram).
- Chat soft-keyboard: a bottom-sheet Modal lifted above the keyboard by a
  visualViewport-driven transform (compositor-only, no page/sheet relayout).
  iOS-specific, needs on-device tuning; native resize=none awaits Capacitor.
- Tests: e2e for the in-game '✓ in friends' item and a board→board tile
  relocation; codec units for last_activity_unix + OutgoingRequestList.

Deferred to the next PR (agreed): #4 enrich the your-turn/game-end push; #5 hide
finished games from the lobby.
2026-06-08 21:31:44 +02:00

36 lines
1.1 KiB
Go

package connectsrv
import (
"net/http"
"testing"
)
// TestPeerIP covers the client-IP extraction the chat-moderation IP and the per-IP rate
// limiter both rely on: the first X-Forwarded-For hop (the real client, once Caddy is
// configured to trust its upstream), falling back to the connection peer (Stage 17).
func TestPeerIP(t *testing.T) {
tests := []struct {
name string
addr string
xff string
want string
}{
{"xff single", "10.0.0.1:5000", "203.0.113.7", "203.0.113.7"},
{"xff client then proxies", "10.0.0.1:5000", "203.0.113.7, 172.18.0.3", "203.0.113.7"},
{"xff trims spaces", "10.0.0.1:5000", " 203.0.113.9 , 10.0.0.2", "203.0.113.9"},
{"no xff uses peer host", "203.0.113.5:42000", "", "203.0.113.5"},
{"no xff no port", "203.0.113.6", "", "203.0.113.6"},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
h := http.Header{}
if tc.xff != "" {
h.Set("X-Forwarded-For", tc.xff)
}
if got := peerIP(tc.addr, h); got != tc.want {
t.Errorf("peerIP(%q, xff=%q) = %q, want %q", tc.addr, tc.xff, got, tc.want)
}
})
}
}