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
3// 🤖 donate_test.go — the /donate checkout (donate.go): mint path, amount
4// bounds, CORS scoping, and the off-until-keyed posture.
5
6import (
7 "bytes"
8 "encoding/json"
9 "net/http"
10 "net/http/httptest"
11 "net/url"
12 "strings"
13 "testing"
14)
15
16func donateTestCloud(t *testing.T) (*httptest.Server, *cloudServer, *url.Values) {
17 t.Helper()
18 stripe, captured := fakeStripe(t)
19 srv, s := newTestCloud(t, okControl(t))
20 s.donate = newDonateCheckout("sk_test_donate", stripe.URL, "https://elevenmessenger.com")
21 return srv, s, captured
22}
23
24func postDonate(t *testing.T, srv *httptest.Server, body map[string]any) *http.Response {
25 t.Helper()
26 raw, _ := json.Marshal(body)
27 resp, err := http.Post(srv.URL+"/api/donate/checkout", "application/json", bytes.NewReader(raw))
28 if err != nil {
29 t.Fatal(err)
30 }
31 t.Cleanup(func() { resp.Body.Close() })
32 return resp
33}
34
35func TestDonateCheckoutMintsSession(t *testing.T) {
36 srv, _, captured := donateTestCloud(t)
37
38 resp := postDonate(t, srv, map[string]any{"amount_minor": 1100, "currency": "eur"})
39 if resp.StatusCode != http.StatusOK {
40 t.Fatalf("status = %d, want 200", resp.StatusCode)
41 }
42 if u, _ := decodeBody(t, resp)["url"].(string); !strings.Contains(u, "checkout.stripe.com") {
43 t.Errorf("url = %q", u)
44 }
45 if got := resp.Header.Get("Access-Control-Allow-Origin"); got != "https://elevenmessenger.com" {
46 t.Errorf("CORS origin = %q", got)
47 }
48 f := *captured
49 if f.Get("mode") != "payment" || f.Get("line_items[0][price_data][unit_amount]") != "1100" ||
50 f.Get("line_items[0][price_data][currency]") != "eur" {
51 t.Errorf("form = %v", f)
52 }
53 if !strings.HasSuffix(f.Get("success_url"), "/donate/?thanks=1") || !strings.HasSuffix(f.Get("cancel_url"), "/donate/") {
54 t.Errorf("redirects = %q / %q", f.Get("success_url"), f.Get("cancel_url"))
55 }
56 for k := range f {
57 if strings.Contains(k, "customer") || strings.Contains(k, "email") {
58 t.Errorf("donation form leaks a customer field: %s", k)
59 }
60 }
61}
62
63func TestDonateCheckoutValidation(t *testing.T) {
64 srv, _, _ := donateTestCloud(t)
65 for name, body := range map[string]map[string]any{
66 "below the €1.10 floor": {"amount_minor": 109, "currency": "eur"},
67 "zero": {"amount_minor": 0, "currency": "eur"},
68 "over the Stripe cap": {"amount_minor": 100_000_000, "currency": "eur"},
69 "bad currency": {"amount_minor": 1100, "currency": "chf"},
70 } {
71 if resp := postDonate(t, srv, body); resp.StatusCode != http.StatusBadRequest {
72 t.Errorf("%s: status = %d, want 400", name, resp.StatusCode)
73 }
74 }
75}
76
77func TestDonateCheckoutUnconfigured(t *testing.T) {
78 srv, s, _ := donateTestCloud(t)
79 s.donate = nil
80 if resp := postDonate(t, srv, map[string]any{"amount_minor": 1100, "currency": "eur"}); resp.StatusCode != http.StatusNotImplemented {
81 t.Fatalf("status = %d, want 501 when unkeyed", resp.StatusCode)
82 }
83 req, _ := http.NewRequest("OPTIONS", srv.URL+"/api/donate/checkout", nil)
84 resp, err := http.DefaultClient.Do(req)
85 if err != nil {
86 t.Fatal(err)
87 }
88 defer resp.Body.Close()
89 if resp.StatusCode != http.StatusNotImplemented {
90 t.Errorf("preflight unkeyed: %d, want 501", resp.StatusCode)
91 }
92}
93