From bb524367eba8841f68c22dcc9aeb060e33c57b7b Mon Sep 17 00:00:00 2001
From: Evan Goode
Date: Sat, 23 Aug 2025 20:34:20 -0400
Subject: [PATCH] Respect RegistrationOIDC.RequireInvite
This previously setting had no effect when clicking 'Sign in with
$PROVIDER' on the home page.
---
front.go | 22 ++++----
user.go | 55 +++++++++-----------
view/complete-registration.tmpl | 92 ++++++++++++++++++---------------
3 files changed, 85 insertions(+), 84 deletions(-)
diff --git a/front.go b/front.go
index 274a725..ad5bb1d 100644
--- a/front.go
+++ b/front.go
@@ -560,11 +560,11 @@ func (app *App) getIDTokenCookie(c *echo.Context) (*OIDCProvider, string, oidc.I
func FrontCompleteRegistration(app *App) func(c echo.Context) error {
type completeRegistrationContext struct {
baseContext
- User *User
- InviteCode string
- AnyUnmigratedUsers bool
- AllowChoosingPlayerName bool
- PreferredPlayerName string
+ User *User
+ InviteCode string
+ OIDCProvider *OIDCProvider
+ AnyUnmigratedUsers bool
+ PreferredPlayerName string
}
returnURL := Unwrap(url.JoinPath(app.FrontEndURL, "web/registration"))
@@ -600,12 +600,12 @@ func FrontCompleteRegistration(app *App) func(c echo.Context) error {
}
return c.Render(http.StatusOK, "complete-registration", completeRegistrationContext{
- baseContext: app.NewBaseContext(&c),
- User: user,
- InviteCode: inviteCode,
- PreferredPlayerName: preferredPlayerName,
- AllowChoosingPlayerName: provider.Config.AllowChoosingPlayerName,
- AnyUnmigratedUsers: anyUnmigratedUsers,
+ baseContext: app.NewBaseContext(&c),
+ User: user,
+ InviteCode: inviteCode,
+ PreferredPlayerName: preferredPlayerName,
+ OIDCProvider: provider,
+ AnyUnmigratedUsers: anyUnmigratedUsers,
})
})
}
diff --git a/user.go b/user.go
index e624a75..a2a2f1e 100644
--- a/user.go
+++ b/user.go
@@ -95,6 +95,21 @@ func (app *App) CreateUser(
}
}
+ var invite mo.Option[Invite]
+ if inviteCode != nil {
+ var inviteStruct Invite
+ result := app.DB.First(&inviteStruct, "code = ?", *inviteCode)
+ if result.Error != nil {
+ if errors.Is(result.Error, gorm.ErrRecordNotFound) {
+ return User{}, InviteNotFoundError
+ } else {
+ return User{}, result.Error
+ }
+ } else {
+ invite = mo.Some(inviteStruct)
+ }
+ }
+
oidcIdentities := make([]UserOIDCIdentity, 0, len(oidcIdentitySpecs.Value))
for _, oidcIdentitySpec := range oidcIdentitySpecs.Value {
provider, ok := app.OIDCProvidersByIssuer[oidcIdentitySpec.Issuer]
@@ -104,6 +119,9 @@ func (app *App) CreateUser(
if oidcIdentitySpec.Subject == "" {
return User{}, NewBadRequestUserError("OIDC subject for provider %s can't be blank.", provider.Config.Issuer)
}
+ if !callerIsAdmin && invite.IsAbsent() && provider.Config.RequireInvite {
+ return User{}, InviteMissingError
+ }
oidcIdentities = append(oidcIdentities, UserOIDCIdentity{
UserUUID: userUUID,
Issuer: provider.Config.Issuer,
@@ -125,26 +143,6 @@ func (app *App) CreateUser(
return User{}, NewBadRequestUserError("Invalid preferred language.")
}
- getInvite := func(requireInvite bool) (*Invite, error) {
- var invite Invite
- if inviteCode == nil {
- if requireInvite && !callerIsAdmin {
- return nil, InviteMissingError
- }
- return nil, nil
- } else {
- result := app.DB.First(&invite, "code = ?", *inviteCode)
- if result.Error != nil {
- if errors.Is(result.Error, gorm.ErrRecordNotFound) {
- return nil, InviteNotFoundError
- }
- return nil, result.Error
- }
- return &invite, nil
- }
- }
-
- var invite *Invite
var playerUUID string
if existingPlayer {
// Existing player registration
@@ -152,10 +150,8 @@ func (app *App) CreateUser(
return User{}, NewBadRequestUserError("Registration from an existing player is not allowed.")
}
- var err error
- invite, err = getInvite(app.Config.RegistrationExistingPlayer.RequireInvite)
- if err != nil {
- return User{}, err
+ if !callerIsAdmin && invite.IsAbsent() && app.Config.RegistrationExistingPlayer.RequireInvite {
+ return User{}, InviteMissingError
}
if err := app.ValidatePlayerName(*playerName); err != nil {
@@ -182,13 +178,12 @@ func (app *App) CreateUser(
return User{}, NewBadRequestUserError("Registration without some existing player is not allowed.")
}
- var err error
- invite, err = getInvite(app.Config.RegistrationNewPlayer.RequireInvite)
- if err != nil {
- return User{}, err
+ if !callerIsAdmin && invite.IsAbsent() && app.Config.RegistrationNewPlayer.RequireInvite {
+ return User{}, InviteMissingError
}
if chosenUUID == nil {
+ var err error
playerUUID, err = app.NewPlayerUUID(*playerName)
if err != nil {
return User{}, err
@@ -332,8 +327,8 @@ func (app *App) CreateUser(
}
}
- if invite != nil {
- if err := tx.Delete(invite).Error; err != nil {
+ if i, ok := invite.Get(); ok {
+ if err := tx.Delete(i).Error; err != nil {
return User{}, err
}
}
diff --git a/view/complete-registration.tmpl b/view/complete-registration.tmpl
index 1f21940..ab7f0a0 100644
--- a/view/complete-registration.tmpl
+++ b/view/complete-registration.tmpl
@@ -16,7 +16,7 @@
{{ end }}
{{ call .T "Migrate an existing user" }}
- {{ call .T "You can link this identity provider to an existing %s account." }} {{ call .T "If you do so, you will no longer be able to log in using your %s password. You'll need to use your Minecraft Token to log in to Minecraft launchers." }}
+ {{ call .T "You can link this identity provider to an existing %s account." .App.Config.ApplicationName }} {{ call .T "If you do so, you will no longer be able to log in using your %s password. You'll need to use your Minecraft Token to log in to Minecraft launchers." .App.Config.ApplicationName }}
- {{ $dividerNeeded := true }}
+ {{ $dividerNeeded = true }}
{{ end }}
@@ -39,46 +39,52 @@
{{ $dividerNeeded = false }}
{{ end }}
{{ call .T "Create a player" }}
- {{ call .T "Complete registration by creating a new player:" }}
-
+ {{ else if and .App.Config.RegistrationExistingPlayer.RequireInvite (not .InviteCode) }}
+ {{ call .T "Registration as a new player is invite-only." }}
+ {{ else }}
+ {{ call .T "Complete registration by creating a new player:" }}
+
+
+ {{ end }}
{{ $dividerNeeded = true }}
{{ end }}
@@ -89,9 +95,9 @@
{{ $dividerNeeded = false }}
{{ end }}
{{ call .T "Register from an existing Minecraft player" }}
- {{ if and .App.Config.RegistrationExistingPlayer.RequireInvite (not
- .InviteCode)
- }}
+ {{ if and .OIDCProvider.Config.RequireInvite (not .InviteCode) }}
+ {{ call .T "Registration with %s requires an invite." .OIDCProvider.Config.Name }}
+ {{ else if and .App.Config.RegistrationExistingPlayer.RequireInvite (not .InviteCode) }}
{{ call .T "Registration as an existing player is invite-only." }}
{{ else }}
{{ if .App.Config.ImportExistingPlayer.RequireSkinVerification }}
@@ -111,7 +117,7 @@
name="playerName"
placeholder="{{ call .T "%s player name" .App.Config.ImportExistingPlayer.Nickname }}"
maxlength="{{ .App.Constants.MaxUsernameLength }}"
- {{ if not .AllowChoosingPlayerName }}
+ {{ if not .OIDCProvider.Config.AllowChoosingPlayerName }}
value="{{ .PreferredPlayerName }}"
title="{{ call .T "Choosing a player name is not allowed." }}"
disabled