tinyrelayfile
tinyrelay/tinyclient/remote_actor_test.go/

tinyclient/remote_actor_test.go raw
1package tinyclient
2
3import (
4 "context"
5 "encoding/json"
6 "net/http"
7 "net/http/httptest"
8 "strings"
9 "sync/atomic"
10 "testing"
11)
12
13type actorReadBackend struct{ actorFeedBackend }
14
15func (b *actorReadBackend) ListRooms(_ context.Context, actor, _ string, _ int) (RoomList, error) {
16 return RoomList{Rooms: []RoomSummary{{ID: "public-article", Name: actor}}}, nil
17}
18func (b *actorReadBackend) ReadRoom(_ context.Context, actor, _, _ string, _ int) (RoomPage, error) {
19 return RoomPage{Room: RoomSummary{ID: "public-article", Name: actor}}, nil
20}
21func (b *actorReadBackend) ReadThread(_ context.Context, actor, _, _, _ string, _ int) (RoomPage, error) {
22 return RoomPage{Room: RoomSummary{ID: "public-article", Name: actor}}, nil
23}
24func (b *actorReadBackend) ReadChatActivity(_ context.Context, actor, _, _ string) (any, error) {
25 return map[string]string{"id": "public-article", "actor": actor}, nil
26}
27
28func TestRemoteReadsPreserveRequestedActor(t *testing.T) {
29 owner, other := strings.Repeat("a", 64), strings.Repeat("b", 64)
30 backend := &actorReadBackend{actorFeedBackend{fakeBackend{policy: DefaultPolicy(owner)}}}
31 app, err := New(backend, Options{Actor: func(r *http.Request) (string, error) {
32 if cookie, err := r.Cookie("tiny_session"); err == nil && cookie.Value == "valid-session" {
33 return owner, nil
34 }
35 return "", nil
36 }})
37 if err != nil {
38 t.Fatal(err)
39 }
40 var reads atomic.Int32
41 upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
42 reads.Add(1)
43 app.BackendHandler().ServeHTTP(w, r)
44 }))
45 defer upstream.Close()
46 handler, err := NewRemote(RemoteOptions{BackendURL: upstream.URL, PublicURL: backend.URL()})
47 if err != nil {
48 t.Fatal(err)
49 }
50 for _, tc := range []struct {
51 name, cookie, actor string
52 denied bool
53 }{
54 {name: "authenticated", cookie: "tiny_session=valid-session", actor: owner},
55 {name: "anonymous read with session", cookie: "tiny_session=valid-session"},
56 {name: "mismatched actor", cookie: "tiny_session=valid-session", actor: other, denied: true},
57 {name: "anonymous"},
58 {name: "forged actor without session", actor: owner, denied: true},
59 {name: "forged actor with invalid session", cookie: "tiny_session=invalid", actor: owner, denied: true},
60 } {
61 t.Run(tc.name, func(t *testing.T) {
62 b := &requestBackend{remote: handler.(*remoteClient), cookie: tc.cookie}
63 if err := b.remote.read(context.Background(), b.cookie, nil, &b.snapshot); err != nil {
64 t.Fatal(err)
65 }
66 for name, read := range map[string]func() (any, error){
67 "query": func() (any, error) { return b.Query(context.Background(), "queryevents", nil, tc.actor) },
68 "rooms": func() (any, error) { return (&remoteRooms{b}).ListRooms(context.Background(), tc.actor, "", 10) },
69 "room": func() (any, error) {
70 return (&remoteRooms{b}).ReadRoom(context.Background(), tc.actor, "build", "", 10)
71 },
72 "thread": func() (any, error) {
73 return (&remoteRooms{b}).ReadThread(context.Background(), tc.actor, "build", "root", "", 10)
74 },
75 "activity": func() (any, error) { return b.ReadChatActivity(context.Background(), tc.actor, "build", "root") },
76 } {
77 t.Run(name, func(t *testing.T) {
78 before := reads.Load()
79 result, err := read()
80 if tc.denied {
81 if err == nil || reads.Load() != before {
82 t.Fatalf("mismatched actor must fail before forwarding: err=%v upstream reads=%d", err, reads.Load()-before)
83 }
84 return
85 }
86 if err != nil {
87 t.Fatal(err)
88 }
89 raw, err := json.Marshal(result)
90 if err != nil {
91 t.Fatal(err)
92 }
93 private := owner
94 if name == "query" {
95 private = "session-only-article"
96 }
97 if !strings.Contains(string(raw), "public-article") || strings.Contains(string(raw), private) != (tc.actor == owner) {
98 t.Fatalf("read used wrong actor: %s", raw)
99 }
100 })
101 }
102 })
103 }
104}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs