oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1package callscore
2
3import (
4 "encoding/json"
5 "errors"
6 "io"
7 "net/http"
8 "net/http/httptest"
9 "strings"
10 "testing"
11
12 "amadan.net/oficina/calls/protocol"
13)
14
15func TestShareInvitationAcceptsOnlySameServerInvitationURLs(t *testing.T) {
16 const token = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
17 for _, shape := range []string{"valid", "foreign", "room", "fragment", "refused"} {
18 t.Run(shape, func(t *testing.T) {
19 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
20 if req.Method != http.MethodPost || req.URL.Path != "/m/room/share" || req.Header.Get("Accept") != "application/json" {
21 t.Error("wrong invitation request")
22 }
23 origin := req.Header.Get("Origin")
24 link := origin + "/j/" + token
25 switch shape {
26 case "foreign":
27 link = "https://elsewhere.example/j/" + token
28 case "room":
29 link = origin + "/m/room"
30 case "fragment":
31 link += "#unexpected"
32 case "refused":
33 w.WriteHeader(http.StatusForbidden)
34 }
35 json.NewEncoder(w).Encode(map[string]string{"url": link})
36 }))
37 defer srv.Close()
38 r, err := New(srv.URL, "room", srv.Client(), func(Event) {})
39 if err != nil {
40 t.Fatal(err)
41 }
42 defer r.Close()
43 link, err := r.ShareLink()
44 if shape == "valid" {
45 if err != nil || link != srv.URL+"/j/"+token {
46 t.Fatalf("valid invitation: %v", err)
47 }
48 } else if err == nil || link != "" {
49 t.Fatal("invalid or refused invitation accepted")
50 }
51 })
52 }
53}
54
55func TestSSEFramingAndBounds(t *testing.T) {
56 for _, tc := range []struct {
57 name, input string
58 want int
59 bad bool
60 }{
61 {"comments and multiline", ": heartbeat\r\nevent: hello\r\ndata: {\"type\":\"hello\",\r\ndata: \"peer\":\"abc\"}\r\n\r\n", 1, false},
62 {"incomplete event", "data: {\"type\":\"hello\"}\n", 0, false},
63 {"malformed", "data: {bad}\n\n", 0, true},
64 {"bounded line", "data: " + strings.Repeat("x", maxResponse) + "\n\n", 0, true},
65 {"bounded event", strings.Repeat("data: "+strings.Repeat("x", 1024)+"\n", 130) + "\n", 0, true},
66 } {
67 t.Run(tc.name, func(t *testing.T) {
68 count := 0
69 err := readEvents(strings.NewReader(tc.input), func(m protocol.Message) error { count++; return nil })
70 if count != tc.want || (err != nil && !errors.Is(err, io.EOF)) != tc.bad {
71 t.Fatalf("events=%d err=%v", count, err)
72 }
73 })
74 }
75}
76func TestTransportNeverFollowsRedirectWithSession(t *testing.T) {
77 reached := false
78 foreign := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { reached = true }))
79 defer foreign.Close()
80 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, foreign.URL, 307) }))
81 defer server.Close()
82 tr, err := newTransport(server.URL, "room", server.Client())
83 if err != nil {
84 t.Fatal(err)
85 }
86 _, err = tr.request(t.Context(), http.MethodGet, "ice", nil, nil)
87 var refusal *HTTPError
88 if !errors.As(err, &refusal) || refusal.Status != 307 || reached {
89 t.Fatalf("redirect escaped: %v reached=%v", err, reached)
90 }
91}
92func TestTransportRejectsUntrustedOriginsAndPaths(t *testing.T) {
93 for _, origin := range []string{"http://calls.example.com", "https://user:pass@calls.example.com", "https://calls.example.com/path", "https://calls.example.com?token=secret", "https://calls.example.com#fragment", "file:///tmp/a"} {
94 if _, err := newTransport(origin, "room", http.DefaultClient); err == nil {
95 t.Fatalf("accepted %s", origin)
96 }
97 }
98 for _, room := range []string{"../other", "a/b", "a?b", "", "a%2fb"} {
99 if _, err := newTransport("https://calls.example.com", room, http.DefaultClient); err == nil {
100 t.Fatalf("accepted room %q", room)
101 }
102 }
103}
104