aboutsummaryrefslogtreecommitdiff
path: root/roomserver/internal
diff options
context:
space:
mode:
authorTill <2353100+S7evinK@users.noreply.github.com>2022-12-22 13:05:59 +0100
committerGitHub <noreply@github.com>2022-12-22 13:05:59 +0100
commit5eed31fea330f5f0500384c98272b9a75a44fba4 (patch)
tree8f968c15c3d49e6626ef762e5f3a6e3e4e1ab74d /roomserver/internal
parent09dff951d6be1fee1cc7c6872e98eb27e81fc778 (diff)
Handle guest access [1/2?] (#2872)
Needs https://github.com/matrix-org/sytest/pull/1315, as otherwise the membership events aren't persisted yet when hitting `/state` after kicking guest users. Makes the following tests pass: ``` Guest users denied access over federation if guest access prohibited Guest users are kicked from guest_access rooms on revocation of guest_access Guest users are kicked from guest_access rooms on revocation of guest_access over federation ``` Todo (in a follow up PR): - Restrict access to CS API Endpoints as per https://spec.matrix.org/v1.4/client-server-api/#client-behaviour-14 Co-authored-by: kegsay <kegan@matrix.org>
Diffstat (limited to 'roomserver/internal')
-rw-r--r--roomserver/internal/api.go20
-rw-r--r--roomserver/internal/input/input.go4
-rw-r--r--roomserver/internal/input/input_events.go105
-rw-r--r--roomserver/internal/perform/perform_join.go23
4 files changed, 146 insertions, 6 deletions
diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go
index 1a362660..451b3769 100644
--- a/roomserver/internal/api.go
+++ b/roomserver/internal/api.go
@@ -4,6 +4,10 @@ import (
"context"
"github.com/getsentry/sentry-go"
+ "github.com/matrix-org/gomatrixserverlib"
+ "github.com/nats-io/nats.go"
+ "github.com/sirupsen/logrus"
+
asAPI "github.com/matrix-org/dendrite/appservice/api"
fsAPI "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal/caching"
@@ -19,9 +23,6 @@ import (
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
userapi "github.com/matrix-org/dendrite/userapi/api"
- "github.com/matrix-org/gomatrixserverlib"
- "github.com/nats-io/nats.go"
- "github.com/sirupsen/logrus"
)
// RoomserverInternalAPI is an implementation of api.RoomserverInternalAPI
@@ -104,6 +105,11 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
r.fsAPI = fsAPI
r.KeyRing = keyRing
+ identity, err := r.Cfg.Matrix.SigningIdentityFor(r.ServerName)
+ if err != nil {
+ logrus.Panic(err)
+ }
+
r.Inputer = &input.Inputer{
Cfg: &r.Base.Cfg.RoomServer,
Base: r.Base,
@@ -114,7 +120,8 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
JetStream: r.JetStream,
NATSClient: r.NATSClient,
Durable: nats.Durable(r.Durable),
- ServerName: r.Cfg.Matrix.ServerName,
+ ServerName: r.ServerName,
+ SigningIdentity: identity,
FSAPI: fsAPI,
KeyRing: keyRing,
ACLs: r.ServerACLs,
@@ -135,7 +142,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
Queryer: r.Queryer,
}
r.Peeker = &perform.Peeker{
- ServerName: r.Cfg.Matrix.ServerName,
+ ServerName: r.ServerName,
Cfg: r.Cfg,
DB: r.DB,
FSAPI: r.fsAPI,
@@ -146,7 +153,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
Inputer: r.Inputer,
}
r.Unpeeker = &perform.Unpeeker{
- ServerName: r.Cfg.Matrix.ServerName,
+ ServerName: r.ServerName,
Cfg: r.Cfg,
DB: r.DB,
FSAPI: r.fsAPI,
@@ -193,6 +200,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
func (r *RoomserverInternalAPI) SetUserAPI(userAPI userapi.RoomserverUserAPI) {
r.Leaver.UserAPI = userAPI
+ r.Inputer.UserAPI = userAPI
}
func (r *RoomserverInternalAPI) SetAppserviceAPI(asAPI asAPI.AppServiceInternalAPI) {
diff --git a/roomserver/internal/input/input.go b/roomserver/internal/input/input.go
index e965691c..94131103 100644
--- a/roomserver/internal/input/input.go
+++ b/roomserver/internal/input/input.go
@@ -23,6 +23,8 @@ import (
"sync"
"time"
+ userapi "github.com/matrix-org/dendrite/userapi/api"
+
"github.com/Arceliar/phony"
"github.com/getsentry/sentry-go"
"github.com/matrix-org/gomatrixserverlib"
@@ -79,6 +81,7 @@ type Inputer struct {
JetStream nats.JetStreamContext
Durable nats.SubOpt
ServerName gomatrixserverlib.ServerName
+ SigningIdentity *gomatrixserverlib.SigningIdentity
FSAPI fedapi.RoomserverFederationAPI
KeyRing gomatrixserverlib.JSONVerifier
ACLs *acls.ServerACLs
@@ -87,6 +90,7 @@ type Inputer struct {
workers sync.Map // room ID -> *worker
Queryer *query.Queryer
+ UserAPI userapi.RoomserverUserAPI
}
// If a room consumer is inactive for a while then we will allow NATS
diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go
index 10b8ee27..4179fc1e 100644
--- a/roomserver/internal/input/input_events.go
+++ b/roomserver/internal/input/input_events.go
@@ -19,6 +19,7 @@ package input
import (
"context"
"database/sql"
+ "encoding/json"
"errors"
"fmt"
"time"
@@ -31,6 +32,8 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
+ userAPI "github.com/matrix-org/dendrite/userapi/api"
+
fedapi "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/eventutil"
@@ -440,6 +443,13 @@ func (r *Inputer) processRoomEvent(
}
}
+ // If guest_access changed and is not can_join, kick all guest users.
+ if event.Type() == gomatrixserverlib.MRoomGuestAccess && gjson.GetBytes(event.Content(), "guest_access").Str != "can_join" {
+ if err = r.kickGuests(ctx, event, roomInfo); err != nil {
+ logrus.WithError(err).Error("failed to kick guest users on m.room.guest_access revocation")
+ }
+ }
+
// Everything was OK — the latest events updater didn't error and
// we've sent output events. Finally, generate a hook call.
hooks.Run(hooks.KindNewEventPersisted, headered)
@@ -729,3 +739,98 @@ func (r *Inputer) calculateAndSetState(
succeeded = true
return nil
}
+
+// kickGuests kicks guests users from m.room.guest_access rooms, if guest access is now prohibited.
+func (r *Inputer) kickGuests(ctx context.Context, event *gomatrixserverlib.Event, roomInfo *types.RoomInfo) error {
+ membershipNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, roomInfo.RoomNID, true, true)
+ if err != nil {
+ return err
+ }
+
+ memberEvents, err := r.DB.Events(ctx, membershipNIDs)
+ if err != nil {
+ return err
+ }
+
+ inputEvents := make([]api.InputRoomEvent, 0, len(memberEvents))
+ latestReq := &api.QueryLatestEventsAndStateRequest{
+ RoomID: event.RoomID(),
+ }
+ latestRes := &api.QueryLatestEventsAndStateResponse{}
+ if err = r.Queryer.QueryLatestEventsAndState(ctx, latestReq, latestRes); err != nil {
+ return err
+ }
+
+ prevEvents := latestRes.LatestEvents
+ for _, memberEvent := range memberEvents {
+ if memberEvent.StateKey() == nil {
+ continue
+ }
+
+ localpart, senderDomain, err := gomatrixserverlib.SplitID('@', *memberEvent.StateKey())
+ if err != nil {
+ continue
+ }
+
+ accountRes := &userAPI.QueryAccountByLocalpartResponse{}
+ if err = r.UserAPI.QueryAccountByLocalpart(ctx, &userAPI.QueryAccountByLocalpartRequest{
+ Localpart: localpart,
+ ServerName: senderDomain,
+ }, accountRes); err != nil {
+ return err
+ }
+ if accountRes.Account == nil {
+ continue
+ }
+
+ if accountRes.Account.AccountType != userAPI.AccountTypeGuest {
+ continue
+ }
+
+ var memberContent gomatrixserverlib.MemberContent
+ if err = json.Unmarshal(memberEvent.Content(), &memberContent); err != nil {
+ return err
+ }
+ memberContent.Membership = gomatrixserverlib.Leave
+
+ stateKey := *memberEvent.StateKey()
+ fledglingEvent := &gomatrixserverlib.EventBuilder{
+ RoomID: event.RoomID(),
+ Type: gomatrixserverlib.MRoomMember,
+ StateKey: &stateKey,
+ Sender: stateKey,
+ PrevEvents: prevEvents,
+ }
+
+ if fledglingEvent.Content, err = json.Marshal(memberContent); err != nil {
+ return err
+ }
+
+ eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(fledglingEvent)
+ if err != nil {
+ return err
+ }
+
+ event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, r.SigningIdentity, time.Now(), &eventsNeeded, latestRes)
+ if err != nil {
+ return err
+ }
+
+ inputEvents = append(inputEvents, api.InputRoomEvent{
+ Kind: api.KindNew,
+ Event: event,
+ Origin: senderDomain,
+ SendAsServer: string(senderDomain),
+ })
+ prevEvents = []gomatrixserverlib.EventReference{
+ event.EventReference(),
+ }
+ }
+
+ inputReq := &api.InputRoomEventsRequest{
+ InputRoomEvents: inputEvents,
+ Asynchronous: true, // Needs to be async, as we otherwise create a deadlock
+ }
+ inputRes := &api.InputRoomEventsResponse{}
+ return r.InputRoomEvents(ctx, inputReq, inputRes)
+}
diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go
index 4de008c6..fc7ba940 100644
--- a/roomserver/internal/perform/perform_join.go
+++ b/roomserver/internal/perform/perform_join.go
@@ -16,6 +16,7 @@ package perform
import (
"context"
+ "database/sql"
"errors"
"fmt"
"strings"
@@ -270,6 +271,28 @@ func (r *Joiner) performJoinRoomByID(
}
}
+ // If a guest is trying to join a room, check that the room has a m.room.guest_access event
+ if req.IsGuest {
+ var guestAccessEvent *gomatrixserverlib.HeaderedEvent
+ guestAccess := "forbidden"
+ guestAccessEvent, err = r.DB.GetStateEvent(ctx, req.RoomIDOrAlias, gomatrixserverlib.MRoomGuestAccess, "")
+ if (err != nil && !errors.Is(err, sql.ErrNoRows)) || guestAccessEvent == nil {
+ logrus.WithError(err).Warn("unable to get m.room.guest_access event, defaulting to 'forbidden'")
+ }
+ if guestAccessEvent != nil {
+ guestAccess = gjson.GetBytes(guestAccessEvent.Content(), "guest_access").String()
+ }
+
+ // Servers MUST only allow guest users to join rooms if the m.room.guest_access state event
+ // is present on the room and has the guest_access value can_join.
+ if guestAccess != "can_join" {
+ return "", "", &rsAPI.PerformError{
+ Code: rsAPI.PerformErrorNotAllowed,
+ Msg: "Guest access is forbidden",
+ }
+ }
+ }
+
// If we should do a forced federated join then do that.
var joinedVia gomatrixserverlib.ServerName
if forceFederatedJoin {