mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 11:54:59 -04:00
remove HTTP, refactor MicrosoftOAuthUtils
This commit is contained in:
parent
3bf80ccea3
commit
854e0bcd8f
@ -79,7 +79,7 @@ class MainErosController : JavaFXWindowController() {
|
|||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
logoFX.image = JavaFXUtil.MINOSOFT_LOGO
|
logoFX.image = JavaFXUtil.MINOSOFT_LOGO
|
||||||
versionTextFX.text = "Minosoft " + GitInfo.IS_INITIALIZED.decide(GitInfo.GIT_COMMIT_ID, StaticConfiguration.VERSION)
|
versionTextFX.text = "Minosoft " + GitInfo.IS_INITIALIZED.decide(GitInfo.GIT_COMMIT_ID_ABBREV, StaticConfiguration.VERSION)
|
||||||
iconMap = mapOf(
|
iconMap = mapOf(
|
||||||
ErosMainActivities.PlAY to playIconFX,
|
ErosMainActivities.PlAY to playIconFX,
|
||||||
ErosMainActivities.SETTINGS to settingsIconFX,
|
ErosMainActivities.SETTINGS to settingsIconFX,
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 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.util;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.http.HttpClient;
|
|
||||||
import java.net.http.HttpRequest;
|
|
||||||
import java.net.http.HttpResponse;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public final class HTTP {
|
|
||||||
|
|
||||||
public static HttpResponse<String> postJson(String url, String json, HashMap<String, String> headers) throws IOException, InterruptedException {
|
|
||||||
headers.put("Content-Type", "application/json");
|
|
||||||
headers.put("Accept", "application/json");
|
|
||||||
|
|
||||||
HttpClient client = HttpClient.newHttpClient();
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
|
||||||
.uri(URI.create(url))
|
|
||||||
.POST(HttpRequest.BodyPublishers.ofString(json))
|
|
||||||
.headers(Util.headersMapToArray(headers))
|
|
||||||
.build();
|
|
||||||
return client.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HttpResponse<String> postJson(String url, JsonObject json) throws IOException, InterruptedException {
|
|
||||||
return postJson(url, Util.GSON.toJson(json), new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HttpResponse<String> postJson(String url, String json) throws IOException, InterruptedException {
|
|
||||||
return postJson(url, json, new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HttpResponse<String> get(String url, HashMap<String, String> headers) throws IOException, InterruptedException {
|
|
||||||
HttpClient client = HttpClient.newHttpClient();
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
|
||||||
.uri(URI.create(url))
|
|
||||||
.headers(Util.headersMapToArray(headers))
|
|
||||||
.build();
|
|
||||||
return client.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HttpResponse<String> get(String url) throws IOException, InterruptedException {
|
|
||||||
return get(url, new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static JsonElement getJson(String url, HashMap<String, String> headers) throws IOException, InterruptedException {
|
|
||||||
HttpResponse<String> response = get(url, headers);
|
|
||||||
if (response.statusCode() != 200) {
|
|
||||||
throw new IOException();
|
|
||||||
}
|
|
||||||
return JsonParser.parseString(response.body());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonElement getJson(String url) throws IOException, InterruptedException {
|
|
||||||
return getJson(url, new HashMap<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HttpResponse<String> postData(String url, HashMap<String, String> data) throws IOException, InterruptedException {
|
|
||||||
HttpClient client = HttpClient.newHttpClient();
|
|
||||||
HttpRequest request = HttpRequest.newBuilder()
|
|
||||||
.uri(URI.create(url))
|
|
||||||
.POST(HttpRequest.BodyPublishers.ofString(Util.mapToUrlQuery(data)))
|
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
.build();
|
|
||||||
return client.send(request, HttpResponse.BodyHandlers.ofString());
|
|
||||||
}
|
|
||||||
}
|
|
@ -282,6 +282,10 @@ object KUtil {
|
|||||||
return this.nullCast()
|
return this.nullCast()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Any?.asList(): List<Any> {
|
||||||
|
return this.unsafeCast()
|
||||||
|
}
|
||||||
|
|
||||||
fun Any.toJson(beautiful: Boolean = false, adapter: JsonAdapter<Any> = JSONSerializer.ANY_ADAPTER): String {
|
fun Any.toJson(beautiful: Boolean = false, adapter: JsonAdapter<Any> = JSONSerializer.ANY_ADAPTER): String {
|
||||||
val buffer = Buffer()
|
val buffer = Buffer()
|
||||||
val jsonWriter: JsonWriter = JsonWriter.of(buffer)
|
val jsonWriter: JsonWriter = JsonWriter.of(buffer)
|
||||||
@ -308,6 +312,15 @@ object KUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Any?.toLong(): Long {
|
||||||
|
return when (this) {
|
||||||
|
is Long -> this
|
||||||
|
is Number -> this.toLong()
|
||||||
|
is Int -> this.toLong()
|
||||||
|
else -> TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Any?.toDouble(): Double {
|
fun Any?.toDouble(): Double {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is Double -> this
|
is Double -> this
|
||||||
|
@ -59,4 +59,26 @@ object HTTP2 {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <Response> String.get(bodyBuilder: (String) -> Response, headers: Map<String, Any> = mapOf()): HTTPResponse<Response> {
|
||||||
|
val client = HttpClient.newHttpClient()
|
||||||
|
val request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(this))
|
||||||
|
.GET()
|
||||||
|
.headers(*headers.headers())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val response = client.send(request, HttpResponse.BodyHandlers.ofString())
|
||||||
|
return HTTPResponse(response.statusCode(), bodyBuilder(response.body()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.getJson(headers: Map<String, Any> = mapOf()): HTTPResponse<Map<String, Any>?> {
|
||||||
|
return this.get(
|
||||||
|
bodyBuilder = { it.isBlank().decide(null) { JSONSerializer.MAP_ADAPTER.fromJson(it) } },
|
||||||
|
headers = headers.extend(
|
||||||
|
"Content-Type" to "application/json",
|
||||||
|
"Accept" to "application/json",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,17 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.util.microsoft
|
package de.bixilon.minosoft.util.microsoft
|
||||||
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import de.bixilon.minosoft.data.accounts.types.MicrosoftAccount
|
import de.bixilon.minosoft.data.accounts.types.MicrosoftAccount
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.terminal.RunConfiguration
|
import de.bixilon.minosoft.util.KUtil.asList
|
||||||
import de.bixilon.minosoft.util.HTTP
|
import de.bixilon.minosoft.util.KUtil.toLong
|
||||||
import de.bixilon.minosoft.util.Util
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
|
import de.bixilon.minosoft.util.http.HTTP2.getJson
|
||||||
|
import de.bixilon.minosoft.util.http.HTTP2.postJson
|
||||||
import de.bixilon.minosoft.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
|
import de.bixilon.minosoft.util.logging.LogLevels
|
||||||
|
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||||
|
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||||
import java.net.URLConnection
|
import java.net.URLConnection
|
||||||
|
|
||||||
object MicrosoftOAuthUtils {
|
object MicrosoftOAuthUtils {
|
||||||
@ -27,69 +31,34 @@ object MicrosoftOAuthUtils {
|
|||||||
override fun connect() {}
|
override fun connect() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loginToMicrosoftAccount(authorizationCode: String) {
|
fun loginToMicrosoftAccount(authorizationCode: String): MicrosoftAccount {
|
||||||
Log.verbose("Logging into microsoft account...")
|
Log.log(LogMessageType.AUTHENTICATION, LogLevels.INFO) { "Logging into microsoft account..." }
|
||||||
try {
|
val authorizationToken = getAuthorizationToken(authorizationCode)
|
||||||
val authorizationToken = getAuthorizationToken(authorizationCode)
|
val xboxLiveToken = getXboxLiveToken(authorizationToken)
|
||||||
val xboxLiveToken = getXboxLiveToken(authorizationToken)
|
val xstsToken = getXSTSToken(xboxLiveToken.first)
|
||||||
val xstsToken = getXSTSToken(xboxLiveToken.first)
|
|
||||||
|
|
||||||
val microsoftAccount = getMicrosoftAccount(getMinecraftAccessToken(xboxLiveToken.second, xstsToken))
|
return getMicrosoftAccount(getMinecraftAccessToken(xboxLiveToken.second, xstsToken))
|
||||||
// ToDo: Account.addAccount(microsoftAccount)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.warn("Can not login into microsoft account")
|
|
||||||
exception.printStackTrace()
|
|
||||||
|
|
||||||
if (RunConfiguration.DISABLE_EROS) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var message = "Could not login!"
|
|
||||||
var errorMessage = exception.javaClass.canonicalName + ": " + exception.message
|
|
||||||
if (exception is LoginException) {
|
|
||||||
message = "${exception.message} (${exception.errorCode})"
|
|
||||||
errorMessage = exception.errorMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Platform.runLater {
|
|
||||||
// val dialog = JFXAlert<Boolean>()
|
|
||||||
// // ToDo: GUITools.initializePane(dialog.dialogPane)
|
|
||||||
// // Do not translate this, translations might fail to load...
|
|
||||||
// dialog.title = "Login error"
|
|
||||||
// val layout = JFXDialogLayout()
|
|
||||||
// layout.setHeading(Text(message))
|
|
||||||
// val text = TextArea(errorMessage)
|
|
||||||
// text.isEditable = false
|
|
||||||
// text.isWrapText = true
|
|
||||||
// layout.setBody(text)
|
|
||||||
// dialog.dialogPane.content = layout
|
|
||||||
// val stage = dialog.dialogPane.scene.window as Stage
|
|
||||||
// stage.toFront()
|
|
||||||
// dialog.show()
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAuthorizationToken(authorizationCode: String): String {
|
fun getAuthorizationToken(authorizationCode: String): String {
|
||||||
val data = mapOf(
|
val response = mapOf(
|
||||||
"client_id" to ProtocolDefinition.MICROSOFT_ACCOUNT_APPLICATION_ID,
|
"client_id" to ProtocolDefinition.MICROSOFT_ACCOUNT_APPLICATION_ID,
|
||||||
"code" to authorizationCode,
|
"code" to authorizationCode,
|
||||||
"grant_type" to "authorization_code",
|
"grant_type" to "authorization_code",
|
||||||
"scope" to "service::user.auth.xboxlive.com::MBI_SSL",
|
"scope" to "service::user.auth.xboxlive.com::MBI_SSL",
|
||||||
)
|
).postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_AUTH_TOKEN_URL)
|
||||||
val response = HTTP.postData(ProtocolDefinition.MICROSOFT_ACCOUNT_AUTH_TOKEN_URL, HashMap(data))
|
if (response.statusCode != 200) {
|
||||||
if (response.statusCode() != 200) {
|
throw LoginException(response.statusCode, "Could not get authorization token ", response.body.toString())
|
||||||
throw LoginException(response.statusCode(), "Could not get authorization token ", response.body())
|
|
||||||
}
|
}
|
||||||
val body = JsonParser.parseString(response.body()).asJsonObject
|
response.body!!
|
||||||
return body["access_token"]!!.asString
|
return response.body["access_token"].unsafeCast()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns A: XBL Token; B: UHS Token
|
* returns A: XBL Token; B: UHS Token
|
||||||
*/
|
*/
|
||||||
fun getXboxLiveToken(authorizationToken: String): Pair<String, String> {
|
fun getXboxLiveToken(authorizationToken: String): Pair<String, String> {
|
||||||
val payload = mapOf(
|
val response = mapOf(
|
||||||
"Properties" to mapOf(
|
"Properties" to mapOf(
|
||||||
"AuthMethod" to "RPS",
|
"AuthMethod" to "RPS",
|
||||||
"SiteName" to "user.auth.xboxlive.com",
|
"SiteName" to "user.auth.xboxlive.com",
|
||||||
@ -97,68 +66,63 @@ object MicrosoftOAuthUtils {
|
|||||||
),
|
),
|
||||||
"RelyingParty" to "http://auth.xboxlive.com",
|
"RelyingParty" to "http://auth.xboxlive.com",
|
||||||
"TokenType" to "JWT",
|
"TokenType" to "JWT",
|
||||||
)
|
).postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_XBOX_LIVE_AUTHENTICATE_URL)
|
||||||
val response = HTTP.postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_XBOX_LIVE_AUTHENTICATE_URL, Util.GSON.toJson(payload))
|
|
||||||
|
|
||||||
if (response.statusCode() != 200) {
|
response.body!!
|
||||||
throw LoginException(response.statusCode(), "Could not get authenticate against xbox live ", response.body())
|
if (response.statusCode != 200) {
|
||||||
|
throw LoginException(response.statusCode, "Could not get authenticate against xbox live ", response.body.toString())
|
||||||
}
|
}
|
||||||
val body = JsonParser.parseString(response.body()).asJsonObject
|
return Pair(response.body["Token"].unsafeCast(), response.body["DisplayClaims"].asCompound()["xui"].asList()[0].asCompound()["uhs"].unsafeCast())
|
||||||
return Pair(body["Token"]!!.asString, body["DisplayClaims"].asJsonObject["xui"].asJsonArray[0].asJsonObject["uhs"].asString)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getXSTSToken(xBoxLiveToken: String): String {
|
fun getXSTSToken(xBoxLiveToken: String): String {
|
||||||
val payload = mapOf(
|
val response = mapOf(
|
||||||
"Properties" to mapOf(
|
"Properties" to mapOf(
|
||||||
"SandboxId" to "RETAIL",
|
"SandboxId" to "RETAIL",
|
||||||
"UserTokens" to listOf(xBoxLiveToken)
|
"UserTokens" to listOf(xBoxLiveToken)
|
||||||
),
|
),
|
||||||
"RelyingParty" to "rp://api.minecraftservices.com/",
|
"RelyingParty" to "rp://api.minecraftservices.com/",
|
||||||
"TokenType" to "JWT",
|
"TokenType" to "JWT",
|
||||||
)
|
).postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_XSTS_URL)
|
||||||
val response = HTTP.postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_XSTS_URL, Util.GSON.toJson(payload))
|
|
||||||
|
|
||||||
if (response.statusCode() != 200) {
|
response.body!!
|
||||||
val error = JsonParser.parseString(response.body()).asJsonObject
|
if (response.statusCode != 200) {
|
||||||
val errorMessage = when (error["XErr"].asLong) {
|
val errorMessage = when (response.body["XErr"].toLong()) {
|
||||||
2148916233 -> "You don't have an XBox account!"
|
2148916233 -> "You don't have an XBox account!"
|
||||||
2148916238 -> "This account is a child account!"
|
2148916238 -> "This account is a child account!"
|
||||||
else -> error["Message"].asString
|
else -> response.body["Message"].unsafeCast()
|
||||||
}
|
}
|
||||||
throw LoginException(response.statusCode(), "Could not get authenticate against XSTS token ", errorMessage)
|
throw LoginException(response.statusCode, "Could not get authenticate against XSTS token ", errorMessage)
|
||||||
}
|
}
|
||||||
val body = JsonParser.parseString(response.body()).asJsonObject
|
return response.body["Token"].unsafeCast()
|
||||||
return body["Token"].asString!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMinecraftAccessToken(uhs: String, xstsToken: String): String {
|
fun getMinecraftAccessToken(uhs: String, xstsToken: String): String {
|
||||||
val payload = mapOf(
|
val response = mapOf(
|
||||||
"identityToken" to "XBL3.0 x=${uhs};${xstsToken}"
|
"identityToken" to "XBL3.0 x=${uhs};${xstsToken}"
|
||||||
)
|
).postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_MINECRAFT_LOGIN_WITH_XBOX_URL)
|
||||||
val response = HTTP.postJson(ProtocolDefinition.MICROSOFT_ACCOUNT_MINECRAFT_LOGIN_WITH_XBOX_URL, Util.GSON.toJson(payload))
|
|
||||||
|
|
||||||
if (response.statusCode() != 200) {
|
response.body!!
|
||||||
val error = JsonParser.parseString(response.body()).asJsonObject
|
if (response.statusCode != 200) {
|
||||||
throw LoginException(response.statusCode(), "Could not get minecraft access token ", error["errorMessage"].asString)
|
throw LoginException(response.statusCode, "Could not get minecraft access token ", response.body["errorMessage"].unsafeCast())
|
||||||
}
|
}
|
||||||
val body = JsonParser.parseString(response.body()).asJsonObject
|
return response.body["access_token"].unsafeCast()
|
||||||
return body["access_token"].asString!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMicrosoftAccount(bearerToken: String): MicrosoftAccount {
|
fun getMicrosoftAccount(bearerToken: String): MicrosoftAccount {
|
||||||
val response = HTTP.get(ProtocolDefinition.MICROSOFT_ACCOUNT_GET_MOJANG_PROFILE_URL, HashMap(mapOf(
|
val response = ProtocolDefinition.MICROSOFT_ACCOUNT_GET_MOJANG_PROFILE_URL.getJson(mapOf(
|
||||||
"Authorization" to "Bearer $bearerToken"
|
"Authorization" to "Bearer $bearerToken"
|
||||||
)))
|
))
|
||||||
|
|
||||||
if (response.statusCode() != 200) {
|
response.body!!
|
||||||
val errorMessage = when (response.statusCode()) {
|
if (response.statusCode != 200) {
|
||||||
|
val errorMessage = when (response.statusCode) {
|
||||||
404 -> "You don't have a copy of minecraft!"
|
404 -> "You don't have a copy of minecraft!"
|
||||||
else -> JsonParser.parseString(response.body()).asJsonObject["errorMessage"].asString
|
else -> response.body["errorMessage"].unsafeCast()
|
||||||
}
|
}
|
||||||
throw LoginException(response.statusCode(), "Could not get minecraft profile", errorMessage)
|
throw LoginException(response.statusCode, "Could not get minecraft profile", errorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
val body = JsonParser.parseString(response.body()).asJsonObject
|
|
||||||
// return MicrosoftAccount(bearerToken, body["id"].asString!!, Util.getUUIDFromString(body["id"].asString!!), body["name"].asString!!)
|
// return MicrosoftAccount(bearerToken, body["id"].asString!!, Util.getUUIDFromString(body["id"].asString!!), body["name"].asString!!)
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user