Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create user room key if needed #3108

Merged
merged 6 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions roomserver/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"context"
"crypto/ed25519"

"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec"
Expand Down Expand Up @@ -66,6 +67,9 @@ type RoomserverInternalAPI interface {
req *QueryAuthChainRequest,
res *QueryAuthChainResponse,
) error

// GetOrCreateUserRoomPrivateKey gets the user room key for the specified user. If no key exists yet, a new one is created.
GetOrCreateUserRoomPrivateKey(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (ed25519.PrivateKey, error)
}

type InputRoomEventsAPI interface {
Expand Down
21 changes: 21 additions & 0 deletions roomserver/internal/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

import (
"context"
"crypto/ed25519"

"github.com/getsentry/sentry-go"
"github.com/matrix-org/gomatrixserverlib"
Expand Down Expand Up @@ -270,3 +271,23 @@ func (r *RoomserverInternalAPI) PerformForget(
) error {
return r.Forgetter.PerformForget(ctx, req, resp)
}

// GetOrCreateUserRoomPrivateKey gets the user room key for the specified user. If no key exists yet, a new one is created.
func (r *RoomserverInternalAPI) GetOrCreateUserRoomPrivateKey(ctx context.Context, userID spec.UserID, roomID spec.RoomID) (ed25519.PrivateKey, error) {
key, err := r.DB.SelectUserRoomPrivateKey(ctx, userID, roomID)
if err != nil {
return nil, err
}
// no key found, create one
if len(key) == 0 {
_, key, err = ed25519.GenerateKey(nil)
if err != nil {
return nil, err
}
key, err = r.DB.InsertUserRoomPrivatePublicKey(ctx, userID, roomID, key)
if err != nil {
return nil, err
}
}
return key, nil
}
25 changes: 24 additions & 1 deletion roomserver/internal/perform/perform_create_room.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,30 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
SendAsServer: api.DoNotSendToOtherServers,
})
}
if err = api.SendInputRoomEvents(ctx, c.RSAPI, userID.Domain(), inputs, false); err != nil {

// first send the `m.room.create` event, so we have a roomNID
if err = api.SendInputRoomEvents(ctx, c.RSAPI, userID.Domain(), inputs[:1], false); err != nil {
util.GetLogger(ctx).WithError(err).Error("roomserverAPI.SendInputRoomEvents failed")
return "", &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}

// create user room key if needed
if createRequest.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
_, err = c.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, userID, roomID)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("GetOrCreateUserRoomPrivateKey failed")
return "", &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}
}

// send the remaining events
if err = api.SendInputRoomEvents(ctx, c.RSAPI, userID.Domain(), inputs[1:], false); err != nil {
util.GetLogger(ctx).WithError(err).Error("roomserverAPI.SendInputRoomEvents failed")
return "", &util.JSONResponse{
Code: http.StatusInternalServerError,
Expand Down
8 changes: 8 additions & 0 deletions roomserver/internal/perform/perform_invite.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ func (r *Inviter) PerformInvite(
inviteEvent = event
}

// if we invited a local user, we can also create a user room key, if it doesn't exist yet.
if isTargetLocal && event.Version() == gomatrixserverlib.RoomVersionPseudoIDs {
_, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *invitedUser, *validRoomID)
if err != nil {
return fmt.Errorf("failed to get user room private key: %w", err)
}
}

// Send the invite event to the roomserver input stream. This will
// notify existing users in the room about the invite, update the
// membership table and ensure that the event is ready and available
Expand Down
9 changes: 9 additions & 0 deletions roomserver/internal/perform/perform_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,15 @@ func (r *Joiner) performJoinRoomByID(

switch err.(type) {
case nil:
// create user room key if needed
if buildRes.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
_, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *userID, *roomID)
if err != nil {
logrus.WithError(err).Error("GetOrCreateUserRoomPrivateKey failed")
return "", "", fmt.Errorf("failed to get user room private key: %w", err)
}
}

// The room join is local. Send the new join event into the
// roomserver. First of all check that the user isn't already
// a member of the room. This is best-effort (as in we won't
Expand Down
2 changes: 1 addition & 1 deletion roomserver/storage/shared/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,7 @@ func (d *Database) SelectUserRoomPrivateKey(ctx context.Context, userID spec.Use
return rErr
}
if roomInfo == nil {
return nil
return eventutil.ErrRoomNoExists{}
}

key, sErr = d.UserRoomKeyTable.SelectUserRoomPrivateKey(ctx, txn, stateKeyNID, roomInfo.RoomNID)
Expand Down