Add CS API /keys tests (#3069)

This is slightly cheating, as the heavy lifting, with regards to key
generation, is done using `mautrix/go`.
This commit is contained in:
Till 2023-04-27 16:43:28 +02:00 committed by GitHub
parent b189edf4f4
commit c6457cd4e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 166 additions and 13 deletions

View file

@ -13,19 +13,13 @@ import (
"testing"
"time"
"github.com/matrix-org/dendrite/internal/pushrules"
"github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
"github.com/stretchr/testify/assert"
"github.com/tidwall/gjson"
"github.com/matrix-org/dendrite/appservice"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/clientapi/routing"
"github.com/matrix-org/dendrite/clientapi/threepid"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/pushrules"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/roomserver/api"
@ -37,6 +31,15 @@ import (
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/userapi"
uapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
"github.com/stretchr/testify/assert"
"github.com/tidwall/gjson"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/crypto"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
)
type userDevice struct {
@ -1630,3 +1633,128 @@ func TestPushRules(t *testing.T) {
}
})
}
// Tests the `/keys` endpoints.
// Note that this only tests the happy path.
func TestKeys(t *testing.T) {
alice := test.NewUser(t)
ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
cfg.ClientAPI.RateLimiting.Enabled = false
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
defer close()
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
accessTokens := map[*test.User]userDevice{
alice: {},
}
createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers)
// Start a TLSServer with our client mux
srv := httptest.NewTLSServer(routers.Client)
defer srv.Close()
cl, err := mautrix.NewClient(srv.URL, id.UserID(alice.ID), accessTokens[alice].accessToken)
if err != nil {
t.Fatal(err)
}
// Set the client so the self-signed certificate is trusted
cl.Client = srv.Client()
cl.DeviceID = id.DeviceID(accessTokens[alice].deviceID)
cs := crypto.NewMemoryStore(nil)
oc := crypto.NewOlmMachine(cl, nil, cs, dummyStore{})
if err = oc.Load(); err != nil {
t.Fatal(err)
}
// tests `/keys/upload`
if err = oc.ShareKeys(ctx, 0); err != nil {
t.Fatal(err)
}
// tests `/keys/device_signing/upload`
_, err = oc.GenerateAndUploadCrossSigningKeys(accessTokens[alice].password, "passphrase")
if err != nil {
t.Fatal(err)
}
// tests `/keys/query`
dev, err := oc.GetOrFetchDevice(ctx, id.UserID(alice.ID), id.DeviceID(accessTokens[alice].deviceID))
if err != nil {
t.Fatal(err)
}
// Validate that the keys returned from the server are what the client has stored
oi := oc.OwnIdentity()
if oi.SigningKey != dev.SigningKey {
t.Fatalf("expected signing key '%s', got '%s'", oi.SigningKey, dev.SigningKey)
}
if oi.IdentityKey != dev.IdentityKey {
t.Fatalf("expected identity '%s', got '%s'", oi.IdentityKey, dev.IdentityKey)
}
// tests `/keys/signatures/upload`
if err = oc.SignOwnMasterKey(); err != nil {
t.Fatal(err)
}
// tests `/keys/claim`
otks := make(map[string]map[string]string)
otks[alice.ID] = map[string]string{
accessTokens[alice].deviceID: string(id.KeyAlgorithmSignedCurve25519),
}
data, err := json.Marshal(claimKeysRequest{OneTimeKeys: otks})
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest(http.MethodPost, srv.URL+"/_matrix/client/v3/keys/claim", bytes.NewBuffer(data))
if err != nil {
t.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken)
resp, err := srv.Client().Do(req)
if err != nil {
t.Fatal(err)
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
if !gjson.GetBytes(respBody, "one_time_keys."+alice.ID+"."+string(dev.DeviceID)).Exists() {
t.Fatalf("expected one time keys for alice, but didn't find any: %s", string(respBody))
}
})
}
type claimKeysRequest struct {
// The keys to be claimed. A map from user ID, to a map from device ID to algorithm name.
OneTimeKeys map[string]map[string]string `json:"one_time_keys"`
}
type dummyStore struct{}
func (d dummyStore) IsEncrypted(roomID id.RoomID) bool {
return true
}
func (d dummyStore) GetEncryptionEvent(roomID id.RoomID) *event.EncryptionEventContent {
return &event.EncryptionEventContent{}
}
func (d dummyStore) FindSharedRooms(userID id.UserID) []id.RoomID {
return []id.RoomID{}
}