diff --git a/clientapi/routing/register.go b/clientapi/routing/register.go index b594c0bfb..816941566 100644 --- a/clientapi/routing/register.go +++ b/clientapi/routing/register.go @@ -19,7 +19,6 @@ import ( "context" "encoding/json" "fmt" - rsAPI "github.com/matrix-org/dendrite/roomserver/api" "io" "net/http" "net/url" @@ -537,7 +536,6 @@ func validateApplicationService( func Register( req *http.Request, userAPI userapi.ClientUserAPI, - clientRsApi rsAPI.ClientRoomserverAPI, cfg *config.ClientAPI, ) util.JSONResponse { defer req.Body.Close() // nolint: errcheck @@ -634,7 +632,7 @@ func Register( "session_id": r.Auth.Session, }).Info("Processing registration request") - return handleRegistrationFlow(req, r, sessionID, cfg, userAPI, accessToken, accessTokenErr, clientRsApi) + return handleRegistrationFlow(req, r, sessionID, cfg, userAPI, accessToken, accessTokenErr) } func handleGuestRegistration( @@ -701,15 +699,13 @@ func handleGuestRegistration( // handleRegistrationFlow will direct and complete registration flow stages // that the client has requested. // nolint: gocyclo -func handleRegistrationFlow( - req *http.Request, +func handleRegistrationFlow(req *http.Request, r registerRequest, sessionID string, cfg *config.ClientAPI, userAPI userapi.ClientUserAPI, accessToken string, accessTokenErr error, - clientRsApi rsAPI.ClientRoomserverAPI, ) util.JSONResponse { // TODO: Enable registration config flag // TODO: Guest account upgrading @@ -725,7 +721,7 @@ func handleRegistrationFlow( // the login type specifically requests it. if r.Type == authtypes.LoginTypeApplicationService && accessTokenErr == nil { return handleApplicationServiceRegistration( - accessToken, accessTokenErr, req, r, cfg, userAPI, clientRsApi, + accessToken, accessTokenErr, req, r, cfg, userAPI, ) } @@ -778,7 +774,7 @@ func handleRegistrationFlow( // Check if the user's registration flow has been completed successfully // A response with current registration flow and remaining available methods // will be returned if a flow has not been successfully completed yet - return checkAndCompleteFlow(sessions.getCompletedStages(sessionID), req, r, sessionID, cfg, userAPI, clientRsApi) + return checkAndCompleteFlow(sessions.getCompletedStages(sessionID), req, r, sessionID, cfg, userAPI) } // handleApplicationServiceRegistration handles the registration of an @@ -789,15 +785,7 @@ func handleRegistrationFlow( // at an earlier step of the registration workflow, or if the provided access // token doesn't belong to a valid AS, or if there was an issue completing the // registration process. -func handleApplicationServiceRegistration( - accessToken string, - tokenErr error, - req *http.Request, - r registerRequest, - cfg *config.ClientAPI, - userAPI userapi.ClientUserAPI, - clientRsApi rsAPI.ClientRoomserverAPI, -) util.JSONResponse { +func handleApplicationServiceRegistration(accessToken string, tokenErr error, req *http.Request, r registerRequest, cfg *config.ClientAPI, userAPI userapi.ClientUserAPI) util.JSONResponse { // Check if we previously had issues extracting the access token from the // request. if tokenErr != nil { @@ -820,8 +808,8 @@ func handleApplicationServiceRegistration( // Don't need to worry about appending to registration stages as // application service registration is entirely separate. return completeRegistration( - req.Context(), userAPI, clientRsApi, r.Username, "", appserviceID, req.RemoteAddr, req.UserAgent(), r.Auth.Session, - cfg, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeAppService, + req.Context(), userAPI, r.Username, "", appserviceID, req.RemoteAddr, req.UserAgent(), r.Auth.Session, + r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeAppService, ) } @@ -833,15 +821,11 @@ func checkAndCompleteFlow(flow []authtypes.LoginType, r registerRequest, sessionID string, cfg *config.ClientAPI, - userAPI userapi.ClientUserAPI, - clientRsApi rsAPI.ClientRoomserverAPI) util.JSONResponse { + userAPI userapi.ClientUserAPI) util.JSONResponse { if checkFlowCompleted(flow, cfg.Derived.Registration.Flows) { // This flow was completed, registration can continue - return completeRegistration( - req.Context(), userAPI, clientRsApi, r.Username, r.Password, "", req.RemoteAddr, req.UserAgent(), sessionID, - cfg, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeUser, - ) + return completeRegistration(req.Context(), userAPI, r.Username, r.Password, "", req.RemoteAddr, req.UserAgent(), sessionID, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeUser) } sessions.addParams(sessionID, r) // There are still more stages to complete. @@ -853,29 +837,6 @@ func checkAndCompleteFlow(flow []authtypes.LoginType, } } -// Add user to a room. This function currently working for auto_join_rooms config, -// which can add a newly registered user to a specified room. -func addUserToRoom( - ctx context.Context, - clientRsAPI rsAPI.ClientRoomserverAPI, - roomID string, - username string, - userID string, -) error { - addGroupContent := make(map[string]interface{}) - // This make sure the user's username can be displayed correctly. - // Because the newly-registered user doesn't have an avatar, - // the avatar_url is not needed. - addGroupContent["displayname"] = username - joinReq := rsAPI.PerformJoinRequest{ - RoomIDOrAlias: roomID, - UserID: userID, - Content: addGroupContent, - } - joinRes := rsAPI.PerformJoinResponse{} - return clientRsAPI.PerformJoin(ctx, &joinReq, &joinRes) -} - // completeRegistration runs some rudimentary checks against the submitted // input, then if successful creates an account and a newly associated device // We pass in each individual part of the request here instead of just passing a @@ -885,9 +846,7 @@ func addUserToRoom( func completeRegistration( ctx context.Context, userAPI userapi.ClientUserAPI, - clientRsApi rsAPI.ClientRoomserverAPI, username, password, appserviceID, ipAddr, userAgent, sessionID string, - cfg *config.ClientAPI, inhibitLogin eventutil.WeakBoolean, displayName, deviceID *string, accType userapi.AccountType, @@ -973,18 +932,6 @@ func completeRegistration( } sessions.addCompletedRegistration(sessionID, result) - // POST register behaviour: check if the user is a normal user. - // If the user is a normal user, add user to room specified in the configuration "auto_join_rooms". - if accType != userapi.AccountTypeAppService && appserviceID == "" { - for room := range cfg.AutoJoinRooms { - err := addUserToRoom(context.Background(), clientRsApi, cfg.AutoJoinRooms[room], username, - userutil.MakeUserID(username, cfg.Matrix.ServerName)) - if err != nil { - log.WithError(err).Errorf("user %s failed to auto-join room %s", username, cfg.AutoJoinRooms[room]) - } - } - } - return util.JSONResponse{ Code: http.StatusOK, JSON: result, @@ -1099,7 +1046,7 @@ func RegisterAvailable( } } -func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.ClientUserAPI, clientRsApi rsAPI.ClientRoomserverAPI, sr *SharedSecretRegistration, req *http.Request) util.JSONResponse { +func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.ClientUserAPI, sr *SharedSecretRegistration, req *http.Request) util.JSONResponse { ssrr, err := NewSharedSecretRegistrationRequest(req.Body) if err != nil { return util.JSONResponse{ @@ -1132,5 +1079,5 @@ func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.Clien if ssrr.Admin { accType = userapi.AccountTypeAdmin } - return completeRegistration(req.Context(), userAPI, clientRsApi, ssrr.User, ssrr.Password, "", req.RemoteAddr, req.UserAgent(), "", cfg, false, &ssrr.User, &deviceID, accType) + return completeRegistration(req.Context(), userAPI, ssrr.User, ssrr.Password, "", req.RemoteAddr, req.UserAgent(), "", false, &ssrr.User, &deviceID, accType) } diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index d95adb990..4ca8e59c5 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -135,7 +135,7 @@ func Setup( } } if req.Method == http.MethodPost { - return handleSharedSecretRegistration(cfg, userAPI, rsAPI, sr, req) + return handleSharedSecretRegistration(cfg, userAPI, sr, req) } return util.JSONResponse{ Code: http.StatusMethodNotAllowed, @@ -432,7 +432,7 @@ func Setup( if r := rateLimits.Limit(req, nil); r != nil { return *r } - return Register(req, userAPI, rsAPI, cfg) + return Register(req, userAPI, cfg) })).Methods(http.MethodPost, http.MethodOptions) v3mux.Handle("/register/available", httputil.MakeExternalAPI("registerAvailable", func(req *http.Request) util.JSONResponse { diff --git a/dendrite-sample.monolith.yaml b/dendrite-sample.monolith.yaml index 8759b534a..5195c29bc 100644 --- a/dendrite-sample.monolith.yaml +++ b/dendrite-sample.monolith.yaml @@ -181,14 +181,6 @@ client_api: recaptcha_bypass_secret: "" recaptcha_siteverify_api: "" - # Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option. - # By default, any room aliases included in this list will be created as a publicly joinable room - # when the first user registers for the homeserver. If the room already exists, - # make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'. - # As Spaces are just rooms under the hood, Space aliases may also be used. - auto_join_rooms: -# - "#main:matrix.org" - # TURN server information that this homeserver should send to clients. turn: turn_user_lifetime: "5m" @@ -318,6 +310,14 @@ user_api: # The default lifetime is 3600000ms (60 minutes). # openid_token_lifetime_ms: 3600000 + # Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option. + # By default, any room aliases included in this list will be created as a publicly joinable room + # when the first user registers for the homeserver. If the room already exists, + # make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'. + # As Spaces are just rooms under the hood, Space aliases may also be used. + auto_join_rooms: + # - "#main:matrix.org" + # Configuration for Opentracing. # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # how this works and how to set it up. diff --git a/dendrite-sample.polylith.yaml b/dendrite-sample.polylith.yaml index 453bebc7c..bbbe16fdc 100644 --- a/dendrite-sample.polylith.yaml +++ b/dendrite-sample.polylith.yaml @@ -177,14 +177,6 @@ client_api: recaptcha_bypass_secret: "" recaptcha_siteverify_api: "" - # Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option. - # By default, any room aliases included in this list will be created as a publicly joinable room - # when the first user registers for the homeserver. If the room already exists, - # make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'. - # As Spaces are just rooms under the hood, Space aliases may also be used. - auto_join_rooms: - # - "#main:matrix.org" - # TURN server information that this homeserver should send to clients. turn: turn_user_lifetime: "5m" @@ -383,6 +375,14 @@ user_api: # The default lifetime is 3600000ms (60 minutes). # openid_token_lifetime_ms: 3600000 + # Users who register on this homeserver will automatically be joined to the rooms listed under "auto_join_rooms" option. + # By default, any room aliases included in this list will be created as a publicly joinable room + # when the first user registers for the homeserver. If the room already exists, + # make certain it is a publicly joinable room, i.e. the join rule of the room must be set to 'public'. + # As Spaces are just rooms under the hood, Space aliases may also be used. + auto_join_rooms: + # - "#main:matrix.org" + # Configuration for Opentracing. # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # how this works and how to set it up. diff --git a/roomserver/api/api.go b/roomserver/api/api.go index baf63aa31..403bbe8be 100644 --- a/roomserver/api/api.go +++ b/roomserver/api/api.go @@ -167,6 +167,7 @@ type UserRoomserverAPI interface { QueryCurrentState(ctx context.Context, req *QueryCurrentStateRequest, res *QueryCurrentStateResponse) error QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error + PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error } type FederationRoomserverAPI interface { diff --git a/setup/config/config_clientapi.go b/setup/config/config_clientapi.go index 76e062172..56f4b3f92 100644 --- a/setup/config/config_clientapi.go +++ b/setup/config/config_clientapi.go @@ -29,10 +29,6 @@ type ClientAPI struct { // is forbidden either way. GuestsDisabled bool `yaml:"guests_disabled"` - // Users who register on this homeserver will automatically - // be joined to the rooms listed under this option. - AutoJoinRooms []string `yaml:"auto_join_rooms"` - // Boolean stating whether catpcha registration is enabled // and required RecaptchaEnabled bool `yaml:"enable_registration_captcha"` diff --git a/setup/config/config_userapi.go b/setup/config/config_userapi.go index 97a6d738b..f8ad41d93 100644 --- a/setup/config/config_userapi.go +++ b/setup/config/config_userapi.go @@ -19,6 +19,10 @@ type UserAPI struct { // The Account database stores the login details and account information // for local users. It is accessed by the UserAPI. AccountDatabase DatabaseOptions `yaml:"account_database,omitempty"` + + // Users who register on this homeserver will automatically + // be joined to the rooms listed under this option. + AutoJoinRooms []string `yaml:"auto_join_rooms"` } const DefaultOpenIDTokenLifetimeMS = 3600000 // 60 minutes diff --git a/userapi/internal/api.go b/userapi/internal/api.go index 63044eedb..7b94b3da7 100644 --- a/userapi/internal/api.go +++ b/userapi/internal/api.go @@ -54,6 +54,7 @@ type UserInternalAPI struct { KeyAPI keyapi.UserKeyAPI RSAPI rsapi.UserRoomserverAPI PgClient pushgateway.Client + Cfg *config.UserAPI } func (a *UserInternalAPI) InputAccountData(ctx context.Context, req *api.InputAccountDataRequest, res *api.InputAccountDataResponse) error { @@ -130,6 +131,45 @@ func (a *UserInternalAPI) setFullyRead(ctx context.Context, req *api.InputAccoun return nil } +func postRegisterJoinRooms(cfg *config.UserAPI, acc *api.Account, rsAPI rsapi.UserRoomserverAPI) { + // POST register behaviour: check if the user is a normal user. + // If the user is a normal user, add user to room specified in the configuration "auto_join_rooms". + if acc.AccountType != api.AccountTypeAppService && acc.AppServiceID == "" { + for room := range cfg.AutoJoinRooms { + userID := userutil.MakeUserID(acc.Localpart, cfg.Matrix.ServerName) + err := addUserToRoom(context.Background(), rsAPI, cfg.AutoJoinRooms[room], acc.Localpart, userID) + if err != nil { + logrus.WithFields(logrus.Fields{ + "user_id": userID, + "room": cfg.AutoJoinRooms[room], + }).WithError(err).Errorf("user failed to auto-join room") + } + } + } +} + +// Add user to a room. This function currently working for auto_join_rooms config, +// which can add a newly registered user to a specified room. +func addUserToRoom( + ctx context.Context, + rsAPI rsapi.UserRoomserverAPI, + roomID string, + username string, + userID string, +) error { + addGroupContent := make(map[string]interface{}) + // This make sure the user's username can be displayed correctly. + // Because the newly-registered user doesn't have an avatar, the avatar_url is not needed. + addGroupContent["displayname"] = username + joinReq := rsapi.PerformJoinRequest{ + RoomIDOrAlias: roomID, + UserID: userID, + Content: addGroupContent, + } + joinRes := rsapi.PerformJoinResponse{} + return rsAPI.PerformJoin(ctx, &joinReq, &joinRes) +} + func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.PerformAccountCreationRequest, res *api.PerformAccountCreationResponse) error { acc, err := a.DB.CreateAccount(ctx, req.Localpart, req.Password, req.AppServiceID, req.AccountType) if err != nil { @@ -174,6 +214,8 @@ func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.P return err } + postRegisterJoinRooms(a.Cfg, acc, a.RSAPI) + res.AccountCreated = true res.Account = acc return nil diff --git a/userapi/userapi.go b/userapi/userapi.go index d26b4e19a..c077248e2 100644 --- a/userapi/userapi.go +++ b/userapi/userapi.go @@ -82,6 +82,7 @@ func NewInternalAPI( RSAPI: rsAPI, DisableTLSValidation: cfg.PushGatewayDisableTLSValidation, PgClient: pgClient, + Cfg: cfg, } receiptConsumer := consumers.NewOutputReceiptEventConsumer(