move auto_join_rooms implementation to userapi

This commit is contained in:
Neboer 2022-10-26 15:27:05 +08:00
parent 9fb11ba1f5
commit 2b8d898b08
9 changed files with 77 additions and 86 deletions

View file

@ -19,7 +19,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
rsAPI "github.com/matrix-org/dendrite/roomserver/api"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -537,7 +536,6 @@ func validateApplicationService(
func Register( func Register(
req *http.Request, req *http.Request,
userAPI userapi.ClientUserAPI, userAPI userapi.ClientUserAPI,
clientRsApi rsAPI.ClientRoomserverAPI,
cfg *config.ClientAPI, cfg *config.ClientAPI,
) util.JSONResponse { ) util.JSONResponse {
defer req.Body.Close() // nolint: errcheck defer req.Body.Close() // nolint: errcheck
@ -634,7 +632,7 @@ func Register(
"session_id": r.Auth.Session, "session_id": r.Auth.Session,
}).Info("Processing registration request") }).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( func handleGuestRegistration(
@ -701,15 +699,13 @@ func handleGuestRegistration(
// handleRegistrationFlow will direct and complete registration flow stages // handleRegistrationFlow will direct and complete registration flow stages
// that the client has requested. // that the client has requested.
// nolint: gocyclo // nolint: gocyclo
func handleRegistrationFlow( func handleRegistrationFlow(req *http.Request,
req *http.Request,
r registerRequest, r registerRequest,
sessionID string, sessionID string,
cfg *config.ClientAPI, cfg *config.ClientAPI,
userAPI userapi.ClientUserAPI, userAPI userapi.ClientUserAPI,
accessToken string, accessToken string,
accessTokenErr error, accessTokenErr error,
clientRsApi rsAPI.ClientRoomserverAPI,
) util.JSONResponse { ) util.JSONResponse {
// TODO: Enable registration config flag // TODO: Enable registration config flag
// TODO: Guest account upgrading // TODO: Guest account upgrading
@ -725,7 +721,7 @@ func handleRegistrationFlow(
// the login type specifically requests it. // the login type specifically requests it.
if r.Type == authtypes.LoginTypeApplicationService && accessTokenErr == nil { if r.Type == authtypes.LoginTypeApplicationService && accessTokenErr == nil {
return handleApplicationServiceRegistration( 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 // Check if the user's registration flow has been completed successfully
// A response with current registration flow and remaining available methods // A response with current registration flow and remaining available methods
// will be returned if a flow has not been successfully completed yet // 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 // 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 // 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 // token doesn't belong to a valid AS, or if there was an issue completing the
// registration process. // registration process.
func handleApplicationServiceRegistration( func handleApplicationServiceRegistration(accessToken string, tokenErr error, req *http.Request, r registerRequest, cfg *config.ClientAPI, userAPI userapi.ClientUserAPI) util.JSONResponse {
accessToken string,
tokenErr error,
req *http.Request,
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 // Check if we previously had issues extracting the access token from the
// request. // request.
if tokenErr != nil { if tokenErr != nil {
@ -820,8 +808,8 @@ func handleApplicationServiceRegistration(
// Don't need to worry about appending to registration stages as // Don't need to worry about appending to registration stages as
// application service registration is entirely separate. // application service registration is entirely separate.
return completeRegistration( return completeRegistration(
req.Context(), userAPI, clientRsApi, r.Username, "", appserviceID, req.RemoteAddr, req.UserAgent(), r.Auth.Session, req.Context(), userAPI, r.Username, "", appserviceID, req.RemoteAddr, req.UserAgent(), r.Auth.Session,
cfg, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeAppService, r.InhibitLogin, r.InitialDisplayName, r.DeviceID, userapi.AccountTypeAppService,
) )
} }
@ -833,15 +821,11 @@ func checkAndCompleteFlow(flow []authtypes.LoginType,
r registerRequest, r registerRequest,
sessionID string, sessionID string,
cfg *config.ClientAPI, cfg *config.ClientAPI,
userAPI userapi.ClientUserAPI, userAPI userapi.ClientUserAPI) util.JSONResponse {
clientRsApi rsAPI.ClientRoomserverAPI) util.JSONResponse {
if checkFlowCompleted(flow, cfg.Derived.Registration.Flows) { if checkFlowCompleted(flow, cfg.Derived.Registration.Flows) {
// This flow was completed, registration can continue // This flow was completed, registration can continue
return completeRegistration( 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) sessions.addParams(sessionID, r)
// There are still more stages to complete. // 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 // completeRegistration runs some rudimentary checks against the submitted
// input, then if successful creates an account and a newly associated device // 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 // We pass in each individual part of the request here instead of just passing a
@ -885,9 +846,7 @@ func addUserToRoom(
func completeRegistration( func completeRegistration(
ctx context.Context, ctx context.Context,
userAPI userapi.ClientUserAPI, userAPI userapi.ClientUserAPI,
clientRsApi rsAPI.ClientRoomserverAPI,
username, password, appserviceID, ipAddr, userAgent, sessionID string, username, password, appserviceID, ipAddr, userAgent, sessionID string,
cfg *config.ClientAPI,
inhibitLogin eventutil.WeakBoolean, inhibitLogin eventutil.WeakBoolean,
displayName, deviceID *string, displayName, deviceID *string,
accType userapi.AccountType, accType userapi.AccountType,
@ -973,18 +932,6 @@ func completeRegistration(
} }
sessions.addCompletedRegistration(sessionID, result) 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{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: result, 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) ssrr, err := NewSharedSecretRegistrationRequest(req.Body)
if err != nil { if err != nil {
return util.JSONResponse{ return util.JSONResponse{
@ -1132,5 +1079,5 @@ func handleSharedSecretRegistration(cfg *config.ClientAPI, userAPI userapi.Clien
if ssrr.Admin { if ssrr.Admin {
accType = userapi.AccountTypeAdmin 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)
} }

View file

@ -135,7 +135,7 @@ func Setup(
} }
} }
if req.Method == http.MethodPost { if req.Method == http.MethodPost {
return handleSharedSecretRegistration(cfg, userAPI, rsAPI, sr, req) return handleSharedSecretRegistration(cfg, userAPI, sr, req)
} }
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusMethodNotAllowed, Code: http.StatusMethodNotAllowed,
@ -432,7 +432,7 @@ func Setup(
if r := rateLimits.Limit(req, nil); r != nil { if r := rateLimits.Limit(req, nil); r != nil {
return *r return *r
} }
return Register(req, userAPI, rsAPI, cfg) return Register(req, userAPI, cfg)
})).Methods(http.MethodPost, http.MethodOptions) })).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/register/available", httputil.MakeExternalAPI("registerAvailable", func(req *http.Request) util.JSONResponse { v3mux.Handle("/register/available", httputil.MakeExternalAPI("registerAvailable", func(req *http.Request) util.JSONResponse {

View file

@ -181,14 +181,6 @@ client_api:
recaptcha_bypass_secret: "" recaptcha_bypass_secret: ""
recaptcha_siteverify_api: "" 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 server information that this homeserver should send to clients.
turn: turn:
turn_user_lifetime: "5m" turn_user_lifetime: "5m"
@ -318,6 +310,14 @@ user_api:
# The default lifetime is 3600000ms (60 minutes). # The default lifetime is 3600000ms (60 minutes).
# openid_token_lifetime_ms: 3600000 # 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. # Configuration for Opentracing.
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on
# how this works and how to set it up. # how this works and how to set it up.

View file

@ -177,14 +177,6 @@ client_api:
recaptcha_bypass_secret: "" recaptcha_bypass_secret: ""
recaptcha_siteverify_api: "" 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 server information that this homeserver should send to clients.
turn: turn:
turn_user_lifetime: "5m" turn_user_lifetime: "5m"
@ -383,6 +375,14 @@ user_api:
# The default lifetime is 3600000ms (60 minutes). # The default lifetime is 3600000ms (60 minutes).
# openid_token_lifetime_ms: 3600000 # 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. # Configuration for Opentracing.
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on
# how this works and how to set it up. # how this works and how to set it up.

View file

@ -167,6 +167,7 @@ type UserRoomserverAPI interface {
QueryCurrentState(ctx context.Context, req *QueryCurrentStateRequest, res *QueryCurrentStateResponse) error QueryCurrentState(ctx context.Context, req *QueryCurrentStateRequest, res *QueryCurrentStateResponse) error
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error
PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error
} }
type FederationRoomserverAPI interface { type FederationRoomserverAPI interface {

View file

@ -29,10 +29,6 @@ type ClientAPI struct {
// is forbidden either way. // is forbidden either way.
GuestsDisabled bool `yaml:"guests_disabled"` 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 // Boolean stating whether catpcha registration is enabled
// and required // and required
RecaptchaEnabled bool `yaml:"enable_registration_captcha"` RecaptchaEnabled bool `yaml:"enable_registration_captcha"`

View file

@ -19,6 +19,10 @@ type UserAPI struct {
// The Account database stores the login details and account information // The Account database stores the login details and account information
// for local users. It is accessed by the UserAPI. // for local users. It is accessed by the UserAPI.
AccountDatabase DatabaseOptions `yaml:"account_database,omitempty"` 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 const DefaultOpenIDTokenLifetimeMS = 3600000 // 60 minutes

View file

@ -54,6 +54,7 @@ type UserInternalAPI struct {
KeyAPI keyapi.UserKeyAPI KeyAPI keyapi.UserKeyAPI
RSAPI rsapi.UserRoomserverAPI RSAPI rsapi.UserRoomserverAPI
PgClient pushgateway.Client PgClient pushgateway.Client
Cfg *config.UserAPI
} }
func (a *UserInternalAPI) InputAccountData(ctx context.Context, req *api.InputAccountDataRequest, res *api.InputAccountDataResponse) error { 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 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 { 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) acc, err := a.DB.CreateAccount(ctx, req.Localpart, req.Password, req.AppServiceID, req.AccountType)
if err != nil { if err != nil {
@ -174,6 +214,8 @@ func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.P
return err return err
} }
postRegisterJoinRooms(a.Cfg, acc, a.RSAPI)
res.AccountCreated = true res.AccountCreated = true
res.Account = acc res.Account = acc
return nil return nil

View file

@ -82,6 +82,7 @@ func NewInternalAPI(
RSAPI: rsAPI, RSAPI: rsAPI,
DisableTLSValidation: cfg.PushGatewayDisableTLSValidation, DisableTLSValidation: cfg.PushGatewayDisableTLSValidation,
PgClient: pgClient, PgClient: pgClient,
Cfg: cfg,
} }
receiptConsumer := consumers.NewOutputReceiptEventConsumer( receiptConsumer := consumers.NewOutputReceiptEventConsumer(