Respect RegistrationOIDC.RequireInvite

This previously setting had no effect when clicking 'Sign in with
$PROVIDER' on the home page.
This commit is contained in:
Evan Goode 2025-08-23 20:34:20 -04:00
parent 1c53e8c2dd
commit bb524367eb
3 changed files with 85 additions and 84 deletions

View File

@ -562,8 +562,8 @@ func FrontCompleteRegistration(app *App) func(c echo.Context) error {
baseContext baseContext
User *User User *User
InviteCode string InviteCode string
OIDCProvider *OIDCProvider
AnyUnmigratedUsers bool AnyUnmigratedUsers bool
AllowChoosingPlayerName bool
PreferredPlayerName string PreferredPlayerName string
} }
@ -604,7 +604,7 @@ func FrontCompleteRegistration(app *App) func(c echo.Context) error {
User: user, User: user,
InviteCode: inviteCode, InviteCode: inviteCode,
PreferredPlayerName: preferredPlayerName, PreferredPlayerName: preferredPlayerName,
AllowChoosingPlayerName: provider.Config.AllowChoosingPlayerName, OIDCProvider: provider,
AnyUnmigratedUsers: anyUnmigratedUsers, AnyUnmigratedUsers: anyUnmigratedUsers,
}) })
}) })

55
user.go
View File

@ -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)) oidcIdentities := make([]UserOIDCIdentity, 0, len(oidcIdentitySpecs.Value))
for _, oidcIdentitySpec := range oidcIdentitySpecs.Value { for _, oidcIdentitySpec := range oidcIdentitySpecs.Value {
provider, ok := app.OIDCProvidersByIssuer[oidcIdentitySpec.Issuer] provider, ok := app.OIDCProvidersByIssuer[oidcIdentitySpec.Issuer]
@ -104,6 +119,9 @@ func (app *App) CreateUser(
if oidcIdentitySpec.Subject == "" { if oidcIdentitySpec.Subject == "" {
return User{}, NewBadRequestUserError("OIDC subject for provider %s can't be blank.", provider.Config.Issuer) 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{ oidcIdentities = append(oidcIdentities, UserOIDCIdentity{
UserUUID: userUUID, UserUUID: userUUID,
Issuer: provider.Config.Issuer, Issuer: provider.Config.Issuer,
@ -125,26 +143,6 @@ func (app *App) CreateUser(
return User{}, NewBadRequestUserError("Invalid preferred language.") 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 var playerUUID string
if existingPlayer { if existingPlayer {
// Existing player registration // Existing player registration
@ -152,10 +150,8 @@ func (app *App) CreateUser(
return User{}, NewBadRequestUserError("Registration from an existing player is not allowed.") return User{}, NewBadRequestUserError("Registration from an existing player is not allowed.")
} }
var err error if !callerIsAdmin && invite.IsAbsent() && app.Config.RegistrationExistingPlayer.RequireInvite {
invite, err = getInvite(app.Config.RegistrationExistingPlayer.RequireInvite) return User{}, InviteMissingError
if err != nil {
return User{}, err
} }
if err := app.ValidatePlayerName(*playerName); err != nil { 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.") return User{}, NewBadRequestUserError("Registration without some existing player is not allowed.")
} }
var err error if !callerIsAdmin && invite.IsAbsent() && app.Config.RegistrationNewPlayer.RequireInvite {
invite, err = getInvite(app.Config.RegistrationNewPlayer.RequireInvite) return User{}, InviteMissingError
if err != nil {
return User{}, err
} }
if chosenUUID == nil { if chosenUUID == nil {
var err error
playerUUID, err = app.NewPlayerUUID(*playerName) playerUUID, err = app.NewPlayerUUID(*playerName)
if err != nil { if err != nil {
return User{}, err return User{}, err
@ -332,8 +327,8 @@ func (app *App) CreateUser(
} }
} }
if invite != nil { if i, ok := invite.Get(); ok {
if err := tx.Delete(invite).Error; err != nil { if err := tx.Delete(i).Error; err != nil {
return User{}, err return User{}, err
} }
} }

View File

@ -16,7 +16,7 @@
{{ end }} {{ end }}
<h3>{{ call .T "Migrate an existing user" }}</h3> <h3>{{ call .T "Migrate an existing user" }}</h3>
<p>{{ call .T "You can link this identity provider to an existing %s account." }} <span class="warning-message">{{ 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." }}</span></p> <p>{{ call .T "You can link this identity provider to an existing %s account." .App.Config.ApplicationName }} <span class="warning-message">{{ 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 }}</span></p>
<form action="{{ .App.FrontEndURL }}/web/oidc-migrate" method="post"> <form action="{{ .App.FrontEndURL }}/web/oidc-migrate" method="post">
<input type="text" name="username" placeholder="{{ call .T "Username" }}" required /> <input type="text" name="username" placeholder="{{ call .T "Username" }}" required />
@ -29,7 +29,7 @@
/> />
<input type="submit" value="{{ call .T "Link account" }}" /> <input type="submit" value="{{ call .T "Link account" }}" />
</form> </form>
{{ $dividerNeeded := true }} {{ $dividerNeeded = true }}
{{ end }} {{ end }}
<!-- CreateNewPlayer --> <!-- CreateNewPlayer -->
@ -39,6 +39,11 @@
{{ $dividerNeeded = false }} {{ $dividerNeeded = false }}
{{ end }} {{ end }}
<h3>{{ call .T "Create a player" }}</h3> <h3>{{ call .T "Create a player" }}</h3>
{{ if and .OIDCProvider.Config.RequireInvite (not .InviteCode) }}
<p>{{ call .T "Registration with %s requires an invite." .OIDCProvider.Config.Name }}</p>
{{ else if and .App.Config.RegistrationExistingPlayer.RequireInvite (not .InviteCode) }}
<p>{{ call .T "Registration as a new player is invite-only." }}</p>
{{ else }}
<p>{{ call .T "Complete registration by creating a new player:" }}</p> <p>{{ call .T "Complete registration by creating a new player:" }}</p>
<form action="{{ .App.FrontEndURL }}/web/register" method="post"> <form action="{{ .App.FrontEndURL }}/web/register" method="post">
<input <input
@ -48,7 +53,7 @@
placeholder="{{ call .T "Player name" }}" placeholder="{{ call .T "Player name" }}"
maxlength="{{ .App.Constants.MaxUsernameLength }}" maxlength="{{ .App.Constants.MaxUsernameLength }}"
value="{{ .PreferredPlayerName }}" value="{{ .PreferredPlayerName }}"
{{ if not .AllowChoosingPlayerName }} {{ if not .OIDCProvider.Config.AllowChoosingPlayerName }}
title="{{ call .T "Choosing a player name is not allowed." }}" title="{{ call .T "Choosing a player name is not allowed." }}"
disabled disabled
{{ end }} {{ end }}
@ -79,6 +84,7 @@
<input type="submit" value="{{ call .T "Register" }}"/> <input type="submit" value="{{ call .T "Register" }}"/>
</p> </p>
</form> </form>
{{ end }}
{{ $dividerNeeded = true }} {{ $dividerNeeded = true }}
{{ end }} {{ end }}
@ -89,9 +95,9 @@
{{ $dividerNeeded = false }} {{ $dividerNeeded = false }}
{{ end }} {{ end }}
<h3>{{ call .T "Register from an existing Minecraft player" }}</h3> <h3>{{ call .T "Register from an existing Minecraft player" }}</h3>
{{ if and .App.Config.RegistrationExistingPlayer.RequireInvite (not {{ if and .OIDCProvider.Config.RequireInvite (not .InviteCode) }}
.InviteCode) <p>{{ call .T "Registration with %s requires an invite." .OIDCProvider.Config.Name }}</p>
}} {{ else if and .App.Config.RegistrationExistingPlayer.RequireInvite (not .InviteCode) }}
<p>{{ call .T "Registration as an existing player is invite-only." }}</p> <p>{{ call .T "Registration as an existing player is invite-only." }}</p>
{{ else }} {{ else }}
{{ if .App.Config.ImportExistingPlayer.RequireSkinVerification }} {{ if .App.Config.ImportExistingPlayer.RequireSkinVerification }}
@ -111,7 +117,7 @@
name="playerName" name="playerName"
placeholder="{{ call .T "%s player name" .App.Config.ImportExistingPlayer.Nickname }}" placeholder="{{ call .T "%s player name" .App.Config.ImportExistingPlayer.Nickname }}"
maxlength="{{ .App.Constants.MaxUsernameLength }}" maxlength="{{ .App.Constants.MaxUsernameLength }}"
{{ if not .AllowChoosingPlayerName }} {{ if not .OIDCProvider.Config.AllowChoosingPlayerName }}
value="{{ .PreferredPlayerName }}" value="{{ .PreferredPlayerName }}"
title="{{ call .T "Choosing a player name is not allowed." }}" title="{{ call .T "Choosing a player name is not allowed." }}"
disabled disabled