mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-26 00:03:09 -06:00
Refactor msc2836 to allow handling from federation
This commit is contained in:
parent
37790d6c68
commit
46cbbc3fc9
|
|
@ -16,10 +16,13 @@
|
||||||
package msc2836
|
package msc2836
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
fs "github.com/matrix-org/dendrite/federationsender/api"
|
fs "github.com/matrix-org/dendrite/federationsender/api"
|
||||||
|
|
@ -52,6 +55,16 @@ type EventRelationshipRequest struct {
|
||||||
AutoJoin bool `json:"auto_join"`
|
AutoJoin bool `json:"auto_join"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewEventRelationshipRequest(body io.Reader) (*EventRelationshipRequest, error) {
|
||||||
|
var relation EventRelationshipRequest
|
||||||
|
if err := json.NewDecoder(body).Decode(&relation); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Sanity check request and set defaults.
|
||||||
|
relation.applyDefaults()
|
||||||
|
return &relation, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *EventRelationshipRequest) applyDefaults() {
|
func (r *EventRelationshipRequest) applyDefaults() {
|
||||||
if r.Limit > 100 || r.Limit < 1 {
|
if r.Limit > 100 || r.Limit < 1 {
|
||||||
r.Limit = 100
|
r.Limit = 100
|
||||||
|
|
@ -88,7 +101,10 @@ type EventRelationshipResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable this MSC
|
// Enable this MSC
|
||||||
func Enable(base *setup.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationSenderInternalAPI, userAPI userapi.UserInternalAPI) error {
|
func Enable(
|
||||||
|
base *setup.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationSenderInternalAPI,
|
||||||
|
userAPI userapi.UserInternalAPI, keyRing gomatrixserverlib.JSONVerifier,
|
||||||
|
) error {
|
||||||
db, err := NewDatabase(&base.Cfg.MSCs.Database)
|
db, err := NewDatabase(&base.Cfg.MSCs.Database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Cannot enable MSC2836: %w", err)
|
return fmt.Errorf("Cannot enable MSC2836: %w", err)
|
||||||
|
|
@ -154,88 +170,56 @@ func Enable(base *setup.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, fs
|
||||||
})
|
})
|
||||||
|
|
||||||
base.PublicClientAPIMux.Handle("/unstable/event_relationships",
|
base.PublicClientAPIMux.Handle("/unstable/event_relationships",
|
||||||
httputil.MakeAuthAPI("eventRelationships", userAPI, eventRelationshipHandler(db, rsAPI)),
|
httputil.MakeAuthAPI("eventRelationships", userAPI, eventRelationshipHandler(db, rsAPI, fsAPI)),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
|
base.PublicFederationAPIMux.Handle("/unstable/event_relationships", httputil.MakeExternalAPI(
|
||||||
|
"msc2836_event_relationships", func(req *http.Request) util.JSONResponse {
|
||||||
|
fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest(
|
||||||
|
req, time.Now(), base.Cfg.Global.ServerName, keyRing,
|
||||||
|
)
|
||||||
|
if fedReq == nil {
|
||||||
|
return errResp
|
||||||
|
}
|
||||||
|
return federatedEventRelationship(req.Context(), fedReq, db, rsAPI)
|
||||||
|
},
|
||||||
|
)).Methods(http.MethodPost, http.MethodOptions)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type reqCtx struct {
|
type reqCtx struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
rsAPI roomserver.RoomserverInternalAPI
|
rsAPI roomserver.RoomserverInternalAPI
|
||||||
req *EventRelationshipRequest
|
db Database
|
||||||
userID string
|
fsAPI fs.FederationSenderInternalAPI
|
||||||
|
req *EventRelationshipRequest
|
||||||
|
userID string
|
||||||
|
isFederatedRequest bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAPI) func(*http.Request, *userapi.Device) util.JSONResponse {
|
func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationSenderInternalAPI) func(*http.Request, *userapi.Device) util.JSONResponse {
|
||||||
return func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
return func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
var relation EventRelationshipRequest
|
relation, err := NewEventRelationshipRequest(req.Body)
|
||||||
if err := json.NewDecoder(req.Body).Decode(&relation); err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("failed to decode HTTP request as JSON")
|
util.GetLogger(req.Context()).WithError(err).Error("failed to decode HTTP request as JSON")
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 400,
|
Code: 400,
|
||||||
JSON: jsonerror.BadJSON(fmt.Sprintf("invalid json: %s", err)),
|
JSON: jsonerror.BadJSON(fmt.Sprintf("invalid json: %s", err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Sanity check request and set defaults.
|
|
||||||
relation.applyDefaults()
|
|
||||||
var res EventRelationshipResponse
|
|
||||||
var returnEvents []*gomatrixserverlib.HeaderedEvent
|
|
||||||
rc := reqCtx{
|
rc := reqCtx{
|
||||||
ctx: req.Context(),
|
ctx: req.Context(),
|
||||||
req: &relation,
|
req: relation,
|
||||||
userID: device.UserID,
|
userID: device.UserID,
|
||||||
rsAPI: rsAPI,
|
rsAPI: rsAPI,
|
||||||
|
isFederatedRequest: false,
|
||||||
|
db: db,
|
||||||
}
|
}
|
||||||
|
res, resErr := rc.process()
|
||||||
// Can the user see (according to history visibility) event_id? If no, reject the request, else continue.
|
if resErr != nil {
|
||||||
// We should have the event being referenced so don't give any claimed room ID / servers
|
return *resErr
|
||||||
event := rc.getEventIfVisible(relation.EventID, "", nil)
|
|
||||||
if event == nil {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: 403,
|
|
||||||
JSON: jsonerror.Forbidden("Event does not exist or you are not authorised to see it"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the event. Add it to response array.
|
|
||||||
returnEvents = append(returnEvents, event)
|
|
||||||
|
|
||||||
if *relation.IncludeParent {
|
|
||||||
if parentEvent := rc.includeParent(event); parentEvent != nil {
|
|
||||||
returnEvents = append(returnEvents, parentEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if *relation.IncludeChildren {
|
|
||||||
remaining := relation.Limit - len(returnEvents)
|
|
||||||
if remaining > 0 {
|
|
||||||
children, resErr := rc.includeChildren(db, event.EventID(), remaining, *relation.RecentFirst)
|
|
||||||
if resErr != nil {
|
|
||||||
return *resErr
|
|
||||||
}
|
|
||||||
returnEvents = append(returnEvents, children...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remaining := relation.Limit - len(returnEvents)
|
|
||||||
var walkLimited bool
|
|
||||||
if remaining > 0 {
|
|
||||||
included := make(map[string]bool, len(returnEvents))
|
|
||||||
for _, ev := range returnEvents {
|
|
||||||
included[ev.EventID()] = true
|
|
||||||
}
|
|
||||||
var events []*gomatrixserverlib.HeaderedEvent
|
|
||||||
events, walkLimited = walkThread(
|
|
||||||
req.Context(), db, &rc, included, remaining,
|
|
||||||
)
|
|
||||||
returnEvents = append(returnEvents, events...)
|
|
||||||
}
|
|
||||||
res.Events = make([]gomatrixserverlib.ClientEvent, len(returnEvents))
|
|
||||||
for i, ev := range returnEvents {
|
|
||||||
res.Events[i] = gomatrixserverlib.HeaderedToClientEvent(*ev, gomatrixserverlib.FormatAll)
|
|
||||||
}
|
|
||||||
res.Limited = remaining == 0 || walkLimited
|
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
JSON: res,
|
JSON: res,
|
||||||
|
|
@ -243,6 +227,88 @@ func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func federatedEventRelationship(ctx context.Context, fedReq *gomatrixserverlib.FederationRequest, db Database, rsAPI roomserver.RoomserverInternalAPI) util.JSONResponse {
|
||||||
|
relation, err := NewEventRelationshipRequest(bytes.NewBuffer(fedReq.Content()))
|
||||||
|
if err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("failed to decode HTTP request as JSON")
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 400,
|
||||||
|
JSON: jsonerror.BadJSON(fmt.Sprintf("invalid json: %s", err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc := reqCtx{
|
||||||
|
ctx: ctx,
|
||||||
|
req: relation,
|
||||||
|
userID: "",
|
||||||
|
rsAPI: rsAPI,
|
||||||
|
isFederatedRequest: true,
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
res, resErr := rc.process()
|
||||||
|
if resErr != nil {
|
||||||
|
return *resErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 200,
|
||||||
|
JSON: res,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *reqCtx) process() (*EventRelationshipResponse, *util.JSONResponse) {
|
||||||
|
var res EventRelationshipResponse
|
||||||
|
var returnEvents []*gomatrixserverlib.HeaderedEvent
|
||||||
|
// Can the user see (according to history visibility) event_id? If no, reject the request, else continue.
|
||||||
|
// We should have the event being referenced so don't give any claimed room ID / servers
|
||||||
|
event := rc.getEventIfVisible(rc.req.EventID, "", nil)
|
||||||
|
if event == nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: 403,
|
||||||
|
JSON: jsonerror.Forbidden("Event does not exist or you are not authorised to see it"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve the event. Add it to response array.
|
||||||
|
returnEvents = append(returnEvents, event)
|
||||||
|
|
||||||
|
if *rc.req.IncludeParent {
|
||||||
|
if parentEvent := rc.includeParent(event); parentEvent != nil {
|
||||||
|
returnEvents = append(returnEvents, parentEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if *rc.req.IncludeChildren {
|
||||||
|
remaining := rc.req.Limit - len(returnEvents)
|
||||||
|
if remaining > 0 {
|
||||||
|
children, resErr := rc.includeChildren(rc.db, event.EventID(), remaining, *rc.req.RecentFirst)
|
||||||
|
if resErr != nil {
|
||||||
|
return nil, resErr
|
||||||
|
}
|
||||||
|
returnEvents = append(returnEvents, children...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining := rc.req.Limit - len(returnEvents)
|
||||||
|
var walkLimited bool
|
||||||
|
if remaining > 0 {
|
||||||
|
included := make(map[string]bool, len(returnEvents))
|
||||||
|
for _, ev := range returnEvents {
|
||||||
|
included[ev.EventID()] = true
|
||||||
|
}
|
||||||
|
var events []*gomatrixserverlib.HeaderedEvent
|
||||||
|
events, walkLimited = walkThread(
|
||||||
|
rc.ctx, rc.db, rc, included, remaining,
|
||||||
|
)
|
||||||
|
returnEvents = append(returnEvents, events...)
|
||||||
|
}
|
||||||
|
res.Events = make([]gomatrixserverlib.ClientEvent, len(returnEvents))
|
||||||
|
for i, ev := range returnEvents {
|
||||||
|
res.Events[i] = gomatrixserverlib.HeaderedToClientEvent(*ev, gomatrixserverlib.FormatAll)
|
||||||
|
}
|
||||||
|
res.Limited = remaining == 0 || walkLimited
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
// If include_parent: true and there is a valid m.relationship field in the event,
|
// If include_parent: true and there is a valid m.relationship field in the event,
|
||||||
// retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array.
|
// retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array.
|
||||||
func (rc *reqCtx) includeParent(event *gomatrixserverlib.HeaderedEvent) (parent *gomatrixserverlib.HeaderedEvent) {
|
func (rc *reqCtx) includeParent(event *gomatrixserverlib.HeaderedEvent) (parent *gomatrixserverlib.HeaderedEvent) {
|
||||||
|
|
|
||||||
|
|
@ -511,11 +511,12 @@ func injectEvents(t *testing.T, userAPI userapi.UserInternalAPI, rsAPI roomserve
|
||||||
cfg.MSCs.Database.ConnectionString = "file:msc2836_test.db"
|
cfg.MSCs.Database.ConnectionString = "file:msc2836_test.db"
|
||||||
cfg.MSCs.MSCs = []string{"msc2836"}
|
cfg.MSCs.MSCs = []string{"msc2836"}
|
||||||
base := &setup.BaseDendrite{
|
base := &setup.BaseDendrite{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
PublicClientAPIMux: mux.NewRouter().PathPrefix(httputil.PublicClientPathPrefix).Subrouter(),
|
PublicClientAPIMux: mux.NewRouter().PathPrefix(httputil.PublicClientPathPrefix).Subrouter(),
|
||||||
|
PublicFederationAPIMux: mux.NewRouter().PathPrefix(httputil.PublicFederationPathPrefix).Subrouter(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := msc2836.Enable(base, rsAPI, userAPI)
|
err := msc2836.Enable(base, rsAPI, nil, userAPI, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to enable MSC2836: %s", err)
|
t.Fatalf("failed to enable MSC2836: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func Enable(base *setup.BaseDendrite, monolith *setup.Monolith) error {
|
||||||
func EnableMSC(base *setup.BaseDendrite, monolith *setup.Monolith, msc string) error {
|
func EnableMSC(base *setup.BaseDendrite, monolith *setup.Monolith, msc string) error {
|
||||||
switch msc {
|
switch msc {
|
||||||
case "msc2836":
|
case "msc2836":
|
||||||
return msc2836.Enable(base, monolith.RoomserverAPI, monolith.FederationSenderAPI, monolith.UserAPI)
|
return msc2836.Enable(base, monolith.RoomserverAPI, monolith.FederationSenderAPI, monolith.UserAPI, monolith.KeyRing)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("EnableMSC: unknown msc '%s'", msc)
|
return fmt.Errorf("EnableMSC: unknown msc '%s'", msc)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue