mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-12 09:23:09 -06:00
Merge branch 'master' into babolivier/view-memberships-after-leave
This commit is contained in:
commit
66498eec73
|
|
@ -78,10 +78,18 @@ func (c *RoomserverProducer) SendEventWithState(state gomatrixserverlib.RespStat
|
||||||
return c.SendInputRoomEvents(ires)
|
return c.SendInputRoomEvents(ires)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendInputRoomEvents writes the given input room events to the roomserver input log. The length of both
|
// SendInputRoomEvents writes the given input room events to the roomserver input API.
|
||||||
// arrays must match, and each element must correspond to the same event.
|
|
||||||
func (c *RoomserverProducer) SendInputRoomEvents(ires []api.InputRoomEvent) error {
|
func (c *RoomserverProducer) SendInputRoomEvents(ires []api.InputRoomEvent) error {
|
||||||
request := api.InputRoomEventsRequest{InputRoomEvents: ires}
|
request := api.InputRoomEventsRequest{InputRoomEvents: ires}
|
||||||
var response api.InputRoomEventsResponse
|
var response api.InputRoomEventsResponse
|
||||||
return c.InputAPI.InputRoomEvents(&request, &response)
|
return c.InputAPI.InputRoomEvents(&request, &response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendInvite writes the invite event to the roomserver input API.
|
||||||
|
func (c *RoomserverProducer) SendInvite(inviteEvent gomatrixserverlib.Event) error {
|
||||||
|
request := api.InputRoomEventsRequest{
|
||||||
|
InputInviteEvents: []api.InputInviteEvent{{Event: inviteEvent}},
|
||||||
|
}
|
||||||
|
var response api.InputRoomEventsResponse
|
||||||
|
return c.InputAPI.InputRoomEvents(&request, &response)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func Setup(
|
||||||
v2keysmux.Handle("/server/{keyID}", localKeys)
|
v2keysmux.Handle("/server/{keyID}", localKeys)
|
||||||
v2keysmux.Handle("/server/", localKeys)
|
v2keysmux.Handle("/server/", localKeys)
|
||||||
|
|
||||||
v1fedmux.Handle("/send/{txnID}/", makeAPI("send",
|
v1fedmux.Handle("/send/{txnID}/", makeAPI("federation_send",
|
||||||
func(req *http.Request) util.JSONResponse {
|
func(req *http.Request) util.JSONResponse {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
return writers.Send(
|
return writers.Send(
|
||||||
|
|
@ -67,6 +67,17 @@ func Setup(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
|
v1fedmux.Handle("/invite/{roomID}/{eventID}", makeAPI("federation_invite",
|
||||||
|
func(req *http.Request) util.JSONResponse {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
return writers.Invite(
|
||||||
|
req, vars["roomID"], vars["eventID"],
|
||||||
|
time.Now(),
|
||||||
|
cfg, producer, keys,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.Handler {
|
func makeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.Handler {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package writers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
|
"github.com/matrix-org/dendrite/common/config"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Invite implements /_matrix/federation/v1/invite/{roomID}/{eventID}
|
||||||
|
func Invite(
|
||||||
|
req *http.Request,
|
||||||
|
roomID string,
|
||||||
|
eventID string,
|
||||||
|
now time.Time,
|
||||||
|
cfg config.Dendrite,
|
||||||
|
producer *producers.RoomserverProducer,
|
||||||
|
keys gomatrixserverlib.KeyRing,
|
||||||
|
) util.JSONResponse {
|
||||||
|
request, errResp := gomatrixserverlib.VerifyHTTPRequest(req, now, cfg.Matrix.ServerName, keys)
|
||||||
|
if request == nil {
|
||||||
|
return errResp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the event JSON from the request.
|
||||||
|
var event gomatrixserverlib.Event
|
||||||
|
if err := json.Unmarshal(request.Content(), &event); err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 400,
|
||||||
|
JSON: jsonerror.NotJSON("The request body could not be decoded into valid JSON. " + err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the room ID is correct.
|
||||||
|
if event.RoomID() != roomID {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 400,
|
||||||
|
JSON: jsonerror.BadJSON("The room ID in the request path must match the room ID in the invite event JSON"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the event ID is correct.
|
||||||
|
if event.EventID() != eventID {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 400,
|
||||||
|
JSON: jsonerror.BadJSON("The event ID in the request path must match the event ID in the invite event JSON"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the event is from the server sending the request.
|
||||||
|
if event.Origin() != request.Origin() {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 403,
|
||||||
|
JSON: jsonerror.Forbidden("The invite must be sent by the server it originated on"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the event is signed by the server sending the request.
|
||||||
|
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
|
||||||
|
ServerName: event.Origin(),
|
||||||
|
Message: event.JSON(),
|
||||||
|
AtTS: event.OriginServerTS(),
|
||||||
|
}}
|
||||||
|
verifyResults, err := keys.VerifyJSONs(verifyRequests)
|
||||||
|
if err != nil {
|
||||||
|
return httputil.LogThenError(req, err)
|
||||||
|
}
|
||||||
|
if verifyResults[0].Error != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 403,
|
||||||
|
JSON: jsonerror.Forbidden("The invite must be signed by the server it originated on"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the event so that other servers will know that we have received the invite.
|
||||||
|
signedEvent := event.Sign(
|
||||||
|
string(cfg.Matrix.ServerName), cfg.Matrix.KeyID, cfg.Matrix.PrivateKey,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add the invite event to the roomserver.
|
||||||
|
if err = producer.SendInvite(signedEvent); err != nil {
|
||||||
|
return httputil.LogThenError(req, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the signed event to the originating server, it should then tell
|
||||||
|
// the other servers in the room that we have been invited.
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 200,
|
||||||
|
JSON: &signedEvent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,9 @@ package writers
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
|
|
@ -10,8 +13,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Send implements /_matrix/federation/v1/send/{txnID}
|
// Send implements /_matrix/federation/v1/send/{txnID}
|
||||||
|
|
@ -39,7 +40,7 @@ func Send(
|
||||||
if err := json.Unmarshal(request.Content(), &t); err != nil {
|
if err := json.Unmarshal(request.Content(), &t); err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 400,
|
Code: 400,
|
||||||
JSON: jsonerror.BadJSON("The request body could not be decoded into valid JSON. " + err.Error()),
|
JSON: jsonerror.NotJSON("The request body could not be decoded into valid JSON. " + err.Error()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,23 @@ type QueryMembershipsForRoomResponse struct {
|
||||||
HasBeenInRoom bool `json:"has_been_in_room"`
|
HasBeenInRoom bool `json:"has_been_in_room"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryInvitesForUserRequest is a request to QueryInvitesForUser
|
||||||
|
type QueryInvitesForUserRequest struct {
|
||||||
|
// The room ID to look up invites in.
|
||||||
|
RoomID string `json:"room_id"`
|
||||||
|
// The User ID to look up invites for.
|
||||||
|
TargetUserID string `json:"target_user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryInvitesForUserResponse is a response to QueryInvitesForUser
|
||||||
|
// This is used when accepting an invite or rejecting a invite to tell which
|
||||||
|
// remote matrix servers to contact.
|
||||||
|
type QueryInvitesForUserResponse struct {
|
||||||
|
// A list of matrix user IDs for each sender of an active invite targeting
|
||||||
|
// the requested user ID.
|
||||||
|
InviteSenderUserIDs []string `json:"invite_sender_user_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
// RoomserverQueryAPI is used to query information from the room server.
|
// RoomserverQueryAPI is used to query information from the room server.
|
||||||
type RoomserverQueryAPI interface {
|
type RoomserverQueryAPI interface {
|
||||||
// Query the latest events and state for a room from the room server.
|
// Query the latest events and state for a room from the room server.
|
||||||
|
|
@ -142,6 +159,12 @@ type RoomserverQueryAPI interface {
|
||||||
request *QueryMembershipsForRoomRequest,
|
request *QueryMembershipsForRoomRequest,
|
||||||
response *QueryMembershipsForRoomResponse,
|
response *QueryMembershipsForRoomResponse,
|
||||||
) error
|
) error
|
||||||
|
|
||||||
|
// Query a list of invite event senders for a user in a room.
|
||||||
|
QueryInvitesForUser(
|
||||||
|
request *QueryInvitesForUserRequest,
|
||||||
|
response *QueryInvitesForUserResponse,
|
||||||
|
) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
|
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
|
||||||
|
|
@ -156,6 +179,9 @@ const RoomserverQueryEventsByIDPath = "/api/roomserver/queryEventsByID"
|
||||||
// RoomserverQueryMembershipsForRoomPath is the HTTP path for the QueryMembershipsForRoom API
|
// RoomserverQueryMembershipsForRoomPath is the HTTP path for the QueryMembershipsForRoom API
|
||||||
const RoomserverQueryMembershipsForRoomPath = "/api/roomserver/queryMembershipsForRoom"
|
const RoomserverQueryMembershipsForRoomPath = "/api/roomserver/queryMembershipsForRoom"
|
||||||
|
|
||||||
|
// RoomserverQueryInvitesForUserPath is the HTTP path for the QueryInvitesForUser API
|
||||||
|
const RoomserverQueryInvitesForUserPath = "/api/roomserver/queryInvitesForUser"
|
||||||
|
|
||||||
// NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API.
|
// NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API.
|
||||||
// If httpClient is nil then it uses the http.DefaultClient
|
// If httpClient is nil then it uses the http.DefaultClient
|
||||||
func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI {
|
func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI {
|
||||||
|
|
@ -206,6 +232,15 @@ func (h *httpRoomserverQueryAPI) QueryMembershipsForRoom(
|
||||||
return postJSON(h.httpClient, apiURL, request, response)
|
return postJSON(h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryInvitesForUser implements RoomserverQueryAPI
|
||||||
|
func (h *httpRoomserverQueryAPI) QueryInvitesForUser(
|
||||||
|
request *QueryInvitesForUserRequest,
|
||||||
|
response *QueryInvitesForUserResponse,
|
||||||
|
) error {
|
||||||
|
apiURL := h.roomserverURL + RoomserverQueryInvitesForUserPath
|
||||||
|
return postJSON(h.httpClient, apiURL, request, response)
|
||||||
|
}
|
||||||
|
|
||||||
func postJSON(httpClient *http.Client, apiURL string, request, response interface{}) error {
|
func postJSON(httpClient *http.Client, apiURL string, request, response interface{}) error {
|
||||||
jsonBytes, err := json.Marshal(request)
|
jsonBytes, err := json.Marshal(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,13 @@ type RoomserverQueryAPIDatabase interface {
|
||||||
// currently members of a given room.
|
// currently members of a given room.
|
||||||
// Returns an error if there was a problem talking to the database.
|
// Returns an error if there was a problem talking to the database.
|
||||||
GetJoinMembershipEventNIDsForRoom(roomNID types.RoomNID) ([]types.EventNID, error)
|
GetJoinMembershipEventNIDsForRoom(roomNID types.RoomNID) ([]types.EventNID, error)
|
||||||
|
// Look up the active invites targeting a user in a room and return the
|
||||||
|
// numeric state key IDs for the user IDs who sent them.
|
||||||
|
// Returns an error if there was a problem talking to the database.
|
||||||
|
GetInvitesForUser(roomNID types.RoomNID, targetUserNID types.EventStateKeyNID) (senderUserNIDs []types.EventStateKeyNID, err error)
|
||||||
|
// Look up the string event state keys for a list of numeric event state keys
|
||||||
|
// Returns an error if there was a problem talking to the database.
|
||||||
|
EventStateKeys([]types.EventStateKeyNID) (map[types.EventStateKeyNID]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomserverQueryAPI is an implementation of api.RoomserverQueryAPI
|
// RoomserverQueryAPI is an implementation of api.RoomserverQueryAPI
|
||||||
|
|
@ -297,6 +304,39 @@ func (r *RoomserverQueryAPI) getMembershipsBeforeEventNID(eventNID types.EventNI
|
||||||
return events, nil
|
return events, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryInvitesForUser implements api.RoomserverQueryAPI
|
||||||
|
func (r *RoomserverQueryAPI) QueryInvitesForUser(
|
||||||
|
request *api.QueryInvitesForUserRequest,
|
||||||
|
response *api.QueryInvitesForUserResponse,
|
||||||
|
) error {
|
||||||
|
roomNID, err := r.DB.RoomNID(request.RoomID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetUserNIDs, err := r.DB.EventStateKeyNIDs([]string{request.TargetUserID})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
targetUserNID := targetUserNIDs[request.TargetUserID]
|
||||||
|
|
||||||
|
senderUserNIDs, err := r.DB.GetInvitesForUser(roomNID, targetUserNID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
senderUserIDs, err := r.DB.EventStateKeys(senderUserNIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, senderUserID := range senderUserIDs {
|
||||||
|
response.InviteSenderUserIDs = append(response.InviteSenderUserIDs, senderUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux.
|
// SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux.
|
||||||
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
||||||
servMux.Handle(
|
servMux.Handle(
|
||||||
|
|
@ -355,4 +395,18 @@ func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
||||||
return util.JSONResponse{Code: 200, JSON: &response}
|
return util.JSONResponse{Code: 200, JSON: &response}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
servMux.Handle(
|
||||||
|
api.RoomserverQueryInvitesForUserPath,
|
||||||
|
common.MakeAPI("queryInvitesForUser", func(req *http.Request) util.JSONResponse {
|
||||||
|
var request api.QueryInvitesForUserRequest
|
||||||
|
var response api.QueryInvitesForUserResponse
|
||||||
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
if err := r.QueryInvitesForUser(&request, &response); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
return util.JSONResponse{Code: 200, JSON: &response}
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,12 @@ func (d *Database) EventStateKeyNIDs(eventStateKeys []string) (map[string]types.
|
||||||
return d.statements.bulkSelectEventStateKeyNID(eventStateKeys)
|
return d.statements.bulkSelectEventStateKeyNID(eventStateKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventNIDs implements query.RoomQueryDatabase
|
// EventStateKeys implements query.RoomserverQueryAPIDatabase
|
||||||
|
func (d *Database) EventStateKeys(eventStateKeyNIDs []types.EventStateKeyNID) (map[types.EventStateKeyNID]string, error) {
|
||||||
|
return d.statements.bulkSelectEventStateKey(eventStateKeyNIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventNIDs implements query.RoomserverQueryAPIDatabase
|
||||||
func (d *Database) EventNIDs(eventIDs []string) (map[string]types.EventNID, error) {
|
func (d *Database) EventNIDs(eventIDs []string) (map[string]types.EventNID, error) {
|
||||||
return d.statements.bulkSelectEventNID(eventIDs)
|
return d.statements.bulkSelectEventNID(eventIDs)
|
||||||
}
|
}
|
||||||
|
|
@ -336,7 +341,7 @@ func (d *Database) RoomNID(roomID string) (types.RoomNID, error) {
|
||||||
return roomNID, err
|
return roomNID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatestEventIDs implements query.RoomserverQueryAPIDB
|
// LatestEventIDs implements query.RoomserverQueryAPIDatabase
|
||||||
func (d *Database) LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, int64, error) {
|
func (d *Database) LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, int64, error) {
|
||||||
eventNIDs, currentStateSnapshotNID, err := d.statements.selectLatestEventNIDs(roomNID)
|
eventNIDs, currentStateSnapshotNID, err := d.statements.selectLatestEventNIDs(roomNID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -353,6 +358,13 @@ func (d *Database) LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.Ev
|
||||||
return references, currentStateSnapshotNID, depth, nil
|
return references, currentStateSnapshotNID, depth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInvitesForUser implements query.RoomserverQueryAPIDatabase
|
||||||
|
func (d *Database) GetInvitesForUser(
|
||||||
|
roomNID types.RoomNID, targetUserNID types.EventStateKeyNID,
|
||||||
|
) (senderUserIDs []types.EventStateKeyNID, err error) {
|
||||||
|
return d.statements.selectInviteActiveForUserInRoom(targetUserNID, roomNID)
|
||||||
|
}
|
||||||
|
|
||||||
// SetRoomAlias implements alias.RoomserverAliasAPIDB
|
// SetRoomAlias implements alias.RoomserverAliasAPIDB
|
||||||
func (d *Database) SetRoomAlias(alias string, roomID string) error {
|
func (d *Database) SetRoomAlias(alias string, roomID string) error {
|
||||||
return d.statements.insertRoomAlias(alias, roomID)
|
return d.statements.insertRoomAlias(alias, roomID)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue