Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ sealed class UsernameResFailureReason {
data class NonPremiumUsernameNotIdentical(val requiredUsername: String) :
UsernameResFailureReason()

data class PremiumUsernameOwnedByAnotherAccount(val username: String) :
UsernameResFailureReason()

data object ProfileAPIFailure : UsernameResFailureReason()
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,18 @@ constructor(private val userService: UserService, private val profileService: Pr
}

if (existingUserIgnoreCase != null && existingUserIgnoreCase.isPremium) {
// A premium account is bound to its Mojang UUID, not to its username. When the name is a
// premium name but the Mojang-verified UUID differs from the stored one, this is a DIFFERENT
// account that only re-claimed a released username - it must not be logged into the stored
// account. Without this guard a released-then-reclaimed username hands the previous owner's
// identity (and its permissions) to the new holder.
if (isPremiumNickname && existingUserIgnoreCase.mojangUuid != correspondingPremiumProfile.uuid) {
return failure(
UsernameResFailureReason.PremiumUsernameOwnedByAnotherAccount(
correspondingPremiumProfile.name.value
)
)
}
if (connUsername.value != existingUserIgnoreCase.username.value) {
return failure(
UsernameResFailureReason.PremiumUsernameNotIdentical(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ open class MessagesConfig : OkaeriConfig() {
"<red>Username '%USERNAME%' is already taken! Administrator needs to resolve the conflict.</red>"
)

var premiumUsernameOwnedByAnotherAccountError =
TextComponent(
"<red>This username '%USERNAME%' belongs to a different premium account and cannot be used " +
"to log in here.<br>It was registered by a previous owner before the name was released."
)

@Comment("Usually caused by API rate limit.")
var profileApiFailureKickMessage =
TextComponent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ constructor(
is UsernameResFailureReason.PremiumUsernameNotIdentical -> {
premiumUsernameRequiredDeniedResult(connUsername, failureReason.requiredUsername)
}
is UsernameResFailureReason.PremiumUsernameOwnedByAnotherAccount -> {
premiumUsernameOwnedByAnotherAccountDeniedResult(failureReason.username)
}
is UsernameResFailureReason.NonPremiumWithPremiumConflict -> {
usernameConflictDeniedResult(failureReason.premiumUsername)
}
Expand Down Expand Up @@ -290,6 +293,19 @@ constructor(
return PreLoginEvent.PreLoginComponentResult.denied(component)
}

private fun premiumUsernameOwnedByAnotherAccountDeniedResult(
username: String
): PreLoginEvent.PreLoginComponentResult {
val comp =
withSupportFooter(
componentWithUsernamePlaceholder(
messagesConfig.premiumUsernameOwnedByAnotherAccountError,
username,
)
)
return PreLoginEvent.PreLoginComponentResult.denied(comp)
}

private fun usernameConflictDeniedResult(
connUsername: String
): PreLoginEvent.PreLoginComponentResult {
Expand Down