remove deprecated mojang accounts

This commit is contained in:
Bixilon 2022-03-05 14:21:22 +01:00
parent 4ddddb31e5
commit 60eaae8660
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 21 additions and 447 deletions

View File

@ -17,6 +17,8 @@ import com.fasterxml.jackson.databind.JavaType
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.collections.CollectionUtil.synchronizedBiMapOf
import de.bixilon.kutil.collections.map.bi.AbstractMutableBiMap
import de.bixilon.kutil.json.JsonUtil.toJsonObject
import de.bixilon.kutil.json.JsonUtil.toMutableJsonObject
import de.bixilon.kutil.watcher.map.bi.BiMapDataWatcher.Companion.watchedBiMap
import de.bixilon.minosoft.config.profile.GlobalProfileManager
import de.bixilon.minosoft.config.profile.ProfileManager
@ -28,7 +30,7 @@ import java.util.concurrent.locks.ReentrantLock
object AccountProfileManager : ProfileManager<AccountProfile> {
override val namespace = "minosoft:account".toResourceLocation()
override val latestVersion = 1
override val latestVersion = 2
override val saveLock = ReentrantLock()
override val profileClass = AccountProfile::class.java
override val jacksonProfileType: JavaType = Jackson.MAPPER.typeFactory.constructType(profileClass)
@ -53,4 +55,22 @@ object AccountProfileManager : ProfileManager<AccountProfile> {
return profile
}
private fun removeMojangAccounts(data: MutableMap<String, Any?>) {
val entries = data["entries"]?.toMutableJsonObject() ?: return
val toRemove: MutableSet<String> = mutableSetOf()
for ((id, entry) in entries) {
if (entry.toJsonObject()?.get("type") != "minosoft:mojang_account") {
continue
}
toRemove += id
}
entries -= toRemove
}
override fun migrate(from: Int, data: MutableMap<String, Any?>) {
when (from) {
1 -> removeMojangAccounts(data)
}
}
}

View File

@ -22,7 +22,6 @@ import de.bixilon.kutil.watcher.DataWatcher.Companion.watched
import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager
import de.bixilon.minosoft.config.profile.profiles.eros.server.entries.Server
import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftAccount
import de.bixilon.minosoft.data.accounts.types.mojang.MojangAccount
import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount
import de.bixilon.minosoft.data.player.properties.PlayerProperties
import de.bixilon.minosoft.data.registries.ResourceLocation
@ -31,7 +30,6 @@ import java.util.*
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes(
JsonSubTypes.Type(value = MojangAccount::class, name = "minosoft:mojang_account"),
JsonSubTypes.Type(value = OfflineAccount::class, name = "minosoft:offline_account"),
JsonSubTypes.Type(value = MicrosoftAccount::class, name = "minosoft:microsoft_account"),
)

View File

@ -1,151 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.accounts.types.mojang
import com.fasterxml.jackson.annotation.JsonProperty
import de.bixilon.kutil.cast.CastUtil.nullCast
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.json.JsonUtil.asJsonObject
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.uuid.UUIDUtil.toUUID
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.AccountStates
import de.bixilon.minosoft.data.player.properties.PlayerProperties
import de.bixilon.minosoft.data.registries.CompanionResourceLocation
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.account.AccountUtil
import de.bixilon.minosoft.util.http.HTTP2.postJson
import de.bixilon.minosoft.util.http.exceptions.AuthenticationException
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType
import java.net.ConnectException
import java.util.*
@Deprecated("Mojang authentication is legacy. Will be removed in the future!")
class MojangAccount(
override val id: String,
username: String,
override val uuid: UUID,
val email: String,
@field:JsonProperty private var accessToken: String,
override val properties: PlayerProperties?,
) : Account(username) {
@Transient
private var refreshed: Boolean = false
override val type: ResourceLocation = RESOURCE_LOCATION
override fun join(serverId: String) {
AccountUtil.joinMojangServer(username, accessToken, uuid, serverId)
}
override fun logout(clientToken: String) {
val response = mutableMapOf(
"accessToken" to accessToken,
"clientToken" to clientToken,
).postJson(MOJANG_URL_INVALIDATE)
if (response.statusCode != 200) {
throw AuthenticationException(response.statusCode)
}
state = AccountStates.EXPIRED
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang account login successful (username=$username)" }
}
override fun check(latch: CountUpAndDownLatch?, clientToken: String) {
if (refreshed) {
return
}
try {
latch?.inc()
refresh(clientToken)
} catch (exception: ConnectException) {
exception.printStackTrace()
state = AccountStates.OFFLINE
} catch (exception: Throwable) {
this.error = exception
state = AccountStates.ERRORED
throw exception
}
latch?.dec()
}
@Synchronized
fun refresh(clientToken: String) {
state = AccountStates.REFRESHING
val response = mutableMapOf(
"accessToken" to accessToken,
"clientToken" to clientToken,
).postJson(MOJANG_URL_REFRESH)
response.body!!
if (response.statusCode != 200) {
throw AuthenticationException(response.statusCode, response.body["errorMessage"].nullCast())
}
this.accessToken = response.body["accessToken"].unsafeCast()
refreshed = true
state = AccountStates.WORKING
save()
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang account refresh successful (username=$username)" }
}
override fun toString(): String {
return "MojangAccount{$username}"
}
companion object : CompanionResourceLocation {
private const val MOJANG_URL_LOGIN = "https://authserver.mojang.com/authenticate"
private const val MOJANG_URL_REFRESH = "https://authserver.mojang.com/refresh"
private const val MOJANG_URL_INVALIDATE = "https://authserver.mojang.com/invalidate"
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:mojang_account".toResourceLocation()
fun login(clientToken: String, email: String, password: String): MojangAccount {
val response = mutableMapOf(
"agent" to mutableMapOf(
"name" to "Minecraft",
"version" to 1,
),
"username" to email,
"password" to password,
"clientToken" to clientToken,
"requestUser" to true,
).postJson(MOJANG_URL_LOGIN)
response.body!!
if (response.statusCode != 200) {
throw AuthenticationException(response.statusCode, response.body["errorMessage"]?.nullCast())
}
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang login successful (email=$email)" }
val uuid = response.body["selectedProfile"].asJsonObject()["id"].toString().toUUID()
val account = MojangAccount(
id = response.body["user"].asJsonObject()["id"].unsafeCast(),
username = response.body["selectedProfile"].asJsonObject()["name"].unsafeCast(),
uuid = uuid,
email = email,
accessToken = response.body["accessToken"].unsafeCast(),
properties = PlayerProperties.fetch(uuid),
)
account.state = AccountStates.WORKING
return account
}
}
}

View File

@ -24,7 +24,6 @@ import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.accounts.AccountStates
import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftAccount
import de.bixilon.minosoft.data.accounts.types.mojang.MojangAccount
import de.bixilon.minosoft.data.accounts.types.offline.OfflineAccount
import de.bixilon.minosoft.data.registries.ResourceLocation
import de.bixilon.minosoft.data.text.ChatComponent
@ -33,7 +32,6 @@ import de.bixilon.minosoft.gui.eros.controller.EmbeddedJavaFXController
import de.bixilon.minosoft.gui.eros.dialog.ErosErrorReport.Companion.report
import de.bixilon.minosoft.gui.eros.dialog.SimpleErosConfirmationDialog
import de.bixilon.minosoft.gui.eros.main.account.add.MicrosoftAddController
import de.bixilon.minosoft.gui.eros.main.account.add.MojangAddController
import de.bixilon.minosoft.gui.eros.main.account.add.OfflineAddController
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.ctext
@ -272,16 +270,6 @@ class AccountController : EmbeddedJavaFXController<Pane>() {
icon = FontAwesomeSolid.MAP,
addHandler = { OfflineAddController(it).show() },
),
ErosAccountType<MojangAccount>(
resourceLocation = MojangAccount.RESOURCE_LOCATION,
translationKey = "minosoft:main.account.type.mojang".toResourceLocation(),
additionalDetails = listOf(
"minosoft:main.account.account_info.email".toResourceLocation() to { it.email },
"minosoft:main.account.account_info.uuid".toResourceLocation() to { it.uuid },
),
icon = FontAwesomeSolid.BUILDING,
addHandler = { MojangAddController(it).show() },
),
)
val <T : Account>T.erosType: ErosAccountType<T>?

View File

@ -1,150 +0,0 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.eros.main.account.add
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager
import de.bixilon.minosoft.data.accounts.types.mojang.MojangAccount
import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController
import de.bixilon.minosoft.gui.eros.main.account.AccountController
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.ctext
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.placeholder
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil.text
import de.bixilon.minosoft.util.KUtil.text
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import javafx.fxml.FXML
import javafx.scene.control.Button
import javafx.scene.control.PasswordField
import javafx.scene.control.TextField
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.text.TextFlow
import javafx.stage.Modality
class MojangAddController(
private val accountController: AccountController,
) : JavaFXWindowController() {
@FXML private lateinit var headerFX: TextFlow
@FXML private lateinit var descriptionFX: TextFlow
@FXML private lateinit var emailLabelFX: TextFlow
@FXML private lateinit var emailFX: TextField
@FXML private lateinit var passwordLabelFX: TextFlow
@FXML private lateinit var passwordFX: PasswordField
@FXML private lateinit var errorFX: TextFlow
@FXML private lateinit var loginButtonFX: Button
@FXML private lateinit var cancelButtonFX: Button
public override fun show() {
JavaFXUtil.openModalAsync(TITLE, LAYOUT, this, modality = Modality.APPLICATION_MODAL) { super.show() }
}
override fun init() {
super.init()
headerFX.text = HEADER
descriptionFX.text = DESCRIPTION
emailLabelFX.text = EMAIL_LABEL
emailFX.placeholder = EMAIL_PLACEHOLDER
passwordLabelFX.text = PASSWORD_LABEL
passwordFX.placeholder = PASSWORD_PLACEHOLDER
loginButtonFX.ctext = ADD_BUTTON
cancelButtonFX.ctext = CANCEL_BUTTON
errorFX.isVisible = false
emailFX.textProperty().addListener { _, _, _ ->
validate()
}
passwordFX.textProperty().addListener { _, _, _ ->
validate()
}
}
override fun postInit() {
super.postInit()
stage.scene.root.addEventFilter(KeyEvent.KEY_PRESSED) {
if (it.code == KeyCode.ESCAPE) {
cancel()
}
}
}
private fun validate() {
if (emailFX.text.isBlank()) {
loginButtonFX.isDisable = true
return
}
if (passwordFX.text.isEmpty()) {
loginButtonFX.isDisable = true
return
}
loginButtonFX.isDisable = false
}
@FXML
fun login() {
val profile = ErosProfileManager.selected.general.accountProfile
if (loginButtonFX.isDisable) {
return
}
loginButtonFX.isDisable = true
errorFX.isVisible = false
DefaultThreadPool += {
try {
val account = MojangAccount.login(email = emailFX.text, password = passwordFX.text, clientToken = profile.clientToken)
profile.entries[account.id] = account
profile.selected = account
JavaFXUtil.runLater {
accountController.refreshList()
close()
}
} catch (exception: Exception) {
JavaFXUtil.runLater {
exception.printStackTrace()
errorFX.text = exception.text
errorFX.isVisible = true
loginButtonFX.isDisable = false
}
}
}
}
@FXML
fun cancel() {
close()
}
companion object {
private val LAYOUT = "minosoft:eros/main/account/add/mojang.fxml".toResourceLocation()
private val TITLE = "minosoft:main.account.add.mojang.title".toResourceLocation()
private val HEADER = "minosoft:main.account.add.mojang.header".toResourceLocation()
private val DESCRIPTION = "minosoft:main.account.add.mojang.description".toResourceLocation()
private val EMAIL_LABEL = "minosoft:main.account.add.mojang.email.label".toResourceLocation()
private val EMAIL_PLACEHOLDER = "minosoft:main.account.add.mojang.email.placeholder".toResourceLocation()
private val PASSWORD_LABEL = "minosoft:main.account.add.mojang.password.label".toResourceLocation()
private val PASSWORD_PLACEHOLDER = "minosoft:main.account.add.mojang.password.placeholder".toResourceLocation()
private val ADD_BUTTON = "minosoft:main.account.add.mojang.add_button".toResourceLocation()
private val CANCEL_BUTTON = "minosoft:main.account.add.mojang.cancel_button".toResourceLocation()
}
}

View File

@ -1,109 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Minosoft
~ Copyright (C) 2020-2022 Moritz Zwerger
~
~ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
~
~ This software is not affiliated with Mojang AB, the original developer of Minecraft.
-->
<?import javafx.geometry.*?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<HBox xmlns:fx="http://javafx.com/fxml/1" fx:id="root" prefHeight="240.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16"> <!--fx:controller="de.bixilon.minosoft.gui.eros.main.account.add.OfflineAddController" -->
<GridPane HBox.hgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
<RowConstraints vgrow="NEVER"/>
<RowConstraints vgrow="NEVER"/>
<RowConstraints vgrow="NEVER"/>
<RowConstraints vgrow="ALWAYS"/>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<TextFlow style="-fx-font-size: 30;" fx:id="headerFX">
<GridPane.margin>
<Insets bottom="10.0" left="5.0" right="5.0" top="10.0"/>
</GridPane.margin>
<Text text="Add mojang account"/>
</TextFlow>
<TextFlow fx:id="descriptionFX" GridPane.rowIndex="1">
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</padding>
<GridPane.margin>
<Insets bottom="15.0" right="5.0" top="5.0"/>
</GridPane.margin>
<Text text="Please enter your mojang email (or for legacy accounts their username) and your password to continue"/>
</TextFlow>
<GridPane GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="ALWAYS"/>
</columnConstraints>
<rowConstraints>
<RowConstraints valignment="CENTER" vgrow="NEVER"/>
<RowConstraints minHeight="10.0" prefHeight="30.0" valignment="CENTER" vgrow="NEVER"/>
</rowConstraints>
<TextFlow fx:id="emailLabelFX">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="30.0" top="5.0"/>
</GridPane.margin>
<Text text="Email"/>
</TextFlow>
<TextField fx:id="emailFX" promptText="user@example.org" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</TextField>
<TextFlow fx:id="passwordLabelFX" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="30.0" top="5.0"/>
</GridPane.margin>
<Text text="Password"/>
</TextFlow>
<PasswordField fx:id="passwordFX" promptText="********" GridPane.columnIndex="1" GridPane.rowIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</PasswordField>
</GridPane>
<GridPane GridPane.rowIndex="5">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS"/>
<ColumnConstraints hgrow="NEVER"/>
<ColumnConstraints hgrow="NEVER"/>
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="NEVER"/>
</rowConstraints>
<Button fx:id="cancelButtonFX" onAction="#cancel" text="Cancel" GridPane.columnIndex="1">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</Button>
<Button fx:id="loginButtonFX" disable="true" onAction="#login" text="Login" defaultButton="true" GridPane.columnIndex="2">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
</Button>
</GridPane>
<TextFlow fx:id="errorFX" GridPane.rowIndex="3">
<GridPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/>
</GridPane.margin>
<Text text="Unknown exception: This is just a dummy"/>
</TextFlow>
</GridPane>
</HBox>

View File

@ -89,7 +89,6 @@ minosoft:main.account.list.info.button.check=Check
minosoft:main.account.list.info.button.use=Use
minosoft:main.account.list.info.button.add=Add account
minosoft:main.account.no_account_selected=No account selected
minosoft:main.account.type.mojang=Mojang
minosoft:main.account.type.microsoft=Microsoft
minosoft:main.account.type.offline=Offline
@ -120,16 +119,6 @@ minosoft:main.account.add.offline.username.placeholder=Test user
minosoft:main.account.add.offline.add_button=Add
minosoft:main.account.add.offline.cancel_button=Cancel
minosoft:main.account.add.mojang.title=Add mojang account
minosoft:main.account.add.mojang.header=Add mojang account
minosoft:main.account.add.mojang.description=Please enter your mojang email (or for legacy accounts their username) and your password to continue
minosoft:main.account.add.mojang.email.label=E-mail
minosoft:main.account.add.mojang.email.placeholder=user@example.org
minosoft:main.account.add.mojang.password.label=Password
minosoft:main.account.add.mojang.password.placeholder=********
minosoft:main.account.add.mojang.add_button=Add
minosoft:main.account.add.mojang.cancel_button=Cancel
minosoft:main.account.add.microsoft.please_wait.device_code=Obtaining device code...Please wait!
minosoft:main.account.add.microsoft.title=Add microsoft account - Minosoft

View File

@ -63,7 +63,6 @@ minosoft:server_list.refresh.text2=información
minosoft:main.account.no_account_selected=Sin cuenta seleccionada
minosoft:main.account.type.mojang=Mojang
minosoft:main.account.type.microsoft=Microsoft
minosoft:main.account.type.offline=Offline
@ -82,16 +81,6 @@ minosoft:main.account.add.offline.username.placeholder=Usuario ejemplo
minosoft:main.account.add.offline.add_button=Añadir
minosoft:main.account.add.offline.cancel_button=Cancelar
minosoft:main.account.add.mojang.title=Añadir cuenta de Mojang
minosoft:main.account.add.mojang.header=Añadir cuenta de Mojang
minosoft:main.account.add.mojang.description=Introduze tu email (o nombre de usuario para cuentas antiguas) y tu contraseña
minosoft:main.account.add.mojang.email.label=E-mail
minosoft:main.account.add.mojang.email.placeholder=user@ejemplo.es
minosoft:main.account.add.mojang.password.label=Contraseña
minosoft:main.account.add.mojang.password.placeholder=****
minosoft:main.account.add.mojang.add_button=Añadir
minosoft:main.account.add.mojang.cancel_button=Cancelar
minosoft:main.account.add.microsoft.title=Añadir cuenta de Microsoft