diff --git a/clientapi/routing/register.go b/clientapi/routing/register.go index ce6076a71..925e18611 100644 --- a/clientapi/routing/register.go +++ b/clientapi/routing/register.go @@ -725,7 +725,7 @@ func handleRegistrationFlow( // the login type specifically requests it. if r.Type == authtypes.LoginTypeApplicationService && accessTokenErr == nil { return handleApplicationServiceRegistration( - accessToken, accessTokenErr, req, r, cfg, userAPI, + accessToken, accessTokenErr, req, r, cfg, userAPI, clientRsApi, ) } @@ -796,6 +796,7 @@ func handleApplicationServiceRegistration( r registerRequest, cfg *config.ClientAPI, userAPI userapi.ClientUserAPI, + clientRsApi rsAPI.ClientRoomserverAPI, ) util.JSONResponse { // Check if we previously had issues extracting the access token from the // request. @@ -819,8 +820,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, r.Username, "", appserviceID, req.RemoteAddr, req.UserAgent(), r.Auth.Session, - r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeAppService, + req.Context(), userAPI, clientRsApi, r.Username, "", appserviceID, req.RemoteAddr, req.UserAgent(), r.Auth.Session, + cfg, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeAppService, ) } @@ -836,20 +837,10 @@ func checkAndCompleteFlow(flow []authtypes.LoginType, clientRsApi rsAPI.ClientRoomserverAPI) util.JSONResponse { if checkFlowCompleted(flow, cfg.Derived.Registration.Flows) { - // POST register behavior: add user to room - for room := range cfg.AutoJoinRooms { - err := addUserToRoom(req.Context(), clientRsApi, cfg.AutoJoinRooms[room], r.Username, - userutil.MakeUserID(r.Username, cfg.Matrix.ServerName)) - if err != nil { - log.Fatal(err) - return util.JSONResponse{Code: http.StatusInternalServerError, - JSON: errorResponse(req.Context(), err, "Cannot add user to room.")} - } - } // This flow was completed, registration can continue return completeRegistration( - req.Context(), userAPI, r.Username, r.Password, "", req.RemoteAddr, req.UserAgent(), sessionID, - r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeUser, + req.Context(), userAPI, clientRsApi, r.Username, r.Password, "", req.RemoteAddr, req.UserAgent(), sessionID, + cfg, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeUser, ) } sessions.addParams(sessionID, r) @@ -862,6 +853,8 @@ 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, @@ -870,6 +863,9 @@ func addUserToRoom( 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, @@ -889,7 +885,9 @@ 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, @@ -975,6 +973,17 @@ func completeRegistration( } sessions.addCompletedRegistration(sessionID, result) + defer func() { + // POST register behavior: add user to room specified in the configuration "auto_join_rooms" + 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, @@ -1089,7 +1098,7 @@ func RegisterAvailable( } } -func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.ClientUserAPI, sr *SharedSecretRegistration, req *http.Request) util.JSONResponse { +func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.ClientUserAPI, clientRsApi rsAPI.ClientRoomserverAPI, sr *SharedSecretRegistration, req *http.Request) util.JSONResponse { ssrr, err := NewSharedSecretRegistrationRequest(req.Body) if err != nil { return util.JSONResponse{ @@ -1122,5 +1131,5 @@ func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.Clien if ssrr.Admin { accType = userapi.AccountTypeAdmin } - return completeRegistration(req.Context(), userAPI, ssrr.User, ssrr.Password, "", req.RemoteAddr, req.UserAgent(), "", false, &ssrr.User, &deviceID, accType) + return completeRegistration(req.Context(), userAPI, clientRsApi, ssrr.User, ssrr.Password, "", req.RemoteAddr, req.UserAgent(), "", cfg, false, &ssrr.User, &deviceID, accType) } diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index 1a1ed05d0..d95adb990 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, sr, req) + return handleSharedSecretRegistration(cfg, userAPI, rsAPI, sr, req) } return util.JSONResponse{ Code: http.StatusMethodNotAllowed, diff --git a/dendrite-sample.monolith.yaml b/dendrite-sample.monolith.yaml index c0f6fe99f..8759b534a 100644 --- a/dendrite-sample.monolith.yaml +++ b/dendrite-sample.monolith.yaml @@ -181,7 +181,12 @@ client_api: recaptcha_bypass_secret: "" recaptcha_siteverify_api: "" -# auto_join_rooms: + # 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. diff --git a/dendrite-sample.polylith.yaml b/dendrite-sample.polylith.yaml index aa7e0cc38..453bebc7c 100644 --- a/dendrite-sample.polylith.yaml +++ b/dendrite-sample.polylith.yaml @@ -177,6 +177,14 @@ 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"