| 1 | package daemon |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "io" |
| 6 | "net/http" |
| 7 | "net/http/httptest" |
| 8 | "strings" |
| 9 | "testing" |
| 10 | ) |
| 11 | |
| 12 | func TestChatPreferencesWritesBindAccountAndSignedBody(t *testing.T) { |
| 13 | app, tenant := testTenant(t) |
| 14 | owner := tenant.Policy().Owner |
| 15 | if err := tenant.store.PutSetting(context.Background(), chatPreferenceKey(owner), chatPreferences{SharePresence: true}); err != nil { |
| 16 | t.Fatal(err) |
| 17 | } |
| 18 | other := strings.Repeat("0" , 63) + "2" |
| 19 | read := httptest.NewRequest("GET" , "http://relay.test/chat/preferences?actor=" +owner, nil) |
| 20 | signRequestWithSecret(t, read, "" , other) |
| 21 | result := httptest.NewRecorder() |
| 22 | app.ServeHTTP(result, read) |
| 23 | if result.Code != 200 || result.Body.String() != `{"share_presence":false}` { |
| 24 | t.Fatalf("cross-account read: %d %s" , result.Code, result.Body.String()) |
| 25 | } |
| 26 | for _, test := range []struct { |
| 27 | name, body string |
| 28 | signed bool |
| 29 | code int |
| 30 | }{ |
| 31 | {"unsigned" , `{"share_presence":false}` , false, 401}, |
| 32 | {"actor injection" , `{"actor":"` + owner + `","share_presence":false}` , true, 400}, |
| 33 | {"trailing object" , `{"share_presence":false}{}` , true, 400}, |
| 34 | {"invalid type" , `{"share_presence":"true"}` , true, 400}, |
| 35 | } { |
| 36 | t.Run(test.name, func(t *testing.T) { |
| 37 | req := httptest.NewRequest("POST" , "http://relay.test/chat/preferences" , strings.NewReader(test.body)) |
| 38 | if test.signed { |
| 39 | signRequestWithSecret(t, req, test.body, other) |
| 40 | } |
| 41 | res := httptest.NewRecorder() |
| 42 | app.ServeHTTP(res, req) |
| 43 | if res.Code != test.code { |
| 44 | t.Fatalf("status %d: %s" , res.Code, res.Body.String()) |
| 45 | } |
| 46 | }) |
| 47 | } |
| 48 | altered := httptest.NewRequest("POST" , "http://relay.test/chat/preferences" , strings.NewReader(`{"share_presence":true}` )) |
| 49 | signRequest(t, altered, `{"share_presence":true}` ) |
| 50 | altered.Body = io.NopCloser(strings.NewReader(`{"share_presence":false}` )) |
| 51 | rejected := httptest.NewRecorder() |
| 52 | app.ServeHTTP(rejected, altered) |
| 53 | if rejected.Code != http.StatusUnauthorized { |
| 54 | t.Fatalf("altered signed body: %d" , rejected.Code) |
| 55 | } |
| 56 | if !tenant.chatSharePresence(context.Background(), owner) { |
| 57 | t.Fatal("another account or invalid signature changed owner preference" ) |
| 58 | } |
| 59 | } |