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 bit
This commit is contained in:
parent
2dcb3a11a5
commit
ea80ffb3af
6 changed files with 207 additions and 2 deletions
|
@ -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 (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"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"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
type RoomserverQueryAPI interface {
|
||||
// Query the latest events and state for a room from the room server.
|
||||
|
@ -167,6 +181,12 @@ type RoomserverQueryAPI interface {
|
|||
request *QueryInvitesForUserRequest,
|
||||
response *QueryInvitesForUserResponse,
|
||||
) 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.
|
||||
|
@ -184,6 +204,9 @@ const RoomserverQueryMembershipsForRoomPath = "/api/roomserver/queryMembershipsF
|
|||
// RoomserverQueryInvitesForUserPath is the HTTP path for the QueryInvitesForUser API
|
||||
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.
|
||||
// If httpClient is nil then it uses the http.DefaultClient
|
||||
func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI {
|
||||
|
@ -243,6 +266,15 @@ func (h *httpRoomserverQueryAPI) QueryInvitesForUser(
|
|||
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 {
|
||||
jsonBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
|
|
|
@ -330,7 +330,66 @@ func (r *RoomserverQueryAPI) QueryInvitesForUser(
|
|||
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.
|
||||
// nolint: gocyclo
|
||||
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
||||
servMux.Handle(
|
||||
api.RoomserverQueryLatestEventsAndStatePath,
|
||||
|
@ -402,4 +461,18 @@ func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
|||
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 (
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/roomserver/types"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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.
|
||||
// Returns a sorted list of events.
|
||||
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.
|
||||
|
@ -96,6 +99,21 @@ func LoadStateAtSnapshot(db RoomStateDatabase, stateNID types.StateSnapshotNID)
|
|||
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
|
||||
// and combines those snapshots together into a single list.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
func (d *Database) EventIDs(eventNIDs []types.EventNID) (map[types.EventNID]string, error) {
|
||||
return d.statements.bulkSelectEventID(eventNIDs)
|
||||
|
|
Loading…
Reference in a new issue