From d0307e9fb21bf528fefd1f2b10a8871dff4a1df4 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Mon, 13 Dec 2021 20:09:02 +0100 Subject: [PATCH] yggdrasil implementation, player data: read player properties correct --- pom.xml | 5 +++ src/main/java/de/bixilon/minosoft/Minosoft.kt | 2 + .../entities/entities/player/PlayerEntity.kt | 4 +- .../entities/player/RemotePlayerEntity.kt | 4 +- .../minosoft/data/player/PlayerProperty.kt | 26 ------------ .../player/properties/PlayerProperties.kt | 7 ++++ .../properties/textures/PlayerTexture.kt | 29 +++++++++++++ .../properties/textures/PlayerTextures.kt | 38 ++++++++++++++++++ .../properties/textures/SkinPlayerTexture.kt | 9 +++++ .../textures/metadata/SkinMetadata.kt | 5 +++ .../properties/textures/metadata/SkinModel.kt | 7 ++++ .../minosoft/data/player/tab/TabListItem.kt | 4 +- .../data/player/tab/TabListItemData.kt | 4 +- .../gui/hud/atlas/HUDAtlasManager.kt | 9 ++++- .../opengl/texture/OpenGLTextureArray.kt | 2 +- .../packets/s2c/play/PlayerEntitySpawnS2CP.kt | 10 ++--- .../packets/s2c/play/TabListDataS2CP.kt | 13 +----- .../protocol/protocol/PlayInByteBuffer.kt | 25 ++++++++++++ .../java/de/bixilon/minosoft/util/KUtil.kt | 6 +++ .../de/bixilon/minosoft/util/YggdrasilUtil.kt | 33 +++++++++++++++ .../de/bixilon/minosoft/util/json/Jackson.kt | 11 +++-- .../bixilon/minosoft/util/nbt/tag/NBTUtil.kt | 8 ++-- .../minosoft/util/task/worker/StartupTasks.kt | 1 + .../mojang/yggdrasil_session_pubkey.der | Bin 0 -> 550 bytes 24 files changed, 198 insertions(+), 64 deletions(-) delete mode 100644 src/main/java/de/bixilon/minosoft/data/player/PlayerProperty.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/player/properties/textures/SkinPlayerTexture.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinMetadata.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinModel.kt create mode 100644 src/main/java/de/bixilon/minosoft/util/YggdrasilUtil.kt create mode 100644 src/main/resources/assets/minosoft/mojang/yggdrasil_session_pubkey.der diff --git a/pom.xml b/pom.xml index 8d44dbc4e..f7a62946e 100644 --- a/pom.xml +++ b/pom.xml @@ -444,5 +444,10 @@ reflections 0.10.2 + + com.github.luben + zstd-jni + 1.5.0-4 + diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.kt b/src/main/java/de/bixilon/minosoft/Minosoft.kt index f960fce3f..e1f5257d6 100644 --- a/src/main/java/de/bixilon/minosoft/Minosoft.kt +++ b/src/main/java/de/bixilon/minosoft/Minosoft.kt @@ -122,6 +122,8 @@ object Minosoft { Util.forceClassInit(Eros::class.java) } + taskWorker += Task(identifier = StartupTasks.LOAD_YGGDRASIL, executor = { YggdrasilUtil.load() }) + taskWorker.work(START_UP_LATCH) diff --git a/src/main/java/de/bixilon/minosoft/data/entities/entities/player/PlayerEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/entities/player/PlayerEntity.kt index e7cdb5828..522642425 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/entities/player/PlayerEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/entities/player/PlayerEntity.kt @@ -19,7 +19,7 @@ import de.bixilon.minosoft.data.entities.Poses import de.bixilon.minosoft.data.entities.entities.EntityMetaDataFunction import de.bixilon.minosoft.data.entities.entities.LivingEntity import de.bixilon.minosoft.data.player.Arms -import de.bixilon.minosoft.data.player.PlayerProperty +import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.data.player.tab.TabListItem import de.bixilon.minosoft.data.registries.entities.EntityType import de.bixilon.minosoft.data.world.World @@ -35,7 +35,7 @@ abstract class PlayerEntity( position: Vec3d = Vec3d.EMPTY, rotation: EntityRotation = EntityRotation(0.0, 0.0), name: String = "TBA", - properties: Map = mapOf(), + properties: PlayerProperties = PlayerProperties(), var tabListItem: TabListItem = TabListItem(name = name, gamemode = Gamemodes.SURVIVAL, properties = properties), ) : LivingEntity(connection, entityType, position, rotation) { override val dimensions: Vec2 diff --git a/src/main/java/de/bixilon/minosoft/data/entities/entities/player/RemotePlayerEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/entities/player/RemotePlayerEntity.kt index be27cfeb7..14c12985f 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/entities/player/RemotePlayerEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/entities/player/RemotePlayerEntity.kt @@ -15,7 +15,7 @@ package de.bixilon.minosoft.data.entities.entities.player import de.bixilon.minosoft.data.abilities.Gamemodes import de.bixilon.minosoft.data.entities.EntityRotation -import de.bixilon.minosoft.data.player.PlayerProperty +import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.data.player.tab.TabListItem import de.bixilon.minosoft.data.registries.ResourceLocation import de.bixilon.minosoft.data.registries.entities.EntityFactory @@ -30,7 +30,7 @@ class RemotePlayerEntity( position: Vec3d = Vec3d.EMPTY, rotation: EntityRotation = EntityRotation(0.0, 0.0), name: String = "TBA", - properties: Map = mapOf(), + properties: PlayerProperties = PlayerProperties(), tabListItem: TabListItem = TabListItem(name = name, gamemode = Gamemodes.SURVIVAL, properties = properties), ) : PlayerEntity(connection, entityType, position, rotation, name, properties, tabListItem) { diff --git a/src/main/java/de/bixilon/minosoft/data/player/PlayerProperty.kt b/src/main/java/de/bixilon/minosoft/data/player/PlayerProperty.kt deleted file mode 100644 index 5b37de058..000000000 --- a/src/main/java/de/bixilon/minosoft/data/player/PlayerProperty.kt +++ /dev/null @@ -1,26 +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 . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ -package de.bixilon.minosoft.data.player - -class PlayerProperty( - val key: String, - val value: String, - val signature: String? = null, -) { - val isSigned: Boolean - get() = signature != null // ToDo check signature - - override fun toString(): String { - return "$key: $value" - } -} diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt new file mode 100644 index 000000000..8aeb56ccd --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/PlayerProperties.kt @@ -0,0 +1,7 @@ +package de.bixilon.minosoft.data.player.properties + +import de.bixilon.minosoft.data.player.properties.textures.PlayerTextures + +class PlayerProperties( + val textures: PlayerTextures? = null, +) diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt new file mode 100644 index 000000000..70b6bf95e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTexture.kt @@ -0,0 +1,29 @@ +package de.bixilon.minosoft.data.player.properties.textures + +import de.bixilon.minosoft.util.KUtil.check +import java.net.URL + +open class PlayerTexture( + val url: URL, +) { + init { + url.check() + + check(urlMatches(url, ALLOWED_DOMAINS) && !urlMatches(url, BLOCKED_DOMAINS)) { "URL hostname is not allowed!" } + } + + + companion object { + private val ALLOWED_DOMAINS = arrayOf(".minecraft.net", ".mojang.com") + private val BLOCKED_DOMAINS = arrayOf("bugs.mojang.com", "education.minecraft.net", "feedback.minecraft.net") + + private fun urlMatches(url: URL, domains: Array): Boolean { + for (checkURL in domains) { + if (url.host.endsWith(checkURL)) { + return true + } + } + return false + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt new file mode 100644 index 000000000..44cd065b2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/PlayerTextures.kt @@ -0,0 +1,38 @@ +package de.bixilon.minosoft.data.player.properties.textures + +import com.fasterxml.jackson.module.kotlin.convertValue +import de.bixilon.minosoft.util.KUtil.toLong +import de.bixilon.minosoft.util.Util +import de.bixilon.minosoft.util.YggdrasilUtil +import de.bixilon.minosoft.util.json.Jackson +import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast +import java.util.* + +class PlayerTextures( + val name: String?, + val uuid: UUID?, + val date: Date?, + val skin: SkinPlayerTexture?, + val cape: PlayerTexture?, + val elytra: PlayerTexture?, +) { + + companion object { + fun of(encoded: String, signature: String): PlayerTextures { + check(YggdrasilUtil.verify(encoded, signature)) { "Texture signature is invalid!" } + + val json: Map = Jackson.MAPPER.readValue(Base64.getDecoder().decode(encoded), Jackson.JSON_MAP_TYPE) + + // Data also contains `signatureRequired` + val textures = json["textures"]?.compoundCast() + return PlayerTextures( + name = json["profileName"]?.toString(), + uuid = json["profileId"]?.toString()?.let { Util.getUUIDFromString(it) }, + date = json["timestamp"]?.toLong()?.let { Date(it) }, + skin = textures?.get("SKIN")?.compoundCast()?.let { return@let Jackson.MAPPER.convertValue(it) }, + cape = textures?.get("CAPE")?.compoundCast()?.let { return@let Jackson.MAPPER.convertValue(it) }, + elytra = textures?.get("ELYTRA")?.compoundCast()?.let { return@let Jackson.MAPPER.convertValue(it) }, + ) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/SkinPlayerTexture.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/SkinPlayerTexture.kt new file mode 100644 index 000000000..2163d9231 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/SkinPlayerTexture.kt @@ -0,0 +1,9 @@ +package de.bixilon.minosoft.data.player.properties.textures + +import de.bixilon.minosoft.data.player.properties.textures.metadata.SkinMetadata +import java.net.URL + +class SkinPlayerTexture( + url: URL, + val metadata: SkinMetadata = SkinMetadata(), +) : PlayerTexture(url = url) diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinMetadata.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinMetadata.kt new file mode 100644 index 000000000..d03475d98 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinMetadata.kt @@ -0,0 +1,5 @@ +package de.bixilon.minosoft.data.player.properties.textures.metadata + +data class SkinMetadata( + val model: SkinModel = SkinModel.NORMAL, +) diff --git a/src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinModel.kt b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinModel.kt new file mode 100644 index 000000000..5666cb6c6 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/player/properties/textures/metadata/SkinModel.kt @@ -0,0 +1,7 @@ +package de.bixilon.minosoft.data.player.properties.textures.metadata + +enum class SkinModel { + SLIM, + NORMAL, + ; +} diff --git a/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItem.kt b/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItem.kt index 95840a0e0..15cad6ad3 100644 --- a/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItem.kt +++ b/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItem.kt @@ -14,7 +14,7 @@ package de.bixilon.minosoft.data.player.tab import de.bixilon.minosoft.data.abilities.Gamemodes -import de.bixilon.minosoft.data.player.PlayerProperty +import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.data.scoreboard.Team import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.util.KUtil.nullCompare @@ -24,7 +24,7 @@ data class TabListItem( var ping: Int = -1, var gamemode: Gamemodes = Gamemodes.SURVIVAL, var displayName: ChatComponent = ChatComponent.of(name), - var properties: Map = mutableMapOf(), + var properties: PlayerProperties = PlayerProperties(), var team: Team? = null, ) : Comparable { val tabDisplayName: ChatComponent diff --git a/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItemData.kt b/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItemData.kt index 4607b1dc6..68b7c5106 100644 --- a/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItemData.kt +++ b/src/main/java/de/bixilon/minosoft/data/player/tab/TabListItemData.kt @@ -14,7 +14,7 @@ package de.bixilon.minosoft.data.player.tab import de.bixilon.minosoft.data.abilities.Gamemodes -import de.bixilon.minosoft.data.player.PlayerProperty +import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.data.scoreboard.Team import de.bixilon.minosoft.data.text.ChatComponent @@ -24,7 +24,7 @@ data class TabListItemData( var gamemode: Gamemodes? = null, var hasDisplayName: Boolean? = null, var displayName: ChatComponent? = null, - val properties: Map? = null, + val properties: PlayerProperties? = null, var remove: Boolean = false, // used for legacy tab list var team: Team? = null, var removeFromTeam: Boolean = false, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt index 19bfdf352..822c432fc 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/atlas/HUDAtlasManager.kt @@ -20,6 +20,8 @@ import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.toVec2i import de.bixilon.minosoft.util.KUtil.mapCast import de.bixilon.minosoft.util.KUtil.toInt import de.bixilon.minosoft.util.KUtil.toResourceLocation +import glm_.vec2.Vec2 +import glm_.vec2.Vec2i class HUDAtlasManager(private val hudRenderer: HUDRenderer) { private lateinit var elements: Map @@ -79,8 +81,8 @@ class HUDAtlasManager(private val hudRenderer: HUDRenderer) { fun postInit() { for (element in elements.values) { - element.uvStart = element.texture.singlePixelSize * element.start - element.uvEnd = element.texture.singlePixelSize * element.end + element.uvStart = ATLAS_SINGLE_PIXEL_SIZE * element.start + element.uvEnd = ATLAS_SINGLE_PIXEL_SIZE * element.end } } @@ -94,5 +96,8 @@ class HUDAtlasManager(private val hudRenderer: HUDRenderer) { companion object { private val ATLAS_DATA = "minosoft:mapping/atlas.json".toResourceLocation() + + private val ATLAS_SIZE = Vec2i(256, 256) + private val ATLAS_SINGLE_PIXEL_SIZE = Vec2(1.0f) / ATLAS_SIZE } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt index 736f60dd5..610c7bf9d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/system/opengl/texture/OpenGLTextureArray.kt @@ -198,8 +198,8 @@ class OpenGLTextureArray( companion object { - val TEXTURE_RESOLUTION_ID_MAP = intArrayOf(16, 32, 64, 128, 256, 512, 1024) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split const val TEXTURE_MAX_RESOLUTION = 1024 + val TEXTURE_RESOLUTION_ID_MAP = intArrayOf(16, 32, 64, 128, 256, 512, TEXTURE_MAX_RESOLUTION) // A 12x12 texture will be saved in texture id 0 (in 0 are only 16x16 textures). Animated textures get split const val MAX_MIPMAP_LEVELS = 5 } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PlayerEntitySpawnS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PlayerEntitySpawnS2CP.kt index 10a79bfbc..3348e1983 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PlayerEntitySpawnS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/PlayerEntitySpawnS2CP.kt @@ -16,7 +16,7 @@ import de.bixilon.minosoft.data.entities.EntityRotation import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity import de.bixilon.minosoft.data.entities.meta.EntityMetaData -import de.bixilon.minosoft.data.player.PlayerProperty +import de.bixilon.minosoft.data.player.properties.PlayerProperties import de.bixilon.minosoft.modding.event.events.EntitySpawnEvent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket @@ -38,15 +38,11 @@ class PlayerEntitySpawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { entityId = buffer.readVarInt() var name = "TBA" - val properties: MutableMap = mutableMapOf() + var properties = PlayerProperties() if (buffer.versionId < ProtocolVersions.V_14W21A) { name = buffer.readString() entityUUID = buffer.readUUIDString() - val length = buffer.readVarInt() - for (i in 0 until length) { - val property = PlayerProperty(buffer.readString(), buffer.readString(), buffer.readString()) - properties[property.key] = property - } + properties = buffer.readPlayerProperties() } else { entityUUID = buffer.readUUID() } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/TabListDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/TabListDataS2CP.kt index c18df39ac..e62a95390 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/TabListDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/TabListDataS2CP.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.protocol.packets.s2c.play import de.bixilon.minosoft.data.abilities.Gamemodes import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity -import de.bixilon.minosoft.data.player.PlayerProperty import de.bixilon.minosoft.data.player.tab.TabListItem import de.bixilon.minosoft.data.player.tab.TabListItemData import de.bixilon.minosoft.modding.event.events.TabListEntryChangeEvent @@ -60,15 +59,7 @@ class TabListDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { when (action) { TabListItemActions.ADD -> { val name = buffer.readString() - val playerProperties: MutableMap = mutableMapOf() - for (index in 0 until buffer.readVarInt()) { - val property = PlayerProperty( - buffer.readString(), - buffer.readString(), - buffer.readOptional { buffer.readString() }, - ) - playerProperties[property.key] = property - } + val properties = buffer.readPlayerProperties() val gamemode = Gamemodes[buffer.readVarInt()] val ping = buffer.readVarInt() val hasDisplayName = buffer.readBoolean() @@ -79,7 +70,7 @@ class TabListDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { } data = TabListItemData( name = name, - properties = playerProperties, + properties = properties, gamemode = gamemode, ping = ping, hasDisplayName = hasDisplayName, diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt index a215821e9..b173a59d2 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PlayInByteBuffer.kt @@ -14,6 +14,8 @@ package de.bixilon.minosoft.protocol.protocol import de.bixilon.minosoft.data.entities.meta.EntityMetaData import de.bixilon.minosoft.data.inventory.ItemStack +import de.bixilon.minosoft.data.player.properties.PlayerProperties +import de.bixilon.minosoft.data.player.properties.textures.PlayerTextures import de.bixilon.minosoft.data.registries.biomes.Biome import de.bixilon.minosoft.data.registries.particle.ParticleType import de.bixilon.minosoft.data.registries.particle.data.BlockParticleData @@ -214,4 +216,27 @@ class PlayInByteBuffer : InByteBuffer { fun readEntityIdArray(length: Int = readVarInt()): Array { return readArray(length) { readEntityId() } } + + + fun readPlayerProperties(): PlayerProperties { + var textures: PlayerTextures? = null + for (i in 0 until readVarInt()) { + val name = readString() + val value = readString() + val signature = if (versionId < V_14W21A) { + readString() + } else { + readOptional { readString() } + } + when (name) { + "textures" -> { + check(textures == null) { "Textures duplicated" } + textures = PlayerTextures.of(value, signature ?: throw IllegalArgumentException("Texture data needs to be signed!")) + } + } + } + return PlayerProperties( + textures = textures, + ) + } } diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index b060709df..a3ab6c02a 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -33,6 +33,7 @@ import glm_.vec4.Vec4t import sun.misc.Unsafe import java.io.* import java.lang.reflect.Field +import java.net.URL import java.nio.ByteBuffer import java.time.Instant import java.util.* @@ -558,4 +559,9 @@ object KUtil { val Locale.fullName: String get() = language + "_" + country.ifEmpty { language.uppercase() } + + + fun URL.check() { + check(this.protocol == "http" || this.protocol == "https") { "Url is not a web address" } + } } diff --git a/src/main/java/de/bixilon/minosoft/util/YggdrasilUtil.kt b/src/main/java/de/bixilon/minosoft/util/YggdrasilUtil.kt new file mode 100644 index 000000000..cbc0b93f3 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/YggdrasilUtil.kt @@ -0,0 +1,33 @@ +package de.bixilon.minosoft.util + +import de.bixilon.minosoft.Minosoft +import de.bixilon.minosoft.util.KUtil.toResourceLocation +import java.security.KeyFactory +import java.security.PublicKey +import java.security.Signature +import java.security.spec.X509EncodedKeySpec +import java.util.* + + +object YggdrasilUtil { + lateinit var PUBLIC_KEY: PublicKey + private set + + fun load() { + check(!this::PUBLIC_KEY.isInitialized) { "Already loaded!" } + val spec = X509EncodedKeySpec(Minosoft.MINOSOFT_ASSETS_MANAGER["minosoft:mojang/yggdrasil_session_pubkey.der".toResourceLocation()].readAllBytes()) + val keyFactory: KeyFactory = KeyFactory.getInstance("RSA") + PUBLIC_KEY = keyFactory.generatePublic(spec) + } + + fun verify(data: ByteArray, signature: ByteArray): Boolean { + val signatureInstance = Signature.getInstance("SHA1withRSA") + signatureInstance.initVerify(PUBLIC_KEY) + signatureInstance.update(data) + return signatureInstance.verify(signature) + } + + fun verify(data: String, signature: String): Boolean { + return verify(data.toByteArray(), Base64.getDecoder().decode(signature)) + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt b/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt index b4c9e0c48..b86a9406e 100644 --- a/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt +++ b/src/main/java/de/bixilon/minosoft/util/json/Jackson.kt @@ -2,14 +2,19 @@ package de.bixilon.minosoft.util.json import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.MapperFeature import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.type.MapType import com.fasterxml.jackson.module.kotlin.KotlinFeature import com.fasterxml.jackson.module.kotlin.KotlinModule object Jackson { - val MAPPER = ObjectMapper() + val MAPPER = JsonMapper.builder() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .disable(JsonParser.Feature.AUTO_CLOSE_SOURCE) + .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) + .build() .registerModule(KotlinModule.Builder() .withReflectionCacheSize(512) .configure(KotlinFeature.NullToEmptyCollection, false) @@ -21,8 +26,6 @@ object Jackson { .registerModule(ResourceLocationSerializer) .registerModule(RGBColorSerializer) .registerModule(ChatComponentColorSerializer) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .disable(JsonParser.Feature.AUTO_CLOSE_SOURCE) .setDefaultMergeable(true) diff --git a/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt b/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt index 17abb9d09..cf57670d1 100644 --- a/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt @@ -13,6 +13,8 @@ package de.bixilon.minosoft.util.nbt.tag +import de.bixilon.minosoft.util.KUtil.nullCast + object NBTUtil { fun compound(): MutableMap { @@ -33,11 +35,7 @@ object NBTUtil { } fun Any?.compoundCast(): MutableMap? { - try { - return this as MutableMap - } catch (ignored: ClassCastException) { - } - return null + return this.nullCast() } fun Any?.asCompound(): MutableMap { diff --git a/src/main/java/de/bixilon/minosoft/util/task/worker/StartupTasks.kt b/src/main/java/de/bixilon/minosoft/util/task/worker/StartupTasks.kt index 80b9ed024..060881820 100644 --- a/src/main/java/de/bixilon/minosoft/util/task/worker/StartupTasks.kt +++ b/src/main/java/de/bixilon/minosoft/util/task/worker/StartupTasks.kt @@ -24,5 +24,6 @@ enum class StartupTasks { INITIALIZE_JAVAFX, X_START_ON_FIRST_THREAD_WARNING, FILE_WATCHER, + LOAD_YGGDRASIL, ; } diff --git a/src/main/resources/assets/minosoft/mojang/yggdrasil_session_pubkey.der b/src/main/resources/assets/minosoft/mojang/yggdrasil_session_pubkey.der new file mode 100644 index 0000000000000000000000000000000000000000..9c79a3aa4771da1f15af37a2af0898f878ad816f GIT binary patch literal 550 zcmV+>0@?jAf&wBi4F(A+hDe6@4FLfG1potr0uKN%f&vNxf&u{m%20R*skxUv>`)yD7%qARQ>bP36CtP}x@~Z9*VkPYUS6pWrZtT#q)8GCbf0*5+4Pyw;#Tq!Aq{bDO|Iw<43LnG*#4;?Z&LM71zXE@J`@_dMl`?qQ1 z@3qR;mm=XG_-{G#4vhRxmZiQslrTtB_&7&0ECnD9)gZ}j`e&Je+s