diff --git a/pkg/modules/auth/openid/openid.go b/pkg/modules/auth/openid/openid.go index 381570f42..b1fa3961a 100644 --- a/pkg/modules/auth/openid/openid.go +++ b/pkg/modules/auth/openid/openid.go @@ -27,6 +27,7 @@ import ( "strings" "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/events" "code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/models" "code.vikunja.io/api/pkg/modules/auth" @@ -187,6 +188,9 @@ func HandleCallback(c *echo.Context) error { s := db.NewSession() defer s.Close() + // Discards events queued during a rolled-back transaction (e.g. user + // creation); a no-op once DispatchPending has run. + defer events.CleanupPending(s) // Check if we have seen this user before u, err := getOrCreateUser(s, cl, provider, idToken) @@ -212,6 +216,9 @@ func HandleCallback(c *echo.Context) error { if err := enforceTOTPIfRequired(s, u, cb.TOTPPasscode); err != nil { if commitErr := s.Commit(); commitErr != nil { log.Errorf("Error committing session after failed OIDC TOTP attempt for user %d: %v", u.ID, commitErr) + } else { + // The user creation above was committed, so its events are real. + events.DispatchPending(c.Request().Context(), s) } if user.IsErrInvalidTOTPPasscode(err) { user.HandleFailedTOTPAuth(u) @@ -233,6 +240,8 @@ func HandleCallback(c *echo.Context) error { return err } + events.DispatchPending(c.Request().Context(), s) + // Create token return auth.NewUserAuthTokenResponse(u, c, false) } diff --git a/pkg/routes/api/shared/auth.go b/pkg/routes/api/shared/auth.go index d11a1cdbb..925a533d8 100644 --- a/pkg/routes/api/shared/auth.go +++ b/pkg/routes/api/shared/auth.go @@ -17,8 +17,11 @@ package shared import ( + "context" + "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/db" + "code.vikunja.io/api/pkg/events" "code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/metrics" "code.vikunja.io/api/pkg/models" @@ -39,9 +42,12 @@ type UserRegister struct { // busts the cached user-count metric so the registration shows up immediately. // The caller is responsible for the registration-enabled gate and input // validation; both v1 and v2 share this body. -func RegisterUser(in *UserRegister) (*user.User, error) { +func RegisterUser(ctx context.Context, in *UserRegister) (*user.User, error) { s := db.NewSession() defer s.Close() + // Discards events queued during a rolled-back transaction; a no-op once + // DispatchPending has run. + defer events.CleanupPending(s) newUser, err := models.RegisterUser(s, &user.User{ Username: in.Username, @@ -59,6 +65,8 @@ func RegisterUser(in *UserRegister) (*user.User, error) { return nil, err } + events.DispatchPending(ctx, s) + // Bust the cached user count so the new registration shows up in metrics // immediately instead of after the regular cache expiry. if config.MetricsEnabled.GetBool() { diff --git a/pkg/routes/api/v1/login.go b/pkg/routes/api/v1/login.go index 6c7eb686a..7385ed1f6 100644 --- a/pkg/routes/api/v1/login.go +++ b/pkg/routes/api/v1/login.go @@ -53,6 +53,9 @@ func Login(c *echo.Context) (err error) { s := db.NewSession() defer s.Close() + // Discards events queued during a rolled-back transaction (e.g. LDAP user + // creation); a no-op once DispatchPending has run. + defer events.CleanupPending(s) var user *user2.User if config.AuthLdapEnabled.GetBool() { @@ -127,6 +130,8 @@ func Login(c *echo.Context) (err error) { return err } + events.DispatchPending(c.Request().Context(), s) + // Create token return auth.NewUserAuthTokenResponse(user, c, u.LongToken) } diff --git a/pkg/routes/api/v1/user_register.go b/pkg/routes/api/v1/user_register.go index 1c70df765..e9a90dc2f 100644 --- a/pkg/routes/api/v1/user_register.go +++ b/pkg/routes/api/v1/user_register.go @@ -63,7 +63,7 @@ func RegisterUser(c *echo.Context) error { return c.JSON(http.StatusBadRequest, models.Message{Message: "No or invalid user model provided."}) } - newUser, err := shared.RegisterUser(userIn) + newUser, err := shared.RegisterUser(c.Request().Context(), userIn) if err != nil { return err } diff --git a/pkg/routes/api/v2/auth_public.go b/pkg/routes/api/v2/auth_public.go index 5791b7c3f..c41fb162d 100644 --- a/pkg/routes/api/v2/auth_public.go +++ b/pkg/routes/api/v2/auth_public.go @@ -127,8 +127,8 @@ func registerLocalAuthRoutes(api huma.API) { }, authConfirmEmail) } -func authRegister(_ context.Context, in *struct{ Body shared.UserRegister }) (*registerUserBody, error) { - newUser, err := shared.RegisterUser(&in.Body) +func authRegister(ctx context.Context, in *struct{ Body shared.UserRegister }) (*registerUserBody, error) { + newUser, err := shared.RegisterUser(ctx, &in.Body) if err != nil { return nil, translateDomainError(err) }