aboutsummaryrefslogtreecommitdiff
path: root/roomserver
diff options
context:
space:
mode:
authorNeil Alexander <neilalexander@users.noreply.github.com>2020-09-29 13:40:29 +0100
committerGitHub <noreply@github.com>2020-09-29 13:40:29 +0100
commit738b829a23d4e50e68f98acb72f7d10a16009f8b (patch)
treebe4f86b0a3b39f10856499d869721c914d56b65f /roomserver
parent4ff7ac7b6574d6adec775057dc2c798a1fe10248 (diff)
Fetch missing auth events, implement QueryMissingAuthPrevEvents, try other servers in room for /event and /get_missing_events (#1450)
* Try to ask other servers in the room for missing events if the origin won't provide them * Logging * More logging * Implement QueryMissingAuthPrevEvents * Try to get missing auth events badly * Use processEvent * Logging * Update QueryMissingAuthPrevEvents * Try to find missing auth events * Patchy fix for test * Logging tweaks * Send auth events as outliers * Update check in QueryMissingAuthPrevEvents * Error responses * More return codes * Don't return error on reject/soft-fail since it was ultimately handled * More tweaks * More error tweaks
Diffstat (limited to 'roomserver')
-rw-r--r--roomserver/api/api.go7
-rw-r--r--roomserver/api/api_trace.go10
-rw-r--r--roomserver/api/query.go23
-rw-r--r--roomserver/internal/helpers/auth.go6
-rw-r--r--roomserver/internal/input/input_events.go2
-rw-r--r--roomserver/internal/perform/perform_invite.go19
-rw-r--r--roomserver/internal/perform/perform_join.go10
-rw-r--r--roomserver/internal/query/query.go39
-rw-r--r--roomserver/inthttp/client.go14
-rw-r--r--roomserver/inthttp/server.go14
10 files changed, 123 insertions, 21 deletions
diff --git a/roomserver/api/api.go b/roomserver/api/api.go
index 159c1829..043f7222 100644
--- a/roomserver/api/api.go
+++ b/roomserver/api/api.go
@@ -68,6 +68,13 @@ type RoomserverInternalAPI interface {
response *QueryStateAfterEventsResponse,
) error
+ // Query whether the roomserver is missing any auth or prev events.
+ QueryMissingAuthPrevEvents(
+ ctx context.Context,
+ request *QueryMissingAuthPrevEventsRequest,
+ response *QueryMissingAuthPrevEventsResponse,
+ ) error
+
// Query a list of events by event ID.
QueryEventsByID(
ctx context.Context,
diff --git a/roomserver/api/api_trace.go b/roomserver/api/api_trace.go
index 5fabbc21..f4eaddc1 100644
--- a/roomserver/api/api_trace.go
+++ b/roomserver/api/api_trace.go
@@ -104,6 +104,16 @@ func (t *RoomserverInternalAPITrace) QueryStateAfterEvents(
return err
}
+func (t *RoomserverInternalAPITrace) QueryMissingAuthPrevEvents(
+ ctx context.Context,
+ req *QueryMissingAuthPrevEventsRequest,
+ res *QueryMissingAuthPrevEventsResponse,
+) error {
+ err := t.Impl.QueryMissingAuthPrevEvents(ctx, req, res)
+ util.GetLogger(ctx).WithError(err).Infof("QueryMissingAuthPrevEvents req=%+v res=%+v", js(req), js(res))
+ return err
+}
+
func (t *RoomserverInternalAPITrace) QueryEventsByID(
ctx context.Context,
req *QueryEventsByIDRequest,
diff --git a/roomserver/api/query.go b/roomserver/api/query.go
index 5d61e862..aff6ee07 100644
--- a/roomserver/api/query.go
+++ b/roomserver/api/query.go
@@ -82,6 +82,27 @@ type QueryStateAfterEventsResponse struct {
StateEvents []gomatrixserverlib.HeaderedEvent `json:"state_events"`
}
+type QueryMissingAuthPrevEventsRequest struct {
+ // The room ID to query the state in.
+ RoomID string `json:"room_id"`
+ // The list of auth events to check the existence of.
+ AuthEventIDs []string `json:"auth_event_ids"`
+ // The list of previous events to check the existence of.
+ PrevEventIDs []string `json:"prev_event_ids"`
+}
+
+type QueryMissingAuthPrevEventsResponse struct {
+ // Does the room exist on this roomserver?
+ // If the room doesn't exist all other fields will be empty.
+ RoomExists bool `json:"room_exists"`
+ // The room version of the room.
+ RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
+ // The event IDs of the auth events that we don't know locally.
+ MissingAuthEventIDs []string `json:"missing_auth_event_ids"`
+ // The event IDs of the previous events that we don't know locally.
+ MissingPrevEventIDs []string `json:"missing_prev_event_ids"`
+}
+
// QueryEventsByIDRequest is a request to QueryEventsByID
type QueryEventsByIDRequest struct {
// The event IDs to look up.
@@ -154,6 +175,8 @@ type QueryServerJoinedToRoomResponse struct {
RoomExists bool `json:"room_exists"`
// True if we still believe that we are participating in the room
IsInRoom bool `json:"is_in_room"`
+ // List of servers that are also in the room
+ ServerNames []gomatrixserverlib.ServerName `json:"server_names"`
}
// QueryServerAllowedToSeeEventRequest is a request to QueryServerAllowedToSeeEvent
diff --git a/roomserver/internal/helpers/auth.go b/roomserver/internal/helpers/auth.go
index 834bc0c6..0fa89d9c 100644
--- a/roomserver/internal/helpers/auth.go
+++ b/roomserver/internal/helpers/auth.go
@@ -83,7 +83,7 @@ func CheckForSoftFail(
// Check if the event is allowed.
if err = gomatrixserverlib.Allowed(event.Event, &authEvents); err != nil {
// return true, nil
- return true, fmt.Errorf("gomatrixserverlib.Allowed: %w", err)
+ return true, err
}
return false, nil
}
@@ -99,7 +99,7 @@ func CheckAuthEvents(
// Grab the numeric IDs for the supplied auth state events from the database.
authStateEntries, err := db.StateEntriesForEventIDs(ctx, authEventIDs)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("db.StateEntriesForEventIDs: %w", err)
}
authStateEntries = types.DeduplicateStateEntries(authStateEntries)
@@ -109,7 +109,7 @@ func CheckAuthEvents(
// Load the actual auth events from the database.
authEvents, err := loadAuthEvents(ctx, db, stateNeeded, authStateEntries)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("loadAuthEvents: %w", err)
}
// Check if the event is allowed.
diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go
index f953a925..3d44f048 100644
--- a/roomserver/internal/input/input_events.go
+++ b/roomserver/internal/input/input_events.go
@@ -49,7 +49,7 @@ func (r *Inputer) processRoomEvent(
isRejected := false
authEventNIDs, rejectionErr := helpers.CheckAuthEvents(ctx, r.DB, headered, input.AuthEventIDs)
if rejectionErr != nil {
- logrus.WithError(rejectionErr).WithField("event_id", event.EventID()).WithField("auth_event_ids", input.AuthEventIDs).Error("processRoomEvent.checkAuthEvents failed for event, rejecting event")
+ logrus.WithError(rejectionErr).WithField("event_id", event.EventID()).WithField("auth_event_ids", input.AuthEventIDs).Error("helpers.CheckAuthEvents failed for event, rejecting event")
isRejected = true
}
diff --git a/roomserver/internal/perform/perform_invite.go b/roomserver/internal/perform/perform_invite.go
index d6a64e7e..734e73d4 100644
--- a/roomserver/internal/perform/perform_invite.go
+++ b/roomserver/internal/perform/perform_invite.go
@@ -136,14 +136,10 @@ func (r *Inviter) PerformInvite(
log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
"processInviteEvent.checkAuthEvents failed for event",
)
- if _, ok := err.(*gomatrixserverlib.NotAllowed); ok {
- res.Error = &api.PerformError{
- Msg: err.Error(),
- Code: api.PerformErrorNotAllowed,
- }
- return nil, nil
+ res.Error = &api.PerformError{
+ Msg: err.Error(),
+ Code: api.PerformErrorNotAllowed,
}
- return nil, fmt.Errorf("checkAuthEvents: %w", err)
}
// If the invite originated from us and the target isn't local then we
@@ -160,7 +156,7 @@ func (r *Inviter) PerformInvite(
if err = r.FSAPI.PerformInvite(ctx, fsReq, fsRes); err != nil {
res.Error = &api.PerformError{
Msg: err.Error(),
- Code: api.PerformErrorNoOperation,
+ Code: api.PerformErrorNotAllowed,
}
log.WithError(err).WithField("event_id", event.EventID()).Error("r.FSAPI.PerformInvite failed")
return nil, nil
@@ -185,7 +181,12 @@ func (r *Inviter) PerformInvite(
inputRes := &api.InputRoomEventsResponse{}
r.Inputer.InputRoomEvents(context.Background(), inputReq, inputRes)
if err = inputRes.Err(); err != nil {
- return nil, fmt.Errorf("r.InputRoomEvents: %w", err)
+ res.Error = &api.PerformError{
+ Msg: fmt.Sprintf("r.InputRoomEvents: %s", err.Error()),
+ Code: api.PerformErrorNotAllowed,
+ }
+ log.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
+ return nil, nil
}
} else {
// The invite originated over federation. Process the membership
diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go
index e9aebb83..56ae6d0b 100644
--- a/roomserver/internal/perform/perform_join.go
+++ b/roomserver/internal/perform/perform_join.go
@@ -249,14 +249,10 @@ func (r *Joiner) performJoinRoomByID(
inputRes := api.InputRoomEventsResponse{}
r.Inputer.InputRoomEvents(ctx, &inputReq, &inputRes)
if err = inputRes.Err(); err != nil {
- var notAllowed *gomatrixserverlib.NotAllowed
- if errors.As(err, &notAllowed) {
- return "", &api.PerformError{
- Code: api.PerformErrorNotAllowed,
- Msg: fmt.Sprintf("InputRoomEvents auth failed: %s", err),
- }
+ return "", &api.PerformError{
+ Code: api.PerformErrorNotAllowed,
+ Msg: fmt.Sprintf("InputRoomEvents auth failed: %s", err),
}
- return "", fmt.Errorf("r.InputRoomEvents: %w", err)
}
}
diff --git a/roomserver/internal/query/query.go b/roomserver/internal/query/query.go
index 58cb4493..73660421 100644
--- a/roomserver/internal/query/query.go
+++ b/roomserver/internal/query/query.go
@@ -98,6 +98,38 @@ func (r *Queryer) QueryStateAfterEvents(
return nil
}
+// QueryMissingAuthPrevEvents implements api.RoomserverInternalAPI
+func (r *Queryer) QueryMissingAuthPrevEvents(
+ ctx context.Context,
+ request *api.QueryMissingAuthPrevEventsRequest,
+ response *api.QueryMissingAuthPrevEventsResponse,
+) error {
+ info, err := r.DB.RoomInfo(ctx, request.RoomID)
+ if err != nil {
+ return err
+ }
+ if info == nil {
+ return errors.New("room doesn't exist")
+ }
+
+ response.RoomExists = !info.IsStub
+ response.RoomVersion = info.RoomVersion
+
+ for _, authEventID := range request.AuthEventIDs {
+ if nids, err := r.DB.EventNIDs(ctx, []string{authEventID}); err != nil || len(nids) == 0 {
+ response.MissingAuthEventIDs = append(response.MissingAuthEventIDs, authEventID)
+ }
+ }
+
+ for _, prevEventID := range request.PrevEventIDs {
+ if nids, err := r.DB.EventNIDs(ctx, []string{prevEventID}); err != nil || len(nids) == 0 {
+ response.MissingPrevEventIDs = append(response.MissingPrevEventIDs, prevEventID)
+ }
+ }
+
+ return nil
+}
+
// QueryEventsByID implements api.RoomserverInternalAPI
func (r *Queryer) QueryEventsByID(
ctx context.Context,
@@ -255,19 +287,24 @@ func (r *Queryer) QueryServerJoinedToRoom(
return fmt.Errorf("r.DB.Events: %w", err)
}
+ servers := map[gomatrixserverlib.ServerName]struct{}{}
for _, e := range events {
if e.Type() == gomatrixserverlib.MRoomMember && e.StateKey() != nil {
_, serverName, err := gomatrixserverlib.SplitID('@', *e.StateKey())
if err != nil {
continue
}
+ servers[serverName] = struct{}{}
if serverName == request.ServerName {
response.IsInRoom = true
- break
}
}
}
+ for server := range servers {
+ response.ServerNames = append(response.ServerNames, server)
+ }
+
return nil
}
diff --git a/roomserver/inthttp/client.go b/roomserver/inthttp/client.go
index 3dd3edaf..24a82adf 100644
--- a/roomserver/inthttp/client.go
+++ b/roomserver/inthttp/client.go
@@ -35,6 +35,7 @@ const (
// Query operations
RoomserverQueryLatestEventsAndStatePath = "/roomserver/queryLatestEventsAndState"
RoomserverQueryStateAfterEventsPath = "/roomserver/queryStateAfterEvents"
+ RoomserverQueryMissingAuthPrevEventsPath = "/roomserver/queryMissingAuthPrevEvents"
RoomserverQueryEventsByIDPath = "/roomserver/queryEventsByID"
RoomserverQueryMembershipForUserPath = "/roomserver/queryMembershipForUser"
RoomserverQueryMembershipsForRoomPath = "/roomserver/queryMembershipsForRoom"
@@ -262,6 +263,19 @@ func (h *httpRoomserverInternalAPI) QueryStateAfterEvents(
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
}
+// QueryStateAfterEvents implements RoomserverQueryAPI
+func (h *httpRoomserverInternalAPI) QueryMissingAuthPrevEvents(
+ ctx context.Context,
+ request *api.QueryMissingAuthPrevEventsRequest,
+ response *api.QueryMissingAuthPrevEventsResponse,
+) error {
+ span, ctx := opentracing.StartSpanFromContext(ctx, "QueryMissingAuthPrevEvents")
+ defer span.Finish()
+
+ apiURL := h.roomserverURL + RoomserverQueryMissingAuthPrevEventsPath
+ return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
+}
+
// QueryEventsByID implements RoomserverQueryAPI
func (h *httpRoomserverInternalAPI) QueryEventsByID(
ctx context.Context,
diff --git a/roomserver/inthttp/server.go b/roomserver/inthttp/server.go
index c7e541dd..9c9d4d4a 100644
--- a/roomserver/inthttp/server.go
+++ b/roomserver/inthttp/server.go
@@ -126,6 +126,20 @@ func AddRoutes(r api.RoomserverInternalAPI, internalAPIMux *mux.Router) {
}),
)
internalAPIMux.Handle(
+ RoomserverQueryMissingAuthPrevEventsPath,
+ httputil.MakeInternalAPI("queryMissingAuthPrevEvents", func(req *http.Request) util.JSONResponse {
+ var request api.QueryMissingAuthPrevEventsRequest
+ var response api.QueryMissingAuthPrevEventsResponse
+ if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
+ return util.ErrorResponse(err)
+ }
+ if err := r.QueryMissingAuthPrevEvents(req.Context(), &request, &response); err != nil {
+ return util.ErrorResponse(err)
+ }
+ return util.JSONResponse{Code: http.StatusOK, JSON: &response}
+ }),
+ )
+ internalAPIMux.Handle(
RoomserverQueryEventsByIDPath,
httputil.MakeInternalAPI("queryEventsByID", func(req *http.Request) util.JSONResponse {
var request api.QueryEventsByIDRequest