diff --git a/Server/src/main/kotlin/rs09/ServerConstants.kt b/Server/src/main/kotlin/rs09/ServerConstants.kt index f76900780..250f6e24e 100644 --- a/Server/src/main/kotlin/rs09/ServerConstants.kt +++ b/Server/src/main/kotlin/rs09/ServerConstants.kt @@ -13,6 +13,9 @@ import java.math.BigInteger class ServerConstants { companion object { @JvmField + var DAILY_ACCOUNT_LIMIT = 3 + + @JvmField var REVENANT_POPULATION: Int = 30 @JvmField diff --git a/Server/src/main/kotlin/rs09/ServerStore.kt b/Server/src/main/kotlin/rs09/ServerStore.kt index 0bbe3cc77..c76c9ecd8 100644 --- a/Server/src/main/kotlin/rs09/ServerStore.kt +++ b/Server/src/main/kotlin/rs09/ServerStore.kt @@ -9,6 +9,7 @@ import core.game.node.entity.player.Player import org.json.simple.JSONArray import org.json.simple.JSONObject import org.json.simple.parser.JSONParser +import rs09.ServerStore.Companion.addToList import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger.logShutdown import rs09.game.system.SystemLogger.logStartup @@ -135,6 +136,18 @@ class ServerStore : PersistWorld { return jArray } + inline fun JSONObject.getList(key: String) : List { + val array = this[key] as? JSONArray ?: JSONArray() + val list = ArrayList() + for(element in array) list.add(element as T) + return list + } + + fun JSONObject.addToList(key: String, value: Any) { + val array = this.getOrPut(key) {JSONArray()} as JSONArray + array.add(value) + } + /** NPCItemMemory * These next methods handle the NPCItemMemory database. these are server-stored JSON objects, * which are based on an npc and an item. diff --git a/Server/src/main/kotlin/rs09/game/system/config/ServerConfigParser.kt b/Server/src/main/kotlin/rs09/game/system/config/ServerConfigParser.kt index 2e806c8e7..a063f4506 100644 --- a/Server/src/main/kotlin/rs09/game/system/config/ServerConfigParser.kt +++ b/Server/src/main/kotlin/rs09/game/system/config/ServerConfigParser.kt @@ -123,6 +123,7 @@ object ServerConfigParser { ServerConstants.I_AM_A_CHEATER = data.getBoolean("world.i_want_to_cheat", false) ServerConstants.USE_AUTH = data.getBoolean("server.use_auth", true) ServerConstants.PERSIST_ACCOUNTS = data.getBoolean("server.persist_accounts", true) + ServerConstants.DAILY_ACCOUNT_LIMIT = data.getLong("server.daily_accounts_per_ip", 3L).toInt() } diff --git a/Server/src/main/kotlin/rs09/net/packet/in/Login.kt b/Server/src/main/kotlin/rs09/net/packet/in/Login.kt index 7c49b3778..b651e4b47 100644 --- a/Server/src/main/kotlin/rs09/net/packet/in/Login.kt +++ b/Server/src/main/kotlin/rs09/net/packet/in/Login.kt @@ -14,6 +14,9 @@ import proto.management.JoinClanRequest import proto.management.PlayerStatusUpdate import proto.management.RequestContactInfo import rs09.ServerConstants +import rs09.ServerStore +import rs09.ServerStore.Companion.addToList +import rs09.ServerStore.Companion.getList import rs09.auth.AuthResponse import rs09.game.node.entity.player.info.login.LoginParser import rs09.game.system.SystemLogger @@ -120,22 +123,39 @@ object Login { Repository.LOGGED_IN_PLAYERS.add(details.username) details.session = session details.info.translate(UIDInfo(details.ipAddress, "DEPRECATED", "DEPRECATED", "DEPRECATED")) - val player = Player(details) - if (Repository.getPlayerByName(player.name) == null) { - Repository.addPlayer(player) - } - session.lastPing = System.currentTimeMillis() - try { - LoginParser(details, LoginType.fromType(opcode)).initialize(player, opcode == RECONNECT_LOGIN_OP) - sendMSEvents(details) - } catch (e: Exception) { - e.printStackTrace() - session.disconnect() - Repository.removePlayer(player) - player.clear(true) + + if (checkAccountLimit(details.ipAddress, details.username)) { + val player = Player(details) + if (Repository.getPlayerByName(player.name) == null) { + Repository.addPlayer(player) + } + session.lastPing = System.currentTimeMillis() + try { + LoginParser(details, LoginType.fromType(opcode)).initialize(player, opcode == RECONNECT_LOGIN_OP) + sendMSEvents(details) + } catch (e: Exception) { + e.printStackTrace() + session.disconnect() + Repository.removePlayer(player) + player.clear(true) + } + } else { + session.write(AuthResponse.LoginLimitExceeded) } } + private fun checkAccountLimit(ipAddress: String, username: String): Boolean { + val archive = ServerStore.getArchive("daily-accounts") + val accounts = archive.getList(ipAddress) + if (username in accounts) return true + + if (accounts.size >= ServerConstants.DAILY_ACCOUNT_LIMIT) + return false + + archive.addToList(ipAddress, username) + return true + } + private fun sendMSEvents(details: PlayerDetails) { val statusEvent = PlayerStatusUpdate.newBuilder() statusEvent.username = details.username diff --git a/Server/worldprops/default.conf b/Server/worldprops/default.conf index e5c988499..b78154754 100644 --- a/Server/worldprops/default.conf +++ b/Server/worldprops/default.conf @@ -13,6 +13,8 @@ use_auth = false #NOTE: THIS MUST BE SET TO TRUE IN PRODUCTION! #NOTE: this does not affect actual save data, like stats, inventory, etc. persist_accounts = false #NOTE: THIS MUST BE SET TO TRUE IN PRODUCTION! #------------------------------------------------------------------------------------------------------ +#The limit on how many different accounts a player can log into per day. +daily_accounts_per_ip = 3 [database] database_name = "global"