mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-08-03 14:42:47 +00:00
Implement history visibility on /messages
, /context
, /sync
(#2511)
* Add possibility to set history_visibility and user AccountType * Add new DB queries * Add actual history_visibility changes for /messages * Add passing tests * Extract check function * Cleanup * Cleanup * Fix build on 386 * Move ApplyHistoryVisibilityFilter to internal * Move queries to topology table * Add filtering to /sync and /context Some cleanup * Add passing tests; Remove failing tests :( * Re-add passing tests * Move filtering to own function to avoid duplication * Re-add passing test * Use newly added GMSL HistoryVisibility * Update gomatrixserverlib * Set the visibility when creating events * Default to shared history visibility * Remove unused query * Update history visibility checks to use gmsl Update tests * Remove unused statement * Update migrations to set "correct" history visibility * Add method to fetch the membership at a given event * Tweaks and logging * Use actual internal rsAPI, default to shared visibility in tests * Revert "Move queries to topology table" This reverts commit 4f0d41be9c194a46379796435ce73e79203edbd6. * Remove noise/unneeded code * More cleanup * Try to optimize database requests * Fix imports * PR peview fixes/changes * Move setting history visibility to own migration, be more restrictive * Fix unit tests * Lint * Fix missing entries * Tweaks for incremental syncs * Adapt generic changes Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> Co-authored-by: kegsay <kegan@matrix.org>
This commit is contained in:
parent
371336c6b5
commit
05cafbd197
31 changed files with 1043 additions and 224 deletions
|
@ -21,10 +21,12 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
"github.com/matrix-org/dendrite/internal/caching"
|
||||
roomserver "github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/syncapi/internal"
|
||||
"github.com/matrix-org/dendrite/syncapi/storage"
|
||||
"github.com/matrix-org/dendrite/syncapi/types"
|
||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||
|
@ -95,24 +97,6 @@ func Context(
|
|||
ContainsURL: filter.ContainsURL,
|
||||
}
|
||||
|
||||
// TODO: Get the actual state at the last event returned by SelectContextAfterEvent
|
||||
state, _ := syncDB.CurrentState(ctx, roomID, &stateFilter, nil)
|
||||
// verify the user is allowed to see the context for this room/event
|
||||
for _, x := range state {
|
||||
var hisVis gomatrixserverlib.HistoryVisibility
|
||||
hisVis, err = x.HistoryVisibility()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
allowed := hisVis == gomatrixserverlib.WorldReadable || membershipRes.Membership == gomatrixserverlib.Join
|
||||
if !allowed {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("User is not allowed to query context"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
id, requestedEvent, err := syncDB.SelectContextEvent(ctx, roomID, eventID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -125,6 +109,24 @@ func Context(
|
|||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
||||
// verify the user is allowed to see the context for this room/event
|
||||
startTime := time.Now()
|
||||
filteredEvents, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, rsAPI, []*gomatrixserverlib.HeaderedEvent{&requestedEvent}, nil, device.UserID, "context")
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("unable to apply history visibility filter")
|
||||
return jsonerror.InternalServerError()
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"duration": time.Since(startTime),
|
||||
"room_id": roomID,
|
||||
}).Debug("applied history visibility (context)")
|
||||
if len(filteredEvents) == 0 {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("User is not allowed to query context"),
|
||||
}
|
||||
}
|
||||
|
||||
eventsBefore, err := syncDB.SelectContextBeforeEvent(ctx, id, roomID, filter)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logrus.WithError(err).Error("unable to fetch before events")
|
||||
|
@ -137,8 +139,27 @@ func Context(
|
|||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
||||
eventsBeforeClient := gomatrixserverlib.HeaderedToClientEvents(eventsBefore, gomatrixserverlib.FormatAll)
|
||||
eventsAfterClient := gomatrixserverlib.HeaderedToClientEvents(eventsAfter, gomatrixserverlib.FormatAll)
|
||||
startTime = time.Now()
|
||||
eventsBeforeFiltered, eventsAfterFiltered, err := applyHistoryVisibilityOnContextEvents(ctx, syncDB, rsAPI, eventsBefore, eventsAfter, device.UserID)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("unable to apply history visibility filter")
|
||||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"duration": time.Since(startTime),
|
||||
"room_id": roomID,
|
||||
}).Debug("applied history visibility (context eventsBefore/eventsAfter)")
|
||||
|
||||
// TODO: Get the actual state at the last event returned by SelectContextAfterEvent
|
||||
state, err := syncDB.CurrentState(ctx, roomID, &stateFilter, nil)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("unable to fetch current room state")
|
||||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
||||
eventsBeforeClient := gomatrixserverlib.HeaderedToClientEvents(eventsBeforeFiltered, gomatrixserverlib.FormatAll)
|
||||
eventsAfterClient := gomatrixserverlib.HeaderedToClientEvents(eventsAfterFiltered, gomatrixserverlib.FormatAll)
|
||||
newState := applyLazyLoadMembers(device, filter, eventsAfterClient, eventsBeforeClient, state, lazyLoadCache)
|
||||
|
||||
response := ContextRespsonse{
|
||||
|
@ -162,6 +183,44 @@ func Context(
|
|||
}
|
||||
}
|
||||
|
||||
// applyHistoryVisibilityOnContextEvents is a helper function to avoid roundtrips to the roomserver
|
||||
// by combining the events before and after the context event. Returns the filtered events,
|
||||
// and an error, if any.
|
||||
func applyHistoryVisibilityOnContextEvents(
|
||||
ctx context.Context, syncDB storage.Database, rsAPI roomserver.SyncRoomserverAPI,
|
||||
eventsBefore, eventsAfter []*gomatrixserverlib.HeaderedEvent,
|
||||
userID string,
|
||||
) (filteredBefore, filteredAfter []*gomatrixserverlib.HeaderedEvent, err error) {
|
||||
eventIDsBefore := make(map[string]struct{}, len(eventsBefore))
|
||||
eventIDsAfter := make(map[string]struct{}, len(eventsAfter))
|
||||
|
||||
// Remember before/after eventIDs, so we can restore them
|
||||
// after applying history visibility checks
|
||||
for _, ev := range eventsBefore {
|
||||
eventIDsBefore[ev.EventID()] = struct{}{}
|
||||
}
|
||||
for _, ev := range eventsAfter {
|
||||
eventIDsAfter[ev.EventID()] = struct{}{}
|
||||
}
|
||||
|
||||
allEvents := append(eventsBefore, eventsAfter...)
|
||||
filteredEvents, err := internal.ApplyHistoryVisibilityFilter(ctx, syncDB, rsAPI, allEvents, nil, userID, "context")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// "Restore" events in the correct context
|
||||
for _, ev := range filteredEvents {
|
||||
if _, ok := eventIDsBefore[ev.EventID()]; ok {
|
||||
filteredBefore = append(filteredBefore, ev)
|
||||
}
|
||||
if _, ok := eventIDsAfter[ev.EventID()]; ok {
|
||||
filteredAfter = append(filteredAfter, ev)
|
||||
}
|
||||
}
|
||||
return filteredBefore, filteredAfter, nil
|
||||
}
|
||||
|
||||
func getStartEnd(ctx context.Context, syncDB storage.Database, startEvents, endEvents []*gomatrixserverlib.HeaderedEvent) (start, end types.TopologyToken, err error) {
|
||||
if len(startEvents) > 0 {
|
||||
start, err = syncDB.EventPositionInTopology(ctx, startEvents[0].EventID())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue