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 "encoding/json"
5 "net/http"
6 "strconv"
7 "strings"
8 "testing"
9 "time"
10)
11
12func enrolStatus(t *testing.T, ts string, nonce string) bool {
13 t.Helper()
14 resp, err := http.Get(ts + "/api/enroll-status?nonce=" + nonce)
15 if err != nil {
16 t.Fatalf("status GET: %v", err)
17 }
18 defer resp.Body.Close()
19 if resp.StatusCode != http.StatusOK {
20 t.Fatalf("status code = %d", resp.StatusCode)
21 }
22 if got := resp.Header.Get("Access-Control-Allow-Origin"); got != "*" {
23 t.Fatalf("ACAO = %q, want *", got)
24 }
25 var body struct{ Done bool }
26 if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
27 t.Fatalf("decode: %v", err)
28 }
29 return body.Done
30}
31
32func TestEnrolStatusRoundTrip(t *testing.T) {
33 ts, _ := newTestServer(t)
34 defer ts.Close()
35
36 const nonce = "abcdefgh1234"
37 if enrolStatus(t, ts.URL, nonce) {
38 t.Fatal("unknown nonce reported done")
39 }
40
41 resp, err := http.Post(ts.URL+"/api/enroll-done", "application/json",
42 strings.NewReader(`{"nonce":"`+nonce+`"}`))
43 if err != nil {
44 t.Fatalf("done POST: %v", err)
45 }
46 resp.Body.Close()
47 if resp.StatusCode != http.StatusNoContent {
48 t.Fatalf("done POST code = %d", resp.StatusCode)
49 }
50
51 if !enrolStatus(t, ts.URL, nonce) {
52 t.Fatal("marked nonce not reported done")
53 }
54 if enrolStatus(t, ts.URL, "differentnonce") {
55 t.Fatal("other nonce reported done")
56 }
57}
58
59func TestEnrolDoneRejectsBadNonces(t *testing.T) {
60 ts, _ := newTestServer(t)
61 defer ts.Close()
62
63 for _, body := range []string{`{}`, `{"nonce":"short"}`, `{"nonce":"` + strings.Repeat("x", 200) + `"}`, `not json`} {
64 resp, err := http.Post(ts.URL+"/api/enroll-done", "application/json", strings.NewReader(body))
65 if err != nil {
66 t.Fatalf("POST: %v", err)
67 }
68 resp.Body.Close()
69 if resp.StatusCode != http.StatusBadRequest {
70 t.Fatalf("body %q: code = %d, want 400", body, resp.StatusCode)
71 }
72 }
73}
74
75func TestEnrolMarksExpiry(t *testing.T) {
76 m := newEnrolMarks()
77 now := time.Now()
78 m.now = func() time.Time { return now }
79 m.mark("nonce-that-expires")
80 if !m.check("nonce-that-expires") {
81 t.Fatal("fresh mark not found")
82 }
83 now = now.Add(enrolMarkTTL + time.Minute)
84 if m.check("nonce-that-expires") {
85 t.Fatal("expired mark still reported done")
86 }
87 // And the next mark purges it from the map entirely.
88 m.mark("another-nonce")
89 m.mu.Lock()
90 _, still := m.done["nonce-that-expires"]
91 m.mu.Unlock()
92 if still {
93 t.Fatal("expired mark not purged")
94 }
95}
96
97func TestEnrolMarksCap(t *testing.T) {
98 m := newEnrolMarks()
99 for i := 0; i < enrolMarkCap; i++ {
100 m.mark("padpadpad" + strconv.Itoa(i))
101 }
102 m.mark("overflow-nonce")
103 if m.check("overflow-nonce") {
104 t.Fatal("mark accepted past the cap")
105 }
106}
107