Add get event federation API (#209)
* Add get event federation API * Handle err correctly * Add missing readers * Ignore gocyclo lint for routing function * Add todo * Fix styling a bitmain
parent
2dcb3a11a5
commit
ea80ffb3af
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2017 New Vector Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/common/config"
|
||||||
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEvent returns the requested event
|
||||||
|
func GetEvent(
|
||||||
|
httpReq *http.Request,
|
||||||
|
request *gomatrixserverlib.FederationRequest,
|
||||||
|
cfg config.Dendrite,
|
||||||
|
query api.RoomserverQueryAPI,
|
||||||
|
now time.Time,
|
||||||
|
keys gomatrixserverlib.KeyRing,
|
||||||
|
eventID string,
|
||||||
|
) util.JSONResponse {
|
||||||
|
var authResponse api.QueryServerAllowedToSeeEventResponse
|
||||||
|
err := query.QueryServerAllowedToSeeEvent(&api.QueryServerAllowedToSeeEventRequest{
|
||||||
|
EventID: eventID,
|
||||||
|
ServerName: request.Origin(),
|
||||||
|
}, &authResponse)
|
||||||
|
if err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !authResponse.AllowedToSeeEvent {
|
||||||
|
return util.MessageResponse(403, "server not allowed to see event")
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventsResponse api.QueryEventsByIDResponse
|
||||||
|
err = query.QueryEventsByID(
|
||||||
|
&api.QueryEventsByIDRequest{EventIDs: []string{eventID}},
|
||||||
|
&eventsResponse,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(eventsResponse.Events) == 0 {
|
||||||
|
return util.JSONResponse{Code: 404, JSON: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{Code: 200, JSON: &eventsResponse.Events[0]}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
|
@ -77,4 +78,14 @@ func Setup(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
|
v1fedmux.Handle("/event/{eventID}", common.MakeFedAPI(
|
||||||
|
"federation_get_event", cfg.Matrix.ServerName, keys,
|
||||||
|
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
|
||||||
|
vars := mux.Vars(httpReq)
|
||||||
|
return readers.GetEvent(
|
||||||
|
httpReq, request, cfg, query, time.Now(), keys, vars["eventID"],
|
||||||
|
)
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,20 @@ type QueryInvitesForUserResponse struct {
|
||||||
InviteSenderUserIDs []string `json:"invite_sender_user_ids"`
|
InviteSenderUserIDs []string `json:"invite_sender_user_ids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryServerAllowedToSeeEventRequest is a request to QueryServerAllowedToSeeEvent
|
||||||
|
type QueryServerAllowedToSeeEventRequest struct {
|
||||||
|
// The event ID to look up invites in.
|
||||||
|
EventID string `json:"event_id"`
|
||||||
|
// The server interested in the event
|
||||||
|
ServerName gomatrixserverlib.ServerName `json:"server_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryServerAllowedToSeeEventResponse is a response to QueryServerAllowedToSeeEvent
|
||||||
|
type QueryServerAllowedToSeeEventResponse struct {
|
||||||
|
// Wether the server in question is allowed to see the event
|
||||||
|
AllowedToSeeEvent bool `json:"can_see_event"`
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -167,6 +181,12 @@ type RoomserverQueryAPI interface {
|
||||||
request *QueryInvitesForUserRequest,
|
request *QueryInvitesForUserRequest,
|
||||||
response *QueryInvitesForUserResponse,
|
response *QueryInvitesForUserResponse,
|
||||||
) error
|
) error
|
||||||
|
|
||||||
|
// Query whether a server is allowed to see an event
|
||||||
|
QueryServerAllowedToSeeEvent(
|
||||||
|
request *QueryServerAllowedToSeeEventRequest,
|
||||||
|
response *QueryServerAllowedToSeeEventResponse,
|
||||||
|
) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
|
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
|
||||||
|
@ -184,6 +204,9 @@ const RoomserverQueryMembershipsForRoomPath = "/api/roomserver/queryMembershipsF
|
||||||
// RoomserverQueryInvitesForUserPath is the HTTP path for the QueryInvitesForUser API
|
// RoomserverQueryInvitesForUserPath is the HTTP path for the QueryInvitesForUser API
|
||||||
const RoomserverQueryInvitesForUserPath = "/api/roomserver/queryInvitesForUser"
|
const RoomserverQueryInvitesForUserPath = "/api/roomserver/queryInvitesForUser"
|
||||||
|
|
||||||
|
// RoomserverQueryServerAllowedToSeeEventPath is the HTTP path for the QueryServerAllowedToSeeEvent API
|
||||||
|
const RoomserverQueryServerAllowedToSeeEventPath = "/api/roomserver/queryServerAllowedToSeeEvent"
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -243,6 +266,15 @@ func (h *httpRoomserverQueryAPI) QueryInvitesForUser(
|
||||||
return postJSON(h.httpClient, apiURL, request, response)
|
return postJSON(h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryServerAllowedToSeeEvent implements RoomserverQueryAPI
|
||||||
|
func (h *httpRoomserverQueryAPI) QueryServerAllowedToSeeEvent(
|
||||||
|
request *QueryServerAllowedToSeeEventRequest,
|
||||||
|
response *QueryServerAllowedToSeeEventResponse,
|
||||||
|
) error {
|
||||||
|
apiURL := h.roomserverURL + RoomserverQueryServerAllowedToSeeEventPath
|
||||||
|
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 {
|
||||||
|
|
|
@ -330,7 +330,66 @@ func (r *RoomserverQueryAPI) QueryInvitesForUser(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryServerAllowedToSeeEvent implements api.RoomserverQueryAPI
|
||||||
|
func (r *RoomserverQueryAPI) QueryServerAllowedToSeeEvent(
|
||||||
|
request *api.QueryServerAllowedToSeeEventRequest,
|
||||||
|
response *api.QueryServerAllowedToSeeEventResponse,
|
||||||
|
) error {
|
||||||
|
stateEntries, err := state.LoadStateAtEvent(r.DB, request.EventID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We probably want to make it so that we don't have to pull
|
||||||
|
// out all the state if possible.
|
||||||
|
stateAtEvent, err := r.loadStateEvents(stateEntries)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Should this be lifted out of here to a more general set of
|
||||||
|
// auth functions?
|
||||||
|
|
||||||
|
isInRoom := false
|
||||||
|
for _, ev := range stateAtEvent {
|
||||||
|
membership, err := ev.Membership()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if membership != "join" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
stateKey := ev.StateKey()
|
||||||
|
if stateKey == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, domain, err := gomatrixserverlib.SplitID('@', *stateKey)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if domain == request.ServerName {
|
||||||
|
isInRoom = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isInRoom {
|
||||||
|
response.AllowedToSeeEvent = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Check if history visibility is shared and if the server is currently in the room
|
||||||
|
|
||||||
|
response.AllowedToSeeEvent = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux.
|
// SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux.
|
||||||
|
// nolint: gocyclo
|
||||||
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
||||||
servMux.Handle(
|
servMux.Handle(
|
||||||
api.RoomserverQueryLatestEventsAndStatePath,
|
api.RoomserverQueryLatestEventsAndStatePath,
|
||||||
|
@ -402,4 +461,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.RoomserverQueryServerAllowedToSeeEventPath,
|
||||||
|
common.MakeAPI("queryServerAllowedToSeeEvent", func(req *http.Request) util.JSONResponse {
|
||||||
|
var request api.QueryServerAllowedToSeeEventRequest
|
||||||
|
var response api.QueryServerAllowedToSeeEventResponse
|
||||||
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
if err := r.QueryServerAllowedToSeeEvent(&request, &response); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
return util.JSONResponse{Code: 200, JSON: &response}
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,13 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// A RoomStateDatabase has the storage APIs needed to load state from the database
|
// A RoomStateDatabase has the storage APIs needed to load state from the database
|
||||||
|
@ -56,6 +57,8 @@ type RoomStateDatabase interface {
|
||||||
// Look up the Events for a list of numeric event IDs.
|
// Look up the Events for a list of numeric event IDs.
|
||||||
// Returns a sorted list of events.
|
// Returns a sorted list of events.
|
||||||
Events(eventNIDs []types.EventNID) ([]types.Event, error)
|
Events(eventNIDs []types.EventNID) ([]types.Event, error)
|
||||||
|
// Look up snapshot NID for an event ID string
|
||||||
|
SnapshotNIDFromEventID(eventID string) (types.StateSnapshotNID, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadStateAtSnapshot loads the full state of a room at a particular snapshot.
|
// LoadStateAtSnapshot loads the full state of a room at a particular snapshot.
|
||||||
|
@ -96,6 +99,21 @@ func LoadStateAtSnapshot(db RoomStateDatabase, stateNID types.StateSnapshotNID)
|
||||||
return fullState, nil
|
return fullState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadStateAtEvent loads the full state of a room at a particular event.
|
||||||
|
func LoadStateAtEvent(db RoomStateDatabase, eventID string) ([]types.StateEntry, error) {
|
||||||
|
snapshotNID, err := db.SnapshotNIDFromEventID(eventID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
stateEntries, err := LoadStateAtSnapshot(db, snapshotNID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stateEntries, nil
|
||||||
|
}
|
||||||
|
|
||||||
// LoadCombinedStateAfterEvents loads a snapshot of the state after each of the events
|
// LoadCombinedStateAfterEvents loads a snapshot of the state after each of the events
|
||||||
// and combines those snapshots together into a single list.
|
// and combines those snapshots together into a single list.
|
||||||
func LoadCombinedStateAfterEvents(db RoomStateDatabase, prevStates []types.StateAtEvent) ([]types.StateEntry, error) {
|
func LoadCombinedStateAfterEvents(db RoomStateDatabase, prevStates []types.StateAtEvent) ([]types.StateEntry, error) {
|
||||||
|
|
|
@ -226,6 +226,12 @@ func (d *Database) StateEntries(stateBlockNIDs []types.StateBlockNID) ([]types.S
|
||||||
return d.statements.bulkSelectStateBlockEntries(stateBlockNIDs)
|
return d.statements.bulkSelectStateBlockEntries(stateBlockNIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SnapshotNIDFromEventID implements state.RoomStateDatabase
|
||||||
|
func (d *Database) SnapshotNIDFromEventID(eventID string) (types.StateSnapshotNID, error) {
|
||||||
|
_, stateNID, err := d.statements.selectEvent(eventID)
|
||||||
|
return stateNID, err
|
||||||
|
}
|
||||||
|
|
||||||
// EventIDs implements input.RoomEventDatabase
|
// EventIDs implements input.RoomEventDatabase
|
||||||
func (d *Database) EventIDs(eventNIDs []types.EventNID) (map[types.EventNID]string, error) {
|
func (d *Database) EventIDs(eventNIDs []types.EventNID) (map[types.EventNID]string, error) {
|
||||||
return d.statements.bulkSelectEventID(eventNIDs)
|
return d.statements.bulkSelectEventID(eventNIDs)
|
||||||
|
|
Loading…
Reference in New Issue