eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "fmt"
5 "net/http"
6 "strings"
7 "testing"
8)
9
10// validatePushEndpoint is the ingest guard: only plain https URLs with a host.
11func TestValidatePushEndpoint(t *testing.T) {
12 bad := []string{
13 "", // empty
14 "http://fcm.googleapis.com/x", // not https
15 "http://169.254.169.254/latest", // http + cloud metadata
16 "https://", // no host
17 "ftp://example.com/x", // wrong scheme
18 "file:///etc/passwd", // wrong scheme
19 "http://[::1]/x", // not https (loopback)
20 }
21 for _, e := range bad {
22 if err := validatePushEndpoint(e); err == nil {
23 t.Errorf("validatePushEndpoint(%q) = nil, want error", e)
24 }
25 }
26 good := []string{
27 "https://fcm.googleapis.com/fcm/send/abc123",
28 "https://updates.push.services.mozilla.com/wpush/v2/xyz",
29 "https://web.push.apple.com/QABC",
30 }
31 for _, e := range good {
32 if err := validatePushEndpoint(e); err != nil {
33 t.Errorf("validatePushEndpoint(%q) = %v, want nil", e, err)
34 }
35 }
36}
37
38// guardDialControl is the enforcement layer: it blocks the resolved IP at dial
39// time, so even a stored endpoint (and any redirect hop) can't reach the
40// server's own network. This is what actually stops the SSRF.
41func TestGuardDialControlBlocksNonPublic(t *testing.T) {
42 saved := allowPrivatePreviewHosts
43 allowPrivatePreviewHosts = false
44 defer func() { allowPrivatePreviewHosts = saved }()
45
46 blocked := []string{
47 "127.0.0.1:443", // loopback
48 "169.254.169.254:443", // cloud metadata (link-local)
49 "10.0.0.5:6379", // private (internal Redis, etc.)
50 "192.168.1.1:443", // private
51 "[::1]:443", // IPv6 loopback
52 "100.64.0.1:443", // CGNAT
53 "0.0.0.0:443", // unspecified
54 }
55 for _, a := range blocked {
56 if err := guardDialControl("tcp", a, nil); err == nil {
57 t.Errorf("guardDialControl(%q) = nil, want blocked", a)
58 }
59 }
60 if err := guardDialControl("tcp", "8.8.8.8:443", nil); err != nil {
61 t.Errorf("guardDialControl(public) = %v, want nil", err)
62 }
63}
64
65// End to end through the handler: a valid participant token does NOT let a member
66// register an internal/non-https push endpoint (proves the validator is wired in).
67func TestSubscribePushRejectsBadEndpoint(t *testing.T) {
68 ts, srv := newTestServer(t)
69 tok := mintDeviceToken(t, srv.db, "push-test")
70 post := func(endpoint string) int {
71 body := fmt.Sprintf(`{"token":%q,"subscription":{"endpoint":%q,"keys":{"p256dh":"p","auth":"a"}}}`, tok, endpoint)
72 resp, err := http.Post(ts.URL+"/api/push/subscribe", "application/json", strings.NewReader(body))
73 if err != nil {
74 t.Fatalf("post: %v", err)
75 }
76 resp.Body.Close()
77 return resp.StatusCode
78 }
79 if got := post("http://169.254.169.254/latest/meta-data/"); got != http.StatusBadRequest {
80 t.Fatalf("http metadata endpoint with valid token: want 400, got %d", got)
81 }
82 if got := post("https://fcm.googleapis.com/fcm/send/abc123"); got != http.StatusOK {
83 t.Fatalf("valid https endpoint: want 200, got %d", got)
84 }
85}
86