diff --git a/relayapi/relayapi_test.go b/relayapi/relayapi_test.go index e43c4b4a8..c1dd8bf06 100644 --- a/relayapi/relayapi_test.go +++ b/relayapi/relayapi_test.go @@ -15,11 +15,19 @@ package relayapi_test import ( + "crypto/ed25519" + "encoding/hex" + "encoding/json" + "net/http" + "net/http/httptest" "testing" + "github.com/gorilla/mux" + "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/relayapi" "github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test/testrig" + "github.com/matrix-org/gomatrixserverlib" "github.com/stretchr/testify/assert" ) @@ -60,6 +68,41 @@ func TestCreateInvalidRelayPublicRoutesPanics(t *testing.T) { }) } +func createGetRelayTxnHTTPRequest(userID string) *http.Request { + _, sk, _ := ed25519.GenerateKey(nil) + keyID := signing.KeyID + pk := sk.Public().(ed25519.PublicKey) + serverName := gomatrixserverlib.ServerName(hex.EncodeToString(pk)) + req := gomatrixserverlib.NewFederationRequest("GET", serverName, "remote", "/_matrix/federation/v1/relay_txn/"+userID) + content := gomatrixserverlib.RelayEntry{EntryID: 0} + req.SetContent(content) + req.Sign(serverName, gomatrixserverlib.KeyID(keyID), sk) + httpreq, _ := req.HTTPRequest() + vars := map[string]string{"userID": userID} + httpreq = mux.SetURLVars(httpreq, vars) + return httpreq +} + +type sendRelayContent struct { + PDUs []json.RawMessage `json:"pdus"` + EDUs []gomatrixserverlib.EDU `json:"edus"` +} + +func createSendRelayTxnHTTPRequest(txnID string, userID string) *http.Request { + _, sk, _ := ed25519.GenerateKey(nil) + keyID := signing.KeyID + pk := sk.Public().(ed25519.PublicKey) + serverName := gomatrixserverlib.ServerName(hex.EncodeToString(pk)) + req := gomatrixserverlib.NewFederationRequest("PUT", serverName, "remote", "/_matrix/federation/v1/send_relay/"+txnID+"/"+userID) + content := sendRelayContent{} + req.SetContent(content) + req.Sign(serverName, gomatrixserverlib.KeyID(keyID), sk) + httpreq, _ := req.HTTPRequest() + vars := map[string]string{"userID": userID, "txnID": txnID} + httpreq = mux.SetURLVars(httpreq, vars) + return httpreq +} + func TestCreateRelayPublicRoutes(t *testing.T) { base, close := testrig.CreateBaseDendrite(t, test.DBTypeSQLite) defer close() @@ -67,5 +110,43 @@ func TestCreateRelayPublicRoutes(t *testing.T) { relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil) assert.NotNil(t, relayAPI) - relayapi.AddPublicRoutes(base, nil, relayAPI) + serverKeyAPI := &signing.YggdrasilKeys{} + keyRing := serverKeyAPI.KeyRing() + relayapi.AddPublicRoutes(base, keyRing, relayAPI) + + testCases := []struct { + name string + req *http.Request + wantCode int + wantJoinedRooms []string + }{ + { + name: "relay_txn invalid user id", + req: createGetRelayTxnHTTPRequest("user:local"), + wantCode: 400, + }, + { + name: "relay_txn valid user id", + req: createGetRelayTxnHTTPRequest("@user:local"), + wantCode: 200, + }, + { + name: "send_relay invalid user id", + req: createSendRelayTxnHTTPRequest("123", "user:local"), + wantCode: 400, + }, + { + name: "send_relay valid user id", + req: createSendRelayTxnHTTPRequest("123", "@user:local"), + wantCode: 200, + }, + } + + for _, tc := range testCases { + w := httptest.NewRecorder() + base.PublicFederationAPIMux.ServeHTTP(w, tc.req) + if w.Code != tc.wantCode { + t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode) + } + } } diff --git a/relayapi/routing/routing.go b/relayapi/routing/routing.go index 16fea7742..6df0cdc5f 100644 --- a/relayapi/routing/routing.go +++ b/relayapi/routing/routing.go @@ -29,11 +29,6 @@ import ( "github.com/matrix-org/util" ) -const ( - SendRelayTransactionRouteName = "SendRelayTransaction" - GetRelayTransactionRouteName = "GetRelayTransaction" -) - // Setup registers HTTP handlers with the given ServeMux. // The provided publicAPIMux MUST have `UseEncodedPath()` enabled or else routes will incorrectly // path unescape twice (once from the router, once from MakeRelayAPI). We need to have this enabled @@ -65,7 +60,7 @@ func Setup( *userID, ) }, - )).Methods(http.MethodPut, http.MethodOptions).Name(SendRelayTransactionRouteName) + )).Methods(http.MethodPut, http.MethodOptions) v1fedmux.Handle("/relay_txn/{userID}", MakeRelayAPI( "get_relay_transaction", "", cfg.Matrix.IsLocalServerName, keys, @@ -79,7 +74,7 @@ func Setup( } return GetTransactionFromRelay(httpReq, request, relayAPI, *userID) }, - )).Methods(http.MethodGet, http.MethodOptions).Name(GetRelayTransactionRouteName) + )).Methods(http.MethodGet, http.MethodOptions) } // MakeRelayAPI makes an http.Handler that checks matrix relay authentication. diff --git a/relayapi/routing/routing_test.go b/relayapi/routing/routing_test.go deleted file mode 100644 index 594709788..000000000 --- a/relayapi/routing/routing_test.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2022 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package routing_test - -import ( - "crypto/ed25519" - "encoding/hex" - "encoding/json" - "net/http/httptest" - "testing" - - "github.com/gorilla/mux" - "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" - "github.com/matrix-org/dendrite/internal/httputil" - "github.com/matrix-org/dendrite/relayapi" - "github.com/matrix-org/dendrite/relayapi/internal" - "github.com/matrix-org/dendrite/relayapi/routing" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/test" - "github.com/matrix-org/dendrite/test/testrig" - "github.com/matrix-org/gomatrixserverlib" - "github.com/stretchr/testify/assert" -) - -type sendRelayContent struct { - PDUs []json.RawMessage `json:"pdus"` - EDUs []gomatrixserverlib.EDU `json:"edus"` -} - -func TestHandleSendRelay(t *testing.T) { - base, close := testrig.CreateBaseDendrite(t, test.DBTypeSQLite) - defer close() - - fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() - cfg := config.FederationAPI{ - Matrix: &config.Global{ - SigningIdentity: gomatrixserverlib.SigningIdentity{ - ServerName: "relay", - }, - }, - } - relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil) - serverKeyAPI := &signing.YggdrasilKeys{} - keyRing := serverKeyAPI.KeyRing() - r, ok := relayAPI.(*internal.RelayInternalAPI) - if !ok { - panic("This is a programming error.") - } - routing.Setup(fedMux, &cfg, r, keyRing) - - handler := fedMux.Get(routing.SendRelayTransactionRouteName).GetHandler().ServeHTTP - _, sk, _ := ed25519.GenerateKey(nil) - keyID := signing.KeyID - pk := sk.Public().(ed25519.PublicKey) - serverName := gomatrixserverlib.ServerName(hex.EncodeToString(pk)) - req := gomatrixserverlib.NewFederationRequest("PUT", serverName, "remote", "/send_relay/1234/@user:local") - content := sendRelayContent{} - err := req.SetContent(content) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - req.Sign(serverName, gomatrixserverlib.KeyID(keyID), sk) - httpReq, err := req.HTTPRequest() - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - vars := map[string]string{"userID": "@user:local", "txnID": "1234"} - w := httptest.NewRecorder() - httpReq = mux.SetURLVars(httpReq, vars) - handler(w, httpReq) - - res := w.Result() - assert.Equal(t, 200, res.StatusCode) -} - -func TestHandleSendRelayBadUserID(t *testing.T) { - base, close := testrig.CreateBaseDendrite(t, test.DBTypeSQLite) - defer close() - - fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() - cfg := config.FederationAPI{ - Matrix: &config.Global{ - SigningIdentity: gomatrixserverlib.SigningIdentity{ - ServerName: "relay", - }, - }, - } - relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil) - serverKeyAPI := &signing.YggdrasilKeys{} - keyRing := serverKeyAPI.KeyRing() - r, ok := relayAPI.(*internal.RelayInternalAPI) - if !ok { - panic("This is a programming error.") - } - routing.Setup(fedMux, &cfg, r, keyRing) - - handler := fedMux.Get(routing.SendRelayTransactionRouteName).GetHandler().ServeHTTP - _, sk, _ := ed25519.GenerateKey(nil) - keyID := signing.KeyID - pk := sk.Public().(ed25519.PublicKey) - serverName := gomatrixserverlib.ServerName(hex.EncodeToString(pk)) - req := gomatrixserverlib.NewFederationRequest("PUT", serverName, "remote", "/send_relay/1234/user") - content := sendRelayContent{} - err := req.SetContent(content) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - req.Sign(serverName, gomatrixserverlib.KeyID(keyID), sk) - httpReq, err := req.HTTPRequest() - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - vars := map[string]string{"userID": "user", "txnID": "1234"} - w := httptest.NewRecorder() - httpReq = mux.SetURLVars(httpReq, vars) - handler(w, httpReq) - - res := w.Result() - assert.NotEqual(t, 200, res.StatusCode) -} - -func TestHandleRelayTransaction(t *testing.T) { - base, close := testrig.CreateBaseDendrite(t, test.DBTypeSQLite) - defer close() - - fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() - cfg := config.FederationAPI{ - Matrix: &config.Global{ - SigningIdentity: gomatrixserverlib.SigningIdentity{ - ServerName: "relay", - }, - }, - } - relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil) - serverKeyAPI := &signing.YggdrasilKeys{} - keyRing := serverKeyAPI.KeyRing() - r, ok := relayAPI.(*internal.RelayInternalAPI) - if !ok { - panic("This is a programming error.") - } - routing.Setup(fedMux, &cfg, r, keyRing) - - handler := fedMux.Get(routing.GetRelayTransactionRouteName).GetHandler().ServeHTTP - _, sk, _ := ed25519.GenerateKey(nil) - keyID := signing.KeyID - pk := sk.Public().(ed25519.PublicKey) - serverName := gomatrixserverlib.ServerName(hex.EncodeToString(pk)) - req := gomatrixserverlib.NewFederationRequest("GET", serverName, "remote", "/relay_txn/@user:local") - content := gomatrixserverlib.RelayEntry{EntryID: 0} - err := req.SetContent(content) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - req.Sign(serverName, gomatrixserverlib.KeyID(keyID), sk) - httpReq, err := req.HTTPRequest() - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - vars := map[string]string{"userID": "@user:local"} - w := httptest.NewRecorder() - httpReq = mux.SetURLVars(httpReq, vars) - handler(w, httpReq) - - res := w.Result() - assert.Equal(t, 200, res.StatusCode) -} - -func TestHandleRelayTxnBadUserID(t *testing.T) { - base, close := testrig.CreateBaseDendrite(t, test.DBTypeSQLite) - defer close() - - fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() - cfg := config.FederationAPI{ - Matrix: &config.Global{ - SigningIdentity: gomatrixserverlib.SigningIdentity{ - ServerName: "relay", - }, - }, - } - relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil) - serverKeyAPI := &signing.YggdrasilKeys{} - keyRing := serverKeyAPI.KeyRing() - r, ok := relayAPI.(*internal.RelayInternalAPI) - if !ok { - panic("This is a programming error.") - } - routing.Setup(fedMux, &cfg, r, keyRing) - - handler := fedMux.Get(routing.GetRelayTransactionRouteName).GetHandler().ServeHTTP - _, sk, _ := ed25519.GenerateKey(nil) - keyID := signing.KeyID - pk := sk.Public().(ed25519.PublicKey) - serverName := gomatrixserverlib.ServerName(hex.EncodeToString(pk)) - req := gomatrixserverlib.NewFederationRequest("GET", serverName, "remote", "/relay_txn/user") - content := gomatrixserverlib.RelayEntry{EntryID: 0} - err := req.SetContent(content) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - req.Sign(serverName, gomatrixserverlib.KeyID(keyID), sk) - httpReq, err := req.HTTPRequest() - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - vars := map[string]string{"userID": "user"} - w := httptest.NewRecorder() - httpReq = mux.SetURLVars(httpReq, vars) - handler(w, httpReq) - - res := w.Result() - assert.NotEqual(t, 200, res.StatusCode) -}