diff --git a/src/main/java/me/spartacus04/jext/Jext.kt b/src/main/java/me/spartacus04/jext/Jext.kt index 53af2f16..c087f613 100644 --- a/src/main/java/me/spartacus04/jext/Jext.kt +++ b/src/main/java/me/spartacus04/jext/Jext.kt @@ -1,7 +1,5 @@ package me.spartacus04.jext -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.cancel import me.spartacus04.jext.State.CONFIG import me.spartacus04.jext.State.DISCS import me.spartacus04.jext.State.INTEGRATIONS @@ -41,7 +39,9 @@ internal class Jext : JavaPlugin() { } private fun load() { - DISCS.registerDiscSource(FileSource()) + DISCS.registerDiscSource(FileSource()) { + JukeboxGuiContainer.loadFromFile() + } ListenerRegistrant.registerListeners() INTEGRATIONS.reloadDefaultIntegrations() @@ -57,7 +57,5 @@ internal class Jext : JavaPlugin() { } } } - - JukeboxGuiContainer.loadFromFile() } } \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/config/fields/FieldGuiStyle.kt b/src/main/java/me/spartacus04/jext/config/fields/FieldGuiStyle.kt index 8642c007..074d830f 100644 --- a/src/main/java/me/spartacus04/jext/config/fields/FieldGuiStyle.kt +++ b/src/main/java/me/spartacus04/jext/config/fields/FieldGuiStyle.kt @@ -15,6 +15,8 @@ enum class FieldGuiStyle { @SerializedName("page-vertical") PAGE_VERTICAL; + fun toGuiStyle(): String = this.name.replace("_", "-").lowercase() + companion object { fun fromString(name: String): FieldGuiStyle { return FieldGuiStyle.entries.find { it.name == name || it.name == name.replace("-", "_").uppercase() } ?: throw IllegalArgumentException("Invalid serialized name") diff --git a/src/main/java/me/spartacus04/jext/config/fields/FieldJukeboxBehaviour.kt b/src/main/java/me/spartacus04/jext/config/fields/FieldJukeboxBehaviour.kt index a14bb822..81fb4764 100644 --- a/src/main/java/me/spartacus04/jext/config/fields/FieldJukeboxBehaviour.kt +++ b/src/main/java/me/spartacus04/jext/config/fields/FieldJukeboxBehaviour.kt @@ -9,6 +9,8 @@ enum class FieldJukeboxBehaviour { @SerializedName("gui") GUI; + fun toJukeboxBehaviour(): String = this.name.lowercase() + companion object { fun fromString(name: String): FieldJukeboxBehaviour { return entries.find { it.name == name || it.name == name.replace("-", "_").uppercase() } ?: throw IllegalArgumentException("Invalid serialized name") diff --git a/src/main/java/me/spartacus04/jext/config/fields/FieldLanguageMode.kt b/src/main/java/me/spartacus04/jext/config/fields/FieldLanguageMode.kt index 73f92867..b11b60ae 100644 --- a/src/main/java/me/spartacus04/jext/config/fields/FieldLanguageMode.kt +++ b/src/main/java/me/spartacus04/jext/config/fields/FieldLanguageMode.kt @@ -20,6 +20,14 @@ enum class FieldLanguageMode { pl_pl, pt_br, pt_pt, ro_ro, ru_ru, sr_sp, sv_se, tr_tr, uk_ua, vi_vn, zh_cn, zh_tw; + fun toLocale(): String { + return if(this == AUTO || this == SILENT || this == CUSTOM) { + this.name + } else { + this.name.replace("_", "-") + }.lowercase() + } + companion object { fun fromString(name: String): FieldLanguageMode { // return enum value, name can either be the actual name or the serialized name diff --git a/src/main/java/me/spartacus04/jext/discs/DiscManager.kt b/src/main/java/me/spartacus04/jext/discs/DiscManager.kt index 083f8d01..bb008cd9 100644 --- a/src/main/java/me/spartacus04/jext/discs/DiscManager.kt +++ b/src/main/java/me/spartacus04/jext/discs/DiscManager.kt @@ -11,23 +11,24 @@ class DiscManager : Iterable { private val discSources = arrayListOf() private var discs: ArrayList = arrayListOf() - fun reloadDiscs() { + fun reloadDiscs(onReload: (() -> Unit)? = null) { discs.clear() SCHEDULER.runTaskAsynchronously { - CoroutineScope(Dispatchers.Default).launch { + val discs = CoroutineScope(Dispatchers.Default).launch { discSources.forEach { discs.addAll(it.getDiscs()) } } + discs.invokeOnCompletion { onReload?.invoke() } } } - fun registerDiscSource(vararg discSources: DiscSource) { + fun registerDiscSource(vararg discSources: DiscSource, onReload: (() -> Unit)? = null) { this.discSources.addAll(discSources) - reloadDiscs() + reloadDiscs(onReload) } override fun iterator(): Iterator { diff --git a/src/main/java/me/spartacus04/jext/language/LanguageManager.kt b/src/main/java/me/spartacus04/jext/language/LanguageManager.kt index 016c95ef..de85521a 100644 --- a/src/main/java/me/spartacus04/jext/language/LanguageManager.kt +++ b/src/main/java/me/spartacus04/jext/language/LanguageManager.kt @@ -157,6 +157,6 @@ class LanguageManager { const val BEDROCK_NOT_SUPPORTED = "[§cJEXT§f] §cJukebox GUI is not supported on bedrock edition!" const val WEBAPI_RESOURCEPACK_NOT_FOUND = "[§cJEXT§f] §cresource-pack.zip not found, please provide it in the plugin directory" const val WEBSERVER_STARTED = "[§aJEXT§f] §aWebserver started on port %port%" - const val WEBSERVER_STOPPED = "[§aJEXT§f] §aWebserver stopped" + const val WEBSERVER_STOPPED = "[§eJEXT§f] §eWebserver stopped" } } diff --git a/src/main/java/me/spartacus04/jext/listeners/RecordPacketEvent.kt b/src/main/java/me/spartacus04/jext/listeners/RecordPacketEvent.kt index 44426442..a3430a28 100644 --- a/src/main/java/me/spartacus04/jext/listeners/RecordPacketEvent.kt +++ b/src/main/java/me/spartacus04/jext/listeners/RecordPacketEvent.kt @@ -33,11 +33,9 @@ internal class RecordPacketEvent : JextPacketListener(packetType = PacketType.Pl fun actionBarDisplay(player: Player, container: Disc) { player.spigot().sendMessage( ChatMessageType.ACTION_BAR, - *TextComponent.fromLegacyText( - LANG.getKey(player, "now-playing", mapOf( - "name" to container.displayName - )) - ) + TextComponent(LANG.getKey(player, "now-playing", mapOf( + "name" to container.displayName + ))) ) } } \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/utils/FileBind.kt b/src/main/java/me/spartacus04/jext/utils/FileBind.kt index 2e9761c5..b19b42c5 100644 --- a/src/main/java/me/spartacus04/jext/utils/FileBind.kt +++ b/src/main/java/me/spartacus04/jext/utils/FileBind.kt @@ -39,6 +39,22 @@ open class FileBind(@Transient private val filePath: String, @Transient private } } + fun fromText(text: String) : Boolean { + try { + val obj = gson.fromJson(text, typeToken) + + obj.javaClass.declaredFields.forEach { field -> + field.isAccessible = true + + field.set(this, field.get(obj)) + } + + return true + } catch (_: Exception) { + return false + } + } + fun save() { val text = gson.toJson(this) diff --git a/src/main/java/me/spartacus04/jext/webapi/JextWebServer.kt b/src/main/java/me/spartacus04/jext/webapi/JextWebServer.kt index 090c04f0..d1958a02 100644 --- a/src/main/java/me/spartacus04/jext/webapi/JextWebServer.kt +++ b/src/main/java/me/spartacus04/jext/webapi/JextWebServer.kt @@ -9,6 +9,11 @@ import me.spartacus04.jext.State.SCHEDULER import me.spartacus04.jext.language.LanguageManager.Companion.WEBAPI_RESOURCEPACK_NOT_FOUND import me.spartacus04.jext.language.LanguageManager.Companion.WEBSERVER_STARTED import me.spartacus04.jext.language.LanguageManager.Companion.WEBSERVER_STOPPED +import me.spartacus04.jext.webapi.auth.ConnectHandler +import me.spartacus04.jext.webapi.auth.DisconnectHandler +import me.spartacus04.jext.webapi.auth.HealthHandler +import me.spartacus04.jext.webapi.config.ConfigApplyHandler +import me.spartacus04.jext.webapi.config.ConfigReadHandler import org.bukkit.Bukkit import java.net.InetSocketAddress @@ -49,6 +54,15 @@ class JextWebServer { Bukkit.getConsoleSender().sendMessage(WEBAPI_RESOURCEPACK_NOT_FOUND) } } + + if(apiEnabled) { + server!!.createContext("/connect", ConnectHandler()) + server!!.createContext("/disconnect", DisconnectHandler()) + server!!.createContext("/health", HealthHandler()) + + server!!.createContext("/config/read", ConfigReadHandler()) + server!!.createContext("/config/apply", ConfigApplyHandler()) + } } } } @@ -79,6 +93,22 @@ class JextWebServer { } else { server!!.removeContext("/resource-pack.zip") } + + if(apiEnabled) { + server!!.createContext("/connect", ConnectHandler()) + server!!.createContext("/disconnect", DisconnectHandler()) + server!!.createContext("/health", HealthHandler()) + + server!!.createContext("/config/read", ConfigReadHandler()) + server!!.createContext("/config/apply", ConfigApplyHandler()) + } else { + server!!.removeContext("/connect") + server!!.removeContext("/disconnect") + server!!.removeContext("/health") + + server!!.removeContext("/config/read") + server!!.removeContext("/config/apply") + } } } else { stop() diff --git a/src/main/java/me/spartacus04/jext/webapi/ResourcePackHandler.kt b/src/main/java/me/spartacus04/jext/webapi/ResourcePackHandler.kt index 4de8830a..48b7f578 100644 --- a/src/main/java/me/spartacus04/jext/webapi/ResourcePackHandler.kt +++ b/src/main/java/me/spartacus04/jext/webapi/ResourcePackHandler.kt @@ -1,24 +1,22 @@ package me.spartacus04.jext.webapi import com.sun.net.httpserver.HttpExchange -import com.sun.net.httpserver.HttpHandler import me.spartacus04.jext.State.PLUGIN +import me.spartacus04.jext.webapi.utils.JextHttpHandler -class ResourcePackHandler : HttpHandler { +class ResourcePackHandler : JextHttpHandler(false) { private val file = PLUGIN.dataFolder.resolve("resource-pack.zip") - override fun handle(exchange: HttpExchange) { + override fun onGet(exchange: HttpExchange) { if(!file.exists()) { - exchange.sendResponseHeaders(404, 0) - exchange.close() - return + return notFound(exchange) } exchange.sendResponseHeaders(200, file.length()) + file.inputStream().use { input -> exchange.responseBody.use { output -> input.copyTo(output) } } - exchange.close() } } \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/webapi/auth/ConnectHandler.kt b/src/main/java/me/spartacus04/jext/webapi/auth/ConnectHandler.kt new file mode 100644 index 00000000..36c8395d --- /dev/null +++ b/src/main/java/me/spartacus04/jext/webapi/auth/ConnectHandler.kt @@ -0,0 +1,36 @@ +package me.spartacus04.jext.webapi.auth + +import com.sun.net.httpserver.HttpExchange +import me.spartacus04.jext.State.CONFIG +import me.spartacus04.jext.webapi.utils.JextHttpHandler +import java.util.HashMap + +class ConnectHandler : JextHttpHandler(false) { + override fun onPost(exchange: HttpExchange) { + val addr = exchange.remoteAddress.address.address.map { it.toInt() }.joinToString(".") + val body = exchange.requestBody.bufferedReader().readText() + + if(body == CONFIG.WEB_INTERFACE_PASSWORD) { + val token = (0..64).map { (('a'..'z') + ('A'..'Z') + ('0'..'9')).random() }.joinToString("") + + connectedHashMap[addr] = token + + exchange.sendResponseHeaders(200, token.length.toLong()) + + exchange.responseBody.use { os -> + os.write(token.toByteArray()) + } + } else { + val response = "401 Unauthorized" + exchange.sendResponseHeaders(401, response.length.toLong()) + + exchange.responseBody.use { os -> + os.write(response.toByteArray()) + } + } + } + + companion object { + internal val connectedHashMap = HashMap() + } +} \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/webapi/auth/DisconnectHandler.kt b/src/main/java/me/spartacus04/jext/webapi/auth/DisconnectHandler.kt new file mode 100644 index 00000000..a368dd9b --- /dev/null +++ b/src/main/java/me/spartacus04/jext/webapi/auth/DisconnectHandler.kt @@ -0,0 +1,14 @@ +package me.spartacus04.jext.webapi.auth + +import com.sun.net.httpserver.HttpExchange +import me.spartacus04.jext.webapi.utils.JextHttpHandler + +class DisconnectHandler : JextHttpHandler(true) { + override fun onPost(exchange: HttpExchange) { + val addr = exchange.remoteAddress.address.address.map { it.toInt() }.joinToString(".") + + ConnectHandler.connectedHashMap.remove(addr) + + exchange.sendResponseHeaders(200, 0) + } +} \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/webapi/auth/HealthHandler.kt b/src/main/java/me/spartacus04/jext/webapi/auth/HealthHandler.kt new file mode 100644 index 00000000..5e11f8c8 --- /dev/null +++ b/src/main/java/me/spartacus04/jext/webapi/auth/HealthHandler.kt @@ -0,0 +1,22 @@ +package me.spartacus04.jext.webapi.auth + +import com.sun.net.httpserver.HttpExchange +import me.spartacus04.jext.webapi.utils.JextHttpHandler + +class HealthHandler : JextHttpHandler(false) { + override fun onGet(exchange: HttpExchange) { + val token = exchange.requestHeaders["Authorization"]?.first()?.replace("Bearer ", "") + + if(token == null) { + exchange.sendResponseHeaders(200, 0) + } else { + val addr = exchange.remoteAddress.address.address.map { it.toInt() }.joinToString(".") + + if(ConnectHandler.connectedHashMap[addr] == token) { + exchange.sendResponseHeaders(200, 0) + } else { + exchange.sendResponseHeaders(401, 0) + } + } + } +} \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/webapi/config/ConfigApplyHandler.kt b/src/main/java/me/spartacus04/jext/webapi/config/ConfigApplyHandler.kt new file mode 100644 index 00000000..834aa9d4 --- /dev/null +++ b/src/main/java/me/spartacus04/jext/webapi/config/ConfigApplyHandler.kt @@ -0,0 +1,23 @@ +package me.spartacus04.jext.webapi.config + +import com.sun.net.httpserver.HttpExchange +import me.spartacus04.jext.State.CONFIG +import me.spartacus04.jext.State.WEBSERVER +import me.spartacus04.jext.utils.JextMetrics +import me.spartacus04.jext.webapi.utils.JextHttpHandler + +class ConfigApplyHandler : JextHttpHandler(true) { + override fun onPost(exchange: HttpExchange) { + val body = exchange.requestBody.bufferedReader().use { it.readText() } + + if(CONFIG.fromText(body)) { + CONFIG.save() + + exchange.sendResponseHeaders(200, 0) + JextMetrics.reloadMetrics() + WEBSERVER.reload() + } else { + exchange.sendResponseHeaders(400, 0) + } + } +} \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/webapi/config/ConfigReadHandler.kt b/src/main/java/me/spartacus04/jext/webapi/config/ConfigReadHandler.kt new file mode 100644 index 00000000..2d8785c8 --- /dev/null +++ b/src/main/java/me/spartacus04/jext/webapi/config/ConfigReadHandler.kt @@ -0,0 +1,144 @@ +package me.spartacus04.jext.webapi.config + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.sun.net.httpserver.HttpExchange +import me.spartacus04.jext.State.CONFIG +import me.spartacus04.jext.config.fields.FieldGuiStyle +import me.spartacus04.jext.config.fields.FieldJukeboxBehaviour +import me.spartacus04.jext.config.fields.FieldLanguageMode +import me.spartacus04.jext.webapi.utils.JextHttpHandler + +class ConfigReadHandler : JextHttpHandler(true) { + private val gson: Gson = GsonBuilder().setPrettyPrinting().create() + + override fun onGet(exchange: HttpExchange) { + // ——————————————No GSON?—————————————— + //⠀⣞⢽⢪⢣⢣⢣⢫⡺⡵⣝⡮⣗⢷⢽⢽⢽⣮⡷⡽⣜⣜⢮⢺⣜⢷⢽⢝⡽⣝ + //⠸⡸⠜⠕⠕⠁⢁⢇⢏⢽⢺⣪⡳⡝⣎⣏⢯⢞⡿⣟⣷⣳⢯⡷⣽⢽⢯⣳⣫⠇ + //⠀⠀⢀⢀⢄⢬⢪⡪⡎⣆⡈⠚⠜⠕⠇⠗⠝⢕⢯⢫⣞⣯⣿⣻⡽⣏⢗⣗⠏⠀ + //⠀⠪⡪⡪⣪⢪⢺⢸⢢⢓⢆⢤⢀⠀⠀⠀⠀⠈⢊⢞⡾⣿⡯⣏⢮⠷⠁⠀⠀ + //⠀⠀⠀⠈⠊⠆⡃⠕⢕⢇⢇⢇⢇⢇⢏⢎⢎⢆⢄⠀⢑⣽⣿⢝⠲⠉⠀⠀⠀⠀ + //⠀⠀⠀⠀⠀⡿⠂⠠⠀⡇⢇⠕⢈⣀⠀⠁⠡⠣⡣⡫⣂⣿⠯⢪⠰⠂⠀⠀⠀⠀ + //⠀⠀⠀⠀⡦⡙⡂⢀⢤⢣⠣⡈⣾⡃⠠⠄⠀⡄⢱⣌⣶⢏⢊⠂⠀⠀⠀⠀⠀⠀ + //⠀⠀⠀⠀⢝⡲⣜⡮⡏⢎⢌⢂⠙⠢⠐⢀⢘⢵⣽⣿⡿⠁⠁⠀⠀⠀⠀⠀⠀⠀ + //⠀⠀⠀⠀⠨⣺⡺⡕⡕⡱⡑⡆⡕⡅⡕⡜⡼⢽⡻⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + //⠀⠀⠀⠀⣼⣳⣫⣾⣵⣗⡵⡱⡡⢣⢑⢕⢜⢕⡝⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + //⠀⠀⠀⣴⣿⣾⣿⣿⣿⡿⡽⡑⢌⠪⡢⡣⣣⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + //⠀⠀⠀⡟⡾⣿⢿⢿⢵⣽⣾⣼⣘⢸⢸⣞⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + //⠀⠀⠀⠀⠁⠇⠡⠩⡫⢿⣝⡻⡮⣒⢽⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + // —————————————Fuck Gson————————————— + val response = """ + [ + { + "name": "Language mode", + "id": "lang", + "description": "If set to auto, the plugin will use the player's locale; if set to silent, the plugin won't output any messages; if set to custom the plugin will use the language specified in the custom language file; If set to a locale, the plugin will use that locale.", + "value": "${CONFIG.LANGUAGE_MODE.toLocale()}", + "defaultValue": "auto", + "enumValues": [${FieldLanguageMode.entries.joinToString(", ") { "\"${it.toLocale()}\"" }}] + }, + { + "name": "Jukebox behaviour", + "id": "jukebox-behaviour", + "description": "If set to vanilla, the plugin will use the vanilla jukebox behaviour; if set to gui, the plugin will use the custom GUI.", + "value": "${CONFIG.JUKEBOX_BEHAVIOUR.toJukeboxBehaviour()}", + "defaultValue": "vanilla", + "enumValues": [${FieldJukeboxBehaviour.entries.joinToString(", ") { "\"${it.toJukeboxBehaviour()}\"" }}] + }, + { + "name": "Jukebox GUI style", + "id": "jukebox-gui-style", + "description": "Determines the style of the jukebox GUI.", + "value": "${CONFIG.GUI_STYLE.toGuiStyle()}", + "defaultValue": "scroll-vertical", + "enumValues": [${FieldGuiStyle.entries.joinToString(", ") { "\"${it.toGuiStyle()}\"" }}] + }, + { + "name": "Jukebox GUI size", + "id": "jukebox-gui-size", + "description": "Sets the maximum amount of items that can be added to a jukebox GUI.", + "value": ${CONFIG.GUI_SIZE}, + "defaultValue": 96 + }, + { + "name": "Disable music overlap", + "id": "disable-music-overlap", + "description": "If set to true, the plugin will not play music if there is already music playing.", + "value": ${CONFIG.DISABLE_MUSIC_OVERLAP}, + "defaultValue": true + }, + { + "name": "Disc loot tables limit", + "id": "disc-loottables-limit", + "description": "Sets the maximum amount of discs that can be found in chests, the default amount is 2.", + "value": ${gson.toJson(CONFIG.DISC_LIMIT)}, + "defaultValue": {}, + "enumValues": "chests/*" + }, + { + "name": "Disc fragments loot tables limit", + "id": "fragment-loottables-limit", + "description": "Sets the maximum amount of disc fragments that can be found in chests, the default amount is 3.", + "value": ${gson.toJson(CONFIG.FRAGMENT_LIMIT)}, + "defaultValue": {}, + "enumValues": "chests/*" + }, + { + "name": "Check for updates", + "id": "check-for-updates", + "description": "If set to true, the plugin will check for updates on startup.", + "value": ${CONFIG.CHECK_FOR_UPDATES}, + "defaultValue": true + }, + { + "name": "Allow metrics", + "id": "allow-metrics", + "description": "If set to true, the plugin will send metrics to bStats. Please consider enabling this, as it helps me improve the plugin.", + "value": ${CONFIG.ALLOW_METRICS}, + "defaultValue": true + }, + { + "name": "Force resource pack", + "id": "force-resource-pack", + "description": "If set to true, the plugin will force players to use the resource pack. If the player declines, they will be kicked.", + "value": ${CONFIG.FORCE_RESOURCE_PACK}, + "defaultValue": false + }, + { + "name": "Enable resource pack host", + "id": "enable-resource-pack-host", + "description": "If set to true, the plugin will host the resource pack and automatically send it to players.", + "value": ${CONFIG.RESOURCE_PACK_HOST}, + "defaultValue": true + }, + { + "name": "Web interface port", + "id": "web-interface-port", + "description": "The port the web interface api & resource pack will be hosted on.", + "value": ${CONFIG.WEB_INTERFACE_PORT}, + "defaultValue": 9871 + }, + { + "name": "Web interface api enabled", + "id": "web-interface-api-enabled", + "description": "If set to true, the plugin will have a REST api running to edit the discs settings and the config.", + "value": ${CONFIG.WEB_INTERFACE_API_ENABLED}, + "defaultValue": true + }, + { + "name": "Web interface password", + "id": "web-interface-password", + "description": "The password required to access the web interface api.", + "value": "${CONFIG.WEB_INTERFACE_PASSWORD}", + "defaultValue": "" + } + ] + """.trimIndent() + + exchange.sendResponseHeaders(200, response.length.toLong()) + exchange.responseBody.use { output -> + output.write(response.toByteArray()) + } + } +} \ No newline at end of file diff --git a/src/main/java/me/spartacus04/jext/webapi/utils/JextHttpHandler.kt b/src/main/java/me/spartacus04/jext/webapi/utils/JextHttpHandler.kt new file mode 100644 index 00000000..8e754700 --- /dev/null +++ b/src/main/java/me/spartacus04/jext/webapi/utils/JextHttpHandler.kt @@ -0,0 +1,51 @@ +package me.spartacus04.jext.webapi.utils + +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpHandler +import me.spartacus04.jext.webapi.auth.ConnectHandler + +open class JextHttpHandler(private val requireAuth: Boolean) : HttpHandler { + override fun handle(exchange: HttpExchange) { + val origin = exchange.requestHeaders["Origin"]?.firstOrNull() ?: "*" + exchange.responseHeaders.add("Access-Control-Allow-Origin", origin) + exchange.responseHeaders.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + exchange.responseHeaders.add("Access-Control-Allow-Headers", "Authorization, *") + + if(exchange.requestMethod == "OPTIONS") { + exchange.sendResponseHeaders(200, 0) + return exchange.close() + } + + if(requireAuth && !isLoggedIn(exchange)) { + val response = "401 Unauthorized" + exchange.sendResponseHeaders(401, response.length.toLong()) + + exchange.responseBody.use { os -> + os.write(response.toByteArray()) + } + + exchange.close() + } + + when(exchange.requestMethod) { + "POST" -> onPost(exchange) + "GET" -> onGet(exchange) + else -> notFound(exchange) + } + + exchange.close() + } + + fun notFound(exchange: HttpExchange) = exchange.sendResponseHeaders(404, 0) + + open fun onPost(exchange: HttpExchange) = notFound(exchange) + + open fun onGet(exchange: HttpExchange) = notFound(exchange) + + private fun isLoggedIn(exchange: HttpExchange): Boolean { + val addr = exchange.remoteAddress.address.address.map { it.toInt() }.joinToString(".") + val token = exchange.requestHeaders["Authorization"]?.first()?.replace("Bearer ", "") ?: return false + + return ConnectHandler.connectedHashMap[addr] == token + } +} \ No newline at end of file diff --git a/src/main/resources/config.json b/src/main/resources/config.json index 379a914a..286460a9 100644 --- a/src/main/resources/config.json +++ b/src/main/resources/config.json @@ -24,7 +24,7 @@ "enable-resource-pack-host": true, - "web-interface-port": 8080, + "web-interface-port": 9871, "web-interface-api-enabled": true,