From b4223a1a1833931111a2c8ad678803a7897f2489 Mon Sep 17 00:00:00 2001 From: John Terzis Date: Tue, 1 Nov 2022 23:17:48 -0700 Subject: [PATCH] Jterzis/sync dendrite (#793) --- clientapi/authorization/authorization.go | 4 +- clientapi/routing/routing.go | 33 +++++++- syncapi/routing/routing.go | 20 +++++ syncapi/syncapi.go | 3 +- zion/store.go | 98 ++++++++++++++++++++++-- zion/zion_authorization.go | 33 ++++++-- 6 files changed, 173 insertions(+), 18 deletions(-) diff --git a/clientapi/authorization/authorization.go b/clientapi/authorization/authorization.go index f81513d76..a520d48b5 100644 --- a/clientapi/authorization/authorization.go +++ b/clientapi/authorization/authorization.go @@ -2,13 +2,13 @@ package authorization import ( "github.com/matrix-org/dendrite/authorization" - roomserver "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/config" + _ "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/zion" log "github.com/sirupsen/logrus" ) -func NewAuthorization(cfg *config.ClientAPI, rsAPI roomserver.ClientRoomserverAPI) authorization.Authorization { +func NewRoomserverAuthorization(cfg *config.ClientAPI, rsAPI zion.RoomserverStoreAPI) authorization.Authorization { // Load authorization manager for Zion if cfg.PublicKeyAuthentication.Ethereum.GetEnableAuthZ() { auth, err := zion.NewZionAuthorization(cfg, rsAPI) diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index 7ac7ccff8..db294a07a 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -42,6 +42,7 @@ import ( "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/jetstream" userapi "github.com/matrix-org/dendrite/userapi/api" + zion "github.com/matrix-org/dendrite/zion" ) var ReleaseVersion string @@ -76,7 +77,8 @@ func Setup( rateLimits := httputil.NewRateLimits(&cfg.RateLimiting) userInteractiveAuth := auth.NewUserInteractive(userAPI, userAPI, cfg) - authorization := clientApiAuthz.NewAuthorization(cfg, rsAPI) + clientAuthz := zion.ClientRoomserverStruct{ClientRoomserverAPI: rsAPI} + authorization := clientApiAuthz.NewRoomserverAuthorization(cfg, clientAuthz) unstableFeatures := map[string]bool{ "org.matrix.e2e_cross_signing": true, @@ -396,6 +398,20 @@ func Setup( v3mux.Handle("/rooms/{roomID}/send/{eventType}", httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) + + isAllowed, _ := authorization.IsAllowed(authz.AuthorizationArgs{ + RoomId: vars["roomID"], + UserId: device.UserID, + Permission: authz.PermissionWrite, + }) + + if !isAllowed { + return util.JSONResponse{ + Code: http.StatusUnauthorized, + JSON: jsonerror.Forbidden("Unauthorised"), + } + } + if err != nil { return util.ErrorResponse(err) } @@ -405,6 +421,20 @@ func Setup( v3mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}", httputil.MakeAuthAPI("send_message", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) + + isAllowed, _ := authorization.IsAllowed(authz.AuthorizationArgs{ + RoomId: vars["roomID"], + UserId: device.UserID, + Permission: authz.PermissionWrite, + }) + + if !isAllowed { + return util.JSONResponse{ + Code: http.StatusUnauthorized, + JSON: jsonerror.Forbidden("Unauthorised to send event"), + } + } + if err != nil { return util.ErrorResponse(err) } @@ -525,7 +555,6 @@ func Setup( return GetVisibility(req, rsAPI, vars["roomID"]) }), ).Methods(http.MethodGet, http.MethodOptions) - v3mux.Handle("/directory/list/room/{roomID}", httputil.MakeAuthAPI("directory_list", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) diff --git a/syncapi/routing/routing.go b/syncapi/routing/routing.go index bc3ad2384..558606f93 100644 --- a/syncapi/routing/routing.go +++ b/syncapi/routing/routing.go @@ -29,7 +29,11 @@ import ( "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/sync" + + authz "github.com/matrix-org/dendrite/authorization" + clientApiAuthz "github.com/matrix-org/dendrite/clientapi/authorization" userapi "github.com/matrix-org/dendrite/userapi/api" + zion "github.com/matrix-org/dendrite/zion" ) // Setup configures the given mux with sync-server listeners @@ -42,9 +46,12 @@ func Setup( userAPI userapi.SyncUserAPI, rsAPI api.SyncRoomserverAPI, cfg *config.SyncAPI, + clientCfg *config.ClientAPI, lazyLoadCache caching.LazyLoadCache, fts *fulltext.Search, ) { + syncAuthz := zion.SyncRoomserverStruct{SyncRoomserverAPI: rsAPI} + authorization := clientApiAuthz.NewRoomserverAuthorization(clientCfg, syncAuthz) v1unstablemux := csMux.PathPrefix("/{apiversion:(?:v1|unstable)}/").Subrouter() v3mux := csMux.PathPrefix("/{apiversion:(?:r0|v3)}/").Subrouter() @@ -55,6 +62,19 @@ func Setup( v3mux.Handle("/rooms/{roomID}/messages", httputil.MakeAuthAPI("room_messages", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) + + isAllowed, _ := authorization.IsAllowed(authz.AuthorizationArgs{ + RoomId: vars["roomID"], + UserId: device.UserID, + Permission: authz.PermissionRead, + }) + + if !isAllowed { + return util.JSONResponse{ + Code: http.StatusUnauthorized, + JSON: jsonerror.Forbidden("Unauthorised"), + } + } if err != nil { return util.ErrorResponse(err) } diff --git a/syncapi/syncapi.go b/syncapi/syncapi.go index be19310f2..4b07366c5 100644 --- a/syncapi/syncapi.go +++ b/syncapi/syncapi.go @@ -45,6 +45,7 @@ func AddPublicRoutes( keyAPI keyapi.SyncKeyAPI, ) { cfg := &base.Cfg.SyncAPI + clientCfg := &base.Cfg.ClientAPI js, natsClient := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream) @@ -132,6 +133,6 @@ func AddPublicRoutes( routing.Setup( base.PublicClientAPIMux, requestPool, syncDB, userAPI, - rsAPI, cfg, base.Caches, base.Fulltext, + rsAPI, cfg, clientCfg, base.Caches, base.Fulltext, ) } diff --git a/zion/store.go b/zion/store.go index a36c01585..6089ff81b 100644 --- a/zion/store.go +++ b/zion/store.go @@ -12,17 +12,19 @@ import ( "github.com/matrix-org/gomatrixserverlib" ) -type Store struct { +type ClientRoomserverStore struct { rsAPI roomserver.ClientRoomserverAPI } -func NewStore(rsAPI roomserver.ClientRoomserverAPI) Store { - return Store{ - rsAPI: rsAPI, - } +type SyncRoomserverStore struct { + rsAPI roomserver.SyncRoomserverAPI } -func (s *Store) GetRoomInfo(roomId string, userId UserIdentifier) RoomInfo { +type StoreAPI interface { + GetRoomInfo(roomId string, userId UserIdentifier) RoomInfo +} + +func (s *ClientRoomserverStore) GetRoomInfo(roomId string, userId UserIdentifier) RoomInfo { result := RoomInfo{ QueryUserId: userId.MatrixUserId, SpaceNetworkId: "", @@ -60,7 +62,7 @@ func (s *Store) GetRoomInfo(roomId string, userId UserIdentifier) RoomInfo { if err != nil { return result } - + //TODO: replace with HydrateRoomInfoWithStateEvents when you have a practical way to flatten roomEvents map for _, state := range roomEvents.StateEvents { switch state.Type() { case gomatrixserverlib.MRoomCreate: @@ -86,3 +88,85 @@ func (s *Store) GetRoomInfo(roomId string, userId UserIdentifier) RoomInfo { return result } + +func (s *SyncRoomserverStore) GetRoomInfo(roomId string, userId UserIdentifier) RoomInfo { + result := RoomInfo{ + QueryUserId: userId.MatrixUserId, + SpaceNetworkId: "", + ChannelNetworkId: "", + RoomType: Unknown, + IsOwner: false, + } + + createTuple := gomatrixserverlib.StateKeyTuple{ + EventType: gomatrixserverlib.MRoomCreate, + StateKey: "", + } + + spaceChildTuple := gomatrixserverlib.StateKeyTuple{ + EventType: ConstSpaceChildEventType, + StateKey: "*", + } + + spaceParentTuple := gomatrixserverlib.StateKeyTuple{ + EventType: ConstSpaceParentEventType, + StateKey: "*", + } + + var roomEvents roomserver.QueryLatestEventsAndStateResponse + err := s.rsAPI.QueryLatestEventsAndState(context.Background(), + &roomserver.QueryLatestEventsAndStateRequest{ + RoomID: roomId, + StateToFetch: []gomatrixserverlib.StateKeyTuple{ + createTuple, + spaceParentTuple, + spaceChildTuple, + }, + }, &roomEvents) + + if err != nil { + return result + } + + HydrateRoomInfoWithStateEvents(roomId, userId, &result, roomEvents.StateEvents) + + return result +} + +func HydrateRoomInfoWithStateEvents(roomId string, userId UserIdentifier, r *RoomInfo, stateEvents []*gomatrixserverlib.HeaderedEvent) { + for _, state := range stateEvents { + switch state.Type() { + case gomatrixserverlib.MRoomCreate: + var creatorEvent CreatorEvent + err := json.Unmarshal(state.Content(), &creatorEvent) + r.IsOwner = strings.HasPrefix( + creatorEvent.Creator, + userId.LocalPart, + ) + if err == nil { + r.RoomType = Space + r.SpaceNetworkId = roomId + } + case ConstSpaceChildEventType: + r.RoomType = Space + r.SpaceNetworkId = roomId + case ConstSpaceParentEventType: + r.RoomType = Channel + r.SpaceNetworkId = *state.StateKey() + r.ChannelNetworkId = roomId + } + } + +} + +func NewClientRoomserverStore(rsAPI roomserver.ClientRoomserverAPI) StoreAPI { + return &ClientRoomserverStore{ + rsAPI: rsAPI, + } +} + +func NewSyncRoomserverStore(rsAPI roomserver.SyncRoomserverAPI) StoreAPI { + return &SyncRoomserverStore{ + rsAPI: rsAPI, + } +} diff --git a/zion/zion_authorization.go b/zion/zion_authorization.go index fbb991a31..5f947e2ce 100644 --- a/zion/zion_authorization.go +++ b/zion/zion_authorization.go @@ -19,16 +19,37 @@ var localhostJson []byte var goerliJson []byte type ZionAuthorization struct { - store Store + store StoreAPI spaceManagerLocalhost *zion_localhost.ZionSpaceManagerLocalhost spaceManagerGoerli *zion_goerli.ZionSpaceManagerGoerli chainId int } +type ClientRoomserverStruct struct { + roomserver.ClientRoomserverAPI +} -func NewZionAuthorization( - cfg *config.ClientAPI, - rsAPI roomserver.ClientRoomserverAPI, -) (authorization.Authorization, error) { +type SyncRoomserverStruct struct { + roomserver.SyncRoomserverAPI +} + +type RoomserverStoreAPI interface { + roomserver.QueryLatestEventsAndStateAPI + NewRoomserverStore() StoreAPI +} + +func (c ClientRoomserverStruct) NewRoomserverStore() StoreAPI { + return &ClientRoomserverStore{ + rsAPI: c, + } +} + +func (c SyncRoomserverStruct) NewRoomserverStore() StoreAPI { + return &SyncRoomserverStore{ + rsAPI: c, + } +} + +func NewZionAuthorization(cfg *config.ClientAPI, rsAPI RoomserverStoreAPI) (authorization.Authorization, error) { if cfg.PublicKeyAuthentication.Ethereum.NetworkUrl == "" { log.Errorf("No blockchain network url specified in config\n") return nil, nil @@ -37,7 +58,7 @@ func NewZionAuthorization( var auth ZionAuthorization auth.chainId = cfg.PublicKeyAuthentication.Ethereum.GetChainID() - auth.store = NewStore(rsAPI) + auth.store = rsAPI.NewRoomserverStore() switch auth.chainId { case 1337, 31337: