Handle cryptoID invites & leaves

This commit is contained in:
Devon Hudson 2023-11-06 16:54:29 -07:00
parent 7f7ac0f4fe
commit 227493cc5d
No known key found for this signature in database
GPG key ID: CD06B18E77F6A628
15 changed files with 139 additions and 86 deletions

View file

@ -15,6 +15,7 @@
package routing package routing
import ( import (
"encoding/json"
"net/http" "net/http"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
@ -23,11 +24,16 @@ import (
"github.com/matrix-org/util" "github.com/matrix-org/util"
) )
type leaveRoomCryptoIDsResponse struct {
PDU json.RawMessage `json:"pdu"`
}
func LeaveRoomByID( func LeaveRoomByID(
req *http.Request, req *http.Request,
device *api.Device, device *api.Device,
rsAPI roomserverAPI.ClientRoomserverAPI, rsAPI roomserverAPI.ClientRoomserverAPI,
roomID string, roomID string,
cryptoIDs bool,
) util.JSONResponse { ) util.JSONResponse {
userID, err := spec.NewUserID(device.UserID, true) userID, err := spec.NewUserID(device.UserID, true)
if err != nil { if err != nil {
@ -45,7 +51,8 @@ func LeaveRoomByID(
leaveRes := roomserverAPI.PerformLeaveResponse{} leaveRes := roomserverAPI.PerformLeaveResponse{}
// Ask the roomserver to perform the leave. // Ask the roomserver to perform the leave.
if err := rsAPI.PerformLeave(req.Context(), &leaveReq, &leaveRes); err != nil { leaveEvent, err := rsAPI.PerformLeave(req.Context(), &leaveReq, &leaveRes, cryptoIDs)
if err != nil {
if leaveRes.Code != 0 { if leaveRes.Code != 0 {
return util.JSONResponse{ return util.JSONResponse{
Code: leaveRes.Code, Code: leaveRes.Code,
@ -60,6 +67,8 @@ func LeaveRoomByID(
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: struct{}{}, JSON: leaveRoomCryptoIDsResponse{
PDU: json.RawMessage(leaveEvent.JSON()),
},
} }
} }

View file

@ -443,7 +443,6 @@ func Setup(
return resp.(util.JSONResponse) return resp.(util.JSONResponse)
}, httputil.WithAllowGuests()), }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions) ).Methods(http.MethodPost, http.MethodOptions)
// TODO: update for cryptoIDs
v3mux.Handle("/rooms/{roomID}/leave", v3mux.Handle("/rooms/{roomID}/leave",
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
if r := rateLimits.Limit(req, device); r != nil { if r := rateLimits.Limit(req, device); r != nil {
@ -454,7 +453,22 @@ func Setup(
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
return LeaveRoomByID( return LeaveRoomByID(
req, device, rsAPI, vars["roomID"], req, device, rsAPI, vars["roomID"], false,
)
}, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
unstableMux.Handle("/org.matrix.msc_cryptoids/rooms/{roomID}/leave",
httputil.MakeAuthAPI("membership", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
logrus.Info("Processing request to /org.matrix.msc_cryptoids/rooms/{roomID}/leave")
if r := rateLimits.Limit(req, device); r != nil {
return *r
}
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
if err != nil {
return util.ErrorResponse(err)
}
return LeaveRoomByID(
req, device, rsAPI, vars["roomID"], true,
) )
}, httputil.WithAllowGuests()), }, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions) ).Methods(http.MethodPost, http.MethodOptions)

View file

@ -32,6 +32,7 @@ import (
"github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/syncapi/synctypes"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
@ -171,7 +172,7 @@ func SendEvent(
} }
} }
e, resErr := generateSendEvent(req.Context(), r, device, roomID, eventType, stateKey, rsAPI, evTime) e, resErr := generateSendEvent(req.Context(), r, device, roomID, eventType, stateKey, rsAPI, evTime, false)
if resErr != nil { if resErr != nil {
return *resErr return *resErr
} }
@ -362,7 +363,7 @@ func SendEventCryptoIDs(
} }
} }
e, resErr := generateSendEvent(req.Context(), r, device, roomID, eventType, stateKey, rsAPI, evTime) e, resErr := generateSendEvent(req.Context(), r, device, roomID, eventType, stateKey, rsAPI, evTime, true)
if resErr != nil { if resErr != nil {
return *resErr return *resErr
} }
@ -484,6 +485,7 @@ func generateSendEvent(
roomID, eventType string, stateKey *string, roomID, eventType string, stateKey *string,
rsAPI api.ClientRoomserverAPI, rsAPI api.ClientRoomserverAPI,
evTime time.Time, evTime time.Time,
cryptoIDs bool,
) (gomatrixserverlib.PDU, *util.JSONResponse) { ) (gomatrixserverlib.PDU, *util.JSONResponse) {
// parse the incoming http request // parse the incoming http request
fullUserID, err := spec.NewUserID(device.UserID, true) fullUserID, err := spec.NewUserID(device.UserID, true)
@ -531,12 +533,18 @@ func generateSendEvent(
} }
} }
identity, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID) var identity fclient.SigningIdentity
if err != nil { if !cryptoIDs {
return nil, &util.JSONResponse{ id, err := rsAPI.SigningIdentityFor(ctx, *validRoomID, *fullUserID)
Code: http.StatusInternalServerError, if err != nil {
JSON: spec.InternalServerError{}, return nil, &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
} }
identity = id
} else {
identity.ServerName = spec.ServerName(*senderID)
} }
var queryRes api.QueryLatestEventsAndStateResponse var queryRes api.QueryLatestEventsAndStateResponse

View file

@ -228,7 +228,7 @@ func SendServerNotice(
"body": r.Content.Body, "body": r.Content.Body,
"msgtype": r.Content.MsgType, "msgtype": r.Content.MsgType,
} }
e, resErr := generateSendEvent(ctx, request, senderDevice, roomID, "m.room.message", nil, rsAPI, time.Now()) e, resErr := generateSendEvent(ctx, request, senderDevice, roomID, "m.room.message", nil, rsAPI, time.Now(), false)
if resErr != nil { if resErr != nil {
logrus.Errorf("failed to send message: %+v", resErr) logrus.Errorf("failed to send message: %+v", resErr)
return *resErr return *resErr

View file

@ -61,7 +61,7 @@ type RoomserverFederationAPI interface {
PerformMakeJoin(ctx context.Context, request *PerformJoinRequest) (gomatrixserverlib.PDU, gomatrixserverlib.RoomVersion, spec.ServerName, error) PerformMakeJoin(ctx context.Context, request *PerformJoinRequest) (gomatrixserverlib.PDU, gomatrixserverlib.RoomVersion, spec.ServerName, error)
PerformSendJoin(ctx context.Context, request *PerformSendJoinRequestCryptoIDs, response *PerformJoinResponse) PerformSendJoin(ctx context.Context, request *PerformSendJoinRequestCryptoIDs, response *PerformJoinResponse)
// Handle an instruction to make_leave & send_leave with a remote server. // Handle an instruction to make_leave & send_leave with a remote server.
PerformLeave(ctx context.Context, request *PerformLeaveRequest, response *PerformLeaveResponse) error PerformLeave(ctx context.Context, request *PerformLeaveRequest, response *PerformLeaveResponse, cryptoIDs bool) error
// Handle sending an invite to a remote server. // Handle sending an invite to a remote server.
SendInvite(ctx context.Context, event gomatrixserverlib.PDU, strippedState []gomatrixserverlib.InviteStrippedState) (gomatrixserverlib.PDU, error) SendInvite(ctx context.Context, event gomatrixserverlib.PDU, strippedState []gomatrixserverlib.InviteStrippedState) (gomatrixserverlib.PDU, error)
// Handle sending an invite to a remote server. // Handle sending an invite to a remote server.

View file

@ -747,6 +747,7 @@ func (r *FederationInternalAPI) PerformLeave(
ctx context.Context, ctx context.Context,
request *api.PerformLeaveRequest, request *api.PerformLeaveRequest,
response *api.PerformLeaveResponse, response *api.PerformLeaveResponse,
cryptoIDs bool,
) (err error) { ) (err error) {
userID, err := spec.NewUserID(request.UserID, true) userID, err := spec.NewUserID(request.UserID, true)
if err != nil { if err != nil {

View file

@ -85,12 +85,20 @@ func BuildEvent(
} }
builder := verImpl.NewEventBuilderFromProtoEvent(proto) builder := verImpl.NewEventBuilderFromProtoEvent(proto)
event, err := builder.Build( var event gomatrixserverlib.PDU
evTime, identity.ServerName, identity.KeyID, if identity.PrivateKey != nil {
identity.PrivateKey, event, err = builder.Build(
) evTime, identity.ServerName, identity.KeyID,
if err != nil { identity.PrivateKey,
return nil, err )
if err != nil {
return nil, err
}
} else {
event, err = builder.BuildWithoutSigning(evTime, identity.ServerName)
if err != nil {
return nil, err
}
} }
return &types.HeaderedEvent{PDU: event}, nil return &types.HeaderedEvent{PDU: event}, nil

View file

@ -248,7 +248,7 @@ type ClientRoomserverAPI interface {
PerformJoin(ctx context.Context, req *PerformJoinRequest) (roomID string, joinedVia spec.ServerName, err error) PerformJoin(ctx context.Context, req *PerformJoinRequest) (roomID string, joinedVia spec.ServerName, err error)
PerformSendJoinCryptoIDs(ctx context.Context, req *PerformJoinRequestCryptoIDs) error PerformSendJoinCryptoIDs(ctx context.Context, req *PerformJoinRequestCryptoIDs) error
PerformJoinCryptoIDs(ctx context.Context, req *PerformJoinRequest) (join gomatrixserverlib.PDU, roomID string, version gomatrixserverlib.RoomVersion, serverName spec.ServerName, err error) PerformJoinCryptoIDs(ctx context.Context, req *PerformJoinRequest) (join gomatrixserverlib.PDU, roomID string, version gomatrixserverlib.RoomVersion, serverName spec.ServerName, err error)
PerformLeave(ctx context.Context, req *PerformLeaveRequest, res *PerformLeaveResponse) error PerformLeave(ctx context.Context, req *PerformLeaveRequest, res *PerformLeaveResponse, cryptoIDs bool) (gomatrixserverlib.PDU, error)
PerformPublish(ctx context.Context, req *PerformPublishRequest) error PerformPublish(ctx context.Context, req *PerformPublishRequest) error
// PerformForget forgets a rooms history for a specific user // PerformForget forgets a rooms history for a specific user
PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error

View file

@ -262,16 +262,18 @@ func (r *RoomserverInternalAPI) PerformLeave(
ctx context.Context, ctx context.Context,
req *api.PerformLeaveRequest, req *api.PerformLeaveRequest,
res *api.PerformLeaveResponse, res *api.PerformLeaveResponse,
) error { cryptoIDs bool,
outputEvents, err := r.Leaver.PerformLeave(ctx, req, res) ) (gomatrixserverlib.PDU, error) {
outputEvents, leaveEvent, err := r.Leaver.PerformLeave(ctx, req, res, cryptoIDs)
if err != nil { if err != nil {
sentry.CaptureException(err) sentry.CaptureException(err)
return err return nil, err
} }
if len(outputEvents) == 0 { if len(outputEvents) == 0 {
return nil return leaveEvent, nil
} }
return r.OutputProducer.ProduceRoomEvents(req.RoomID, outputEvents) // TODO: cryptoIDs - what to do with this?
return leaveEvent, r.OutputProducer.ProduceRoomEvents(req.RoomID, outputEvents)
} }
func (r *RoomserverInternalAPI) PerformForget( func (r *RoomserverInternalAPI) PerformForget(

View file

@ -179,7 +179,7 @@ func (r *Admin) PerformAdminEvacuateUser(
Leaver: *fullUserID, Leaver: *fullUserID,
} }
leaveRes := &api.PerformLeaveResponse{} leaveRes := &api.PerformLeaveResponse{}
outputEvents, err := r.Leaver.PerformLeave(ctx, leaveReq, leaveRes) outputEvents, _, err := r.Leaver.PerformLeave(ctx, leaveReq, leaveRes, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -163,7 +163,7 @@ func (r *Inviter) PerformInvite(
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(req.InviteInput.Invitee.Domain()) isTargetLocal := r.Cfg.Matrix.IsLocalServerName(req.InviteInput.Invitee.Domain())
signingKey := req.InviteInput.PrivateKey signingKey := req.InviteInput.PrivateKey
if info.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs { if !cryptoIDs && info.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
signingKey, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, req.InviteInput.Inviter, req.InviteInput.RoomID) signingKey, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, req.InviteInput.Inviter, req.InviteInput.RoomID)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -665,15 +665,8 @@ func (r *Joiner) performJoinRoomByIDCryptoIDs(
// at this point we know we have an existing room // at this point we know we have an existing room
if inRoomRes.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs { if inRoomRes.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
var pseudoIDKey ed25519.PrivateKey
pseudoIDKey, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *userID, *roomID)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("GetOrCreateUserRoomPrivateKey failed")
return nil, "", "", "", err
}
mapping := &gomatrixserverlib.MXIDMapping{ mapping := &gomatrixserverlib.MXIDMapping{
UserRoomKey: spec.SenderIDFromPseudoIDKey(pseudoIDKey), UserRoomKey: senderID,
UserID: userID.String(), UserID: userID.String(),
} }
@ -685,9 +678,9 @@ func (r *Joiner) performJoinRoomByIDCryptoIDs(
// sign the event with the pseudo ID key // sign the event with the pseudo ID key
identity = fclient.SigningIdentity{ identity = fclient.SigningIdentity{
ServerName: spec.ServerName(spec.SenderIDFromPseudoIDKey(pseudoIDKey)), ServerName: spec.ServerName(senderID),
KeyID: "ed25519:1", KeyID: "ed25519:1",
PrivateKey: pseudoIDKey, PrivateKey: nil,
} }
} }

View file

@ -24,6 +24,7 @@ import (
"github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/internal/eventutil"
"github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -52,9 +53,10 @@ func (r *Leaver) PerformLeave(
ctx context.Context, ctx context.Context,
req *api.PerformLeaveRequest, req *api.PerformLeaveRequest,
res *api.PerformLeaveResponse, res *api.PerformLeaveResponse,
) ([]api.OutputEvent, error) { cryptoIDs bool,
) ([]api.OutputEvent, gomatrixserverlib.PDU, error) {
if !r.Cfg.Matrix.IsLocalServerName(req.Leaver.Domain()) { if !r.Cfg.Matrix.IsLocalServerName(req.Leaver.Domain()) {
return nil, fmt.Errorf("user %q does not belong to this homeserver", req.Leaver.String()) return nil, nil, fmt.Errorf("user %q does not belong to this homeserver", req.Leaver.String())
} }
logger := logrus.WithContext(ctx).WithFields(logrus.Fields{ logger := logrus.WithContext(ctx).WithFields(logrus.Fields{
"room_id": req.RoomID, "room_id": req.RoomID,
@ -62,15 +64,15 @@ func (r *Leaver) PerformLeave(
}) })
logger.Info("User requested to leave join") logger.Info("User requested to leave join")
if strings.HasPrefix(req.RoomID, "!") { if strings.HasPrefix(req.RoomID, "!") {
output, err := r.performLeaveRoomByID(context.Background(), req, res) output, event, err := r.performLeaveRoomByID(context.Background(), req, res, cryptoIDs)
if err != nil { if err != nil {
logger.WithError(err).Error("Failed to leave room") logger.WithError(err).Error("Failed to leave room")
} else { } else {
logger.Info("User left room successfully") logger.Info("User left room successfully")
} }
return output, err return output, event, err
} }
return nil, fmt.Errorf("room ID %q is invalid", req.RoomID) return nil, nil, fmt.Errorf("room ID %q is invalid", req.RoomID)
} }
// nolint:gocyclo // nolint:gocyclo
@ -78,14 +80,15 @@ func (r *Leaver) performLeaveRoomByID(
ctx context.Context, ctx context.Context,
req *api.PerformLeaveRequest, req *api.PerformLeaveRequest,
res *api.PerformLeaveResponse, // nolint:unparam res *api.PerformLeaveResponse, // nolint:unparam
) ([]api.OutputEvent, error) { cryptoIDs bool,
) ([]api.OutputEvent, gomatrixserverlib.PDU, error) {
roomID, err := spec.NewRoomID(req.RoomID) roomID, err := spec.NewRoomID(req.RoomID)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
leaver, err := r.RSAPI.QuerySenderIDForUser(ctx, *roomID, req.Leaver) leaver, err := r.RSAPI.QuerySenderIDForUser(ctx, *roomID, req.Leaver)
if err != nil || leaver == nil { if err != nil || leaver == nil {
return nil, fmt.Errorf("leaver %s has no matching senderID in this room", req.Leaver.String()) return nil, nil, fmt.Errorf("leaver %s has no matching senderID in this room", req.Leaver.String())
} }
// If there's an invite outstanding for the room then respond to // If there's an invite outstanding for the room then respond to
@ -94,7 +97,7 @@ func (r *Leaver) performLeaveRoomByID(
if err == nil && isInvitePending { if err == nil && isInvitePending {
sender, serr := r.RSAPI.QueryUserIDForSender(ctx, *roomID, senderUser) sender, serr := r.RSAPI.QueryUserIDForSender(ctx, *roomID, senderUser)
if serr != nil { if serr != nil {
return nil, fmt.Errorf("failed looking up userID for sender %q: %w", senderUser, serr) return nil, nil, fmt.Errorf("failed looking up userID for sender %q: %w", senderUser, serr)
} }
var domain spec.ServerName var domain spec.ServerName
@ -107,7 +110,7 @@ func (r *Leaver) performLeaveRoomByID(
domain = sender.Domain() domain = sender.Domain()
} }
if !r.Cfg.Matrix.IsLocalServerName(domain) { if !r.Cfg.Matrix.IsLocalServerName(domain) {
return r.performFederatedRejectInvite(ctx, req, res, domain, eventID, *leaver) return r.performFederatedRejectInvite(ctx, req, res, domain, eventID, *leaver, cryptoIDs)
} }
// check that this is not a "server notice room" // check that this is not a "server notice room"
accData := &userapi.QueryAccountDataResponse{} accData := &userapi.QueryAccountDataResponse{}
@ -116,7 +119,7 @@ func (r *Leaver) performLeaveRoomByID(
RoomID: req.RoomID, RoomID: req.RoomID,
DataType: "m.tag", DataType: "m.tag",
}, accData); err != nil { }, accData); err != nil {
return nil, fmt.Errorf("unable to query account data: %w", err) return nil, nil, fmt.Errorf("unable to query account data: %w", err)
} }
if roomData, ok := accData.RoomAccountData[req.RoomID]; ok { if roomData, ok := accData.RoomAccountData[req.RoomID]; ok {
@ -124,13 +127,13 @@ func (r *Leaver) performLeaveRoomByID(
if ok { if ok {
tags := gomatrix.TagContent{} tags := gomatrix.TagContent{}
if err = json.Unmarshal(tagData, &tags); err != nil { if err = json.Unmarshal(tagData, &tags); err != nil {
return nil, fmt.Errorf("unable to unmarshal tag content") return nil, nil, fmt.Errorf("unable to unmarshal tag content")
} }
if _, ok = tags.Tags["m.server_notice"]; ok { if _, ok = tags.Tags["m.server_notice"]; ok {
// mimic the returned values from Synapse // mimic the returned values from Synapse
res.Message = "You cannot reject this invite" res.Message = "You cannot reject this invite"
res.Code = 403 res.Code = 403
return nil, spec.LeaveServerNoticeError() return nil, nil, spec.LeaveServerNoticeError()
} }
} }
} }
@ -149,22 +152,22 @@ func (r *Leaver) performLeaveRoomByID(
} }
latestRes := api.QueryLatestEventsAndStateResponse{} latestRes := api.QueryLatestEventsAndStateResponse{}
if err = helpers.QueryLatestEventsAndState(ctx, r.DB, r.RSAPI, &latestReq, &latestRes); err != nil { if err = helpers.QueryLatestEventsAndState(ctx, r.DB, r.RSAPI, &latestReq, &latestRes); err != nil {
return nil, err return nil, nil, err
} }
if !latestRes.RoomExists { if !latestRes.RoomExists {
return nil, fmt.Errorf("room %q does not exist", req.RoomID) return nil, nil, fmt.Errorf("room %q does not exist", req.RoomID)
} }
// Now let's see if the user is in the room. // Now let's see if the user is in the room.
if len(latestRes.StateEvents) == 0 { if len(latestRes.StateEvents) == 0 {
return nil, fmt.Errorf("user %q is not a member of room %q", req.Leaver.String(), req.RoomID) return nil, nil, fmt.Errorf("user %q is not a member of room %q", req.Leaver.String(), req.RoomID)
} }
membership, err := latestRes.StateEvents[0].Membership() membership, err := latestRes.StateEvents[0].Membership()
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting membership: %w", err) return nil, nil, fmt.Errorf("error getting membership: %w", err)
} }
if membership != spec.Join && membership != spec.Invite { if membership != spec.Join && membership != spec.Invite {
return nil, fmt.Errorf("user %q is not joined to the room (membership is %q)", req.Leaver.String(), membership) return nil, nil, fmt.Errorf("user %q is not joined to the room (membership is %q)", req.Leaver.String(), membership)
} }
// Prepare the template for the leave event. // Prepare the template for the leave event.
@ -177,10 +180,10 @@ func (r *Leaver) performLeaveRoomByID(
Redacts: "", Redacts: "",
} }
if err = proto.SetContent(map[string]interface{}{"membership": "leave"}); err != nil { if err = proto.SetContent(map[string]interface{}{"membership": "leave"}); err != nil {
return nil, fmt.Errorf("eb.SetContent: %w", err) return nil, nil, fmt.Errorf("eb.SetContent: %w", err)
} }
if err = proto.SetUnsigned(struct{}{}); err != nil { if err = proto.SetUnsigned(struct{}{}); err != nil {
return nil, fmt.Errorf("eb.SetUnsigned: %w", err) return nil, nil, fmt.Errorf("eb.SetUnsigned: %w", err)
} }
// We know that the user is in the room at this point so let's build // We know that the user is in the room at this point so let's build
@ -190,39 +193,50 @@ func (r *Leaver) performLeaveRoomByID(
validRoomID, err := spec.NewRoomID(req.RoomID) validRoomID, err := spec.NewRoomID(req.RoomID)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
var buildRes rsAPI.QueryLatestEventsAndStateResponse var buildRes rsAPI.QueryLatestEventsAndStateResponse
identity, err := r.RSAPI.SigningIdentityFor(ctx, *validRoomID, req.Leaver) var identity fclient.SigningIdentity
if err != nil { if !cryptoIDs {
return nil, fmt.Errorf("SigningIdentityFor: %w", err) identity, err = r.RSAPI.SigningIdentityFor(ctx, *validRoomID, req.Leaver)
if err != nil {
return nil, nil, fmt.Errorf("SigningIdentityFor: %w", err)
}
} else {
identity = fclient.SigningIdentity{
ServerName: spec.ServerName(*leaver),
KeyID: "ed25519:1",
PrivateKey: nil,
}
} }
event, err := eventutil.QueryAndBuildEvent(ctx, &proto, &identity, time.Now(), r.RSAPI, &buildRes) event, err := eventutil.QueryAndBuildEvent(ctx, &proto, &identity, time.Now(), r.RSAPI, &buildRes)
if err != nil { if err != nil {
return nil, fmt.Errorf("eventutil.QueryAndBuildEvent: %w", err) return nil, nil, fmt.Errorf("eventutil.QueryAndBuildEvent: %w", err)
} }
// Give our leave event to the roomserver input stream. The if !cryptoIDs {
// roomserver will process the membership change and notify // Give our leave event to the roomserver input stream. The
// downstream automatically. // roomserver will process the membership change and notify
inputReq := api.InputRoomEventsRequest{ // downstream automatically.
InputRoomEvents: []api.InputRoomEvent{ inputReq := api.InputRoomEventsRequest{
{ InputRoomEvents: []api.InputRoomEvent{
Kind: api.KindNew, {
Event: event, Kind: api.KindNew,
Origin: req.Leaver.Domain(), Event: event,
SendAsServer: string(req.Leaver.Domain()), Origin: req.Leaver.Domain(),
SendAsServer: string(req.Leaver.Domain()),
},
}, },
}, }
} inputRes := api.InputRoomEventsResponse{}
inputRes := api.InputRoomEventsResponse{} r.Inputer.InputRoomEvents(ctx, &inputReq, &inputRes)
r.Inputer.InputRoomEvents(ctx, &inputReq, &inputRes) if err = inputRes.Err(); err != nil {
if err = inputRes.Err(); err != nil { return nil, nil, fmt.Errorf("r.InputRoomEvents: %w", err)
return nil, fmt.Errorf("r.InputRoomEvents: %w", err) }
} }
return nil, nil return nil, event, nil
} }
func (r *Leaver) performFederatedRejectInvite( func (r *Leaver) performFederatedRejectInvite(
@ -231,7 +245,8 @@ func (r *Leaver) performFederatedRejectInvite(
res *api.PerformLeaveResponse, // nolint:unparam res *api.PerformLeaveResponse, // nolint:unparam
inviteDomain spec.ServerName, eventID string, inviteDomain spec.ServerName, eventID string,
leaver spec.SenderID, leaver spec.SenderID,
) ([]api.OutputEvent, error) { cryptoIDs bool,
) ([]api.OutputEvent, gomatrixserverlib.PDU, error) {
// Ask the federation sender to perform a federated leave for us. // Ask the federation sender to perform a federated leave for us.
leaveReq := fsAPI.PerformLeaveRequest{ leaveReq := fsAPI.PerformLeaveRequest{
RoomID: req.RoomID, RoomID: req.RoomID,
@ -239,7 +254,7 @@ func (r *Leaver) performFederatedRejectInvite(
ServerNames: []spec.ServerName{inviteDomain}, ServerNames: []spec.ServerName{inviteDomain},
} }
leaveRes := fsAPI.PerformLeaveResponse{} leaveRes := fsAPI.PerformLeaveResponse{}
if err := r.FSAPI.PerformLeave(ctx, &leaveReq, &leaveRes); err != nil { if err := r.FSAPI.PerformLeave(ctx, &leaveReq, &leaveRes, cryptoIDs); err != nil {
// failures in PerformLeave should NEVER stop us from telling other components like the // failures in PerformLeave should NEVER stop us from telling other components like the
// sync API that the invite was withdrawn. Otherwise we can end up with stuck invites. // sync API that the invite was withdrawn. Otherwise we can end up with stuck invites.
util.GetLogger(ctx).WithError(err).Errorf("failed to PerformLeave, still retiring invite event") util.GetLogger(ctx).WithError(err).Errorf("failed to PerformLeave, still retiring invite event")
@ -279,5 +294,5 @@ func (r *Leaver) performFederatedRejectInvite(
TargetSenderID: leaver, TargetSenderID: leaver,
}, },
}, },
}, nil }, nil, nil
} }

View file

@ -532,6 +532,7 @@ type InviteResponse struct {
InviteState struct { InviteState struct {
Events []json.RawMessage `json:"events"` Events []json.RawMessage `json:"events"`
} `json:"invite_state"` } `json:"invite_state"`
OneTimePseudoID string `json:"one_time_pseudoid,omitempty"`
} }
// NewInviteResponse creates an empty response with initialised arrays. // NewInviteResponse creates an empty response with initialised arrays.
@ -539,6 +540,8 @@ func NewInviteResponse(ctx context.Context, rsAPI api.QuerySenderIDAPI, event *t
res := InviteResponse{} res := InviteResponse{}
res.InviteState.Events = []json.RawMessage{} res.InviteState.Events = []json.RawMessage{}
res.OneTimePseudoID = *event.PDU.StateKey()
// First see if there's invite_room_state in the unsigned key of the invite. // First see if there's invite_room_state in the unsigned key of the invite.
// If there is then unmarshal it into the response. This will contain the // If there is then unmarshal it into the response. This will contain the
// partial room state such as join rules, room name etc. // partial room state such as join rules, room name etc.

View file

@ -858,15 +858,15 @@ type Ed25519Key struct {
} }
func (a *UserInternalAPI) ClaimOneTimePseudoID(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (spec.SenderID, error) { func (a *UserInternalAPI) ClaimOneTimePseudoID(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (spec.SenderID, error) {
pseudoIDs, err := a.KeyDatabase.ClaimOneTimePseudoID(ctx, userID, "ed25519") pseudoID, err := a.KeyDatabase.ClaimOneTimePseudoID(ctx, userID, "ed25519")
if err != nil { if err != nil {
return "", err return "", err
} }
logrus.Infof("Claimed one time pseuodID: %v", pseudoIDs) logrus.Infof("Claimed one time pseuodID: %s", pseudoID)
if pseudoIDs != nil { if pseudoID != nil {
for key, value := range pseudoIDs.KeyJSON { for key, value := range pseudoID.KeyJSON {
keyParts := strings.Split(key, ":") keyParts := strings.Split(key, ":")
if keyParts[0] == "ed25519" { if keyParts[0] == "ed25519" {
var key_bytes Ed25519Key var key_bytes Ed25519Key