aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/data/ApiKeyGrabber.kt
blob: 000d218052e0151aedcf29ba2b9dc2dcc3f774ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package at.hannibal2.skyhanni.data

import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.events.ProfileApiDataLoadedEvent
import at.hannibal2.skyhanni.events.ProfileJoinEvent
import at.hannibal2.skyhanni.utils.APIUtil
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.StringUtils.toDashlessUUID
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.minecraft.client.Minecraft
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.io.File
import java.util.*

class ApiKeyGrabber {

    private var currentProfileName = ""

    @SubscribeEvent
    fun onStatusBar(event: LorenzChatEvent) {
        val message = event.message
        if (message.startsWith("§aYour new API key is §r§b")) {
            SkyHanniMod.feature.hidden.apiKey = message.substring(26)
            LorenzUtils.chat("§b[SkyHanni] A new API Key has been detected and installed")

            if (currentProfileName != "") {
                updateApiData()
            }
        }
    }

    @SubscribeEvent
    fun onStatusBar(event: ProfileJoinEvent) {
        currentProfileName = event.name
        updateApiData()
    }


    private suspend fun tryUpdateProfileDataAndVerifyKey(apiKey: String): Boolean {
        val uuid = Minecraft.getMinecraft().thePlayer.uniqueID.toDashlessUUID()
        val url = "https://api.hypixel.net/player?key=$apiKey&uuid=$uuid"
        val jsonObject = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }

        if (jsonObject["success"]?.asBoolean == false) {
            if (jsonObject["throttle"]?.asBoolean == true) return true // 429 Too Many Requests does not make an invalid key.
            val cause = jsonObject["cause"].asString
            if (cause == "Invalid API key") {
                return false
            } else {
                throw RuntimeException("API error for url '$url': $cause")
            }
        }
        val player = jsonObject["player"].asJsonObject
        val stats = player["stats"].asJsonObject
        val skyblock = stats["SkyBlock"].asJsonObject
        val profiles = skyblock["profiles"].asJsonObject
        for (entry in profiles.entrySet()) {
            val asJsonObject = entry.value.asJsonObject
            val name = asJsonObject["cute_name"].asString
            if (currentProfileName == name.lowercase()) {
                val profileId = asJsonObject["profile_id"].asString
                loadProfile(apiKey, uuid, profileId)
            }
        }
        return true
    }

    private fun updateApiData() {
        SkyHanniMod.coroutineScope.launch {
            val oldApiKey = SkyHanniMod.feature.hidden.apiKey
            if (oldApiKey.isNotEmpty() && tryUpdateProfileDataAndVerifyKey(oldApiKey)) {
                return@launch
            }
            findApiCandidatesFromOtherMods().forEach { (modName, newApiKey) ->
                if (tryUpdateProfileDataAndVerifyKey(newApiKey)) {
                    SkyHanniMod.feature.hidden.apiKey = newApiKey
                    LorenzUtils.chat("§e[SkyHanni] Imported valid new API key from $modName.")
                    return@launch
                } else {
                    LorenzUtils.error("§c[SkyHanni] Invalid API key from $modName")
                }
            }
            LorenzUtils.error("§c[SkyHanni] SkyHanni has no API key set. Please run /api new")
        }
    }

    private fun findApiCandidatesFromOtherMods(): Map<String, String> {
        LorenzUtils.consoleLog("Trying to find the API Key from the config of other mods..")
        val candidates = mutableMapOf<String, String>()
        for (mod in OtherMod.values()) {
            val modName = mod.modName
            val file = File(mod.configPath)
            if (file.exists()) {
                val reader = APIUtil.readFile(file)
                try {
                    val key = mod.readKey(reader).replace("\n", "").replace(" ", "")
                    UUID.fromString(key)
                    candidates[modName] = key
                } catch (e: Throwable) {
                    LorenzUtils.consoleLog("- $modName: wrong config format! (" + e.message + ")")
                    continue
                }
            } else {
                LorenzUtils.consoleLog("- $modName: no config found!")
            }
        }
        return candidates
    }

    private suspend fun loadProfile(apiKey: String, playerUuid: String, profileId: String) {
        val url = "https://api.hypixel.net/skyblock/profile?key=$apiKey&profile=$profileId"

        val jsonObject = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }

        val profile = jsonObject["profile"]?.asJsonObject ?: return
        val members = profile["members"]?.asJsonObject ?: return
        for (entry in members.entrySet()) {
            if (entry.key == playerUuid) {
                val profileData = entry.value.asJsonObject
                ProfileApiDataLoadedEvent(profileData).postAndCatch()
            }
        }
    }
}