mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-09 16:45:44 -07:00
Miscellaneous moderation QoL improvements
This commit is contained in:
parent
785f72215f
commit
c3b91b2240
10 changed files with 123 additions and 4 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package core.game.content.global.report;
|
package core.game.content.global.report;
|
||||||
|
|
||||||
import core.game.node.entity.player.Player;
|
import core.game.node.entity.player.Player;
|
||||||
|
import discord.Discord;
|
||||||
import rs09.game.system.command.CommandMapping;
|
import rs09.game.system.command.CommandMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,6 +51,7 @@ public final class AbuseReport {
|
||||||
CommandMapping.INSTANCE.get("mute").attemptHandling(player, new String[] {"mute", victim, "48h"});
|
CommandMapping.INSTANCE.get("mute").attemptHandling(player, new String[] {"mute", victim, "48h"});
|
||||||
}
|
}
|
||||||
player.getPacketDispatch().sendMessage("Thank-you, your abuse report has been received.");
|
player.getPacketDispatch().sendMessage("Thank-you, your abuse report has been received.");
|
||||||
|
Discord.INSTANCE.postPlayerAlert(victim, "Abuse Report - " + rule.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package discord
|
package discord
|
||||||
|
|
||||||
import api.getItemName
|
import api.getItemName
|
||||||
|
import core.game.node.entity.player.Player
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.json.simple.JSONArray
|
import org.json.simple.JSONArray
|
||||||
|
|
@ -24,7 +25,7 @@ object Discord {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val offer = encodeOfferJson(isSale, itemId, value, qty, user)
|
val offer = encodeOfferJson(isSale, itemId, value, qty, user)
|
||||||
try {
|
try {
|
||||||
sendJsonPost(offer)
|
sendJsonPost(ServerConstants.DISCORD_GE_WEBHOOK, offer)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +37,18 @@ object Discord {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val offer = encodeUpdateJson(isSale, itemId, value, amtLeft)
|
val offer = encodeUpdateJson(isSale, itemId, value, amtLeft)
|
||||||
try {
|
try {
|
||||||
sendJsonPost(offer)
|
sendJsonPost(ServerConstants.DISCORD_GE_WEBHOOK, offer)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postPlayerAlert(player: String, type: String) {
|
||||||
|
GlobalScope.launch {
|
||||||
|
val alert = encodeUserAlert(type, player)
|
||||||
|
try {
|
||||||
|
sendJsonPost(ServerConstants.DISCORD_MOD_WEBHOOK, alert)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +100,23 @@ object Discord {
|
||||||
return obj.toJSONString()
|
return obj.toJSONString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun encodeUserAlert(type: String, player: String) : String {
|
||||||
|
val obj = JSONObject()
|
||||||
|
val embeds = JSONArray()
|
||||||
|
val embed = JSONObject()
|
||||||
|
|
||||||
|
val fields = arrayOf(
|
||||||
|
EmbedField("Player", player, false),
|
||||||
|
EmbedField("Type", type, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
embed["title"] = "Player Alert"
|
||||||
|
embed["fields"] = getFields(fields)
|
||||||
|
embeds.add(embed)
|
||||||
|
obj["embeds"] = embeds
|
||||||
|
return obj.toJSONString()
|
||||||
|
}
|
||||||
|
|
||||||
private fun getFields(fields: Array<EmbedField>): JSONArray {
|
private fun getFields(fields: Array<EmbedField>): JSONArray {
|
||||||
val arr = JSONArray()
|
val arr = JSONArray()
|
||||||
|
|
||||||
|
|
@ -110,8 +139,8 @@ object Discord {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendJsonPost(data: String) {
|
private fun sendJsonPost(url: String = ServerConstants.DISCORD_GE_WEBHOOK, data: String) {
|
||||||
val conn = URL(ServerConstants.DISCORD_GE_WEBHOOK).openConnection() as HttpURLConnection
|
val conn = URL(url).openConnection() as HttpURLConnection
|
||||||
conn.doOutput = true
|
conn.doOutput = true
|
||||||
conn.requestMethod = "POST"
|
conn.requestMethod = "POST"
|
||||||
conn.setRequestProperty("Content-Type", "application/json")
|
conn.setRequestProperty("Content-Type", "application/json")
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,9 @@ class ServerConstants {
|
||||||
@JvmField
|
@JvmField
|
||||||
var DISCORD_GE_WEBHOOK = ""
|
var DISCORD_GE_WEBHOOK = ""
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
var DISCORD_MOD_WEBHOOK = ""
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
var PRELOAD_MAP = false
|
var PRELOAD_MAP = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import core.game.world.map.Location
|
||||||
import core.game.world.map.RegionManager
|
import core.game.world.map.RegionManager
|
||||||
import core.game.world.map.path.Pathfinder
|
import core.game.world.map.path.Pathfinder
|
||||||
import core.game.world.update.flag.context.Graphics
|
import core.game.world.update.flag.context.Graphics
|
||||||
|
import discord.Discord
|
||||||
import rs09.game.content.ame.events.MysteriousOldManNPC
|
import rs09.game.content.ame.events.MysteriousOldManNPC
|
||||||
import rs09.game.content.global.WeightBasedTable
|
import rs09.game.content.global.WeightBasedTable
|
||||||
import rs09.tools.secondsToTicks
|
import rs09.tools.secondsToTicks
|
||||||
|
|
@ -104,6 +105,7 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
|
||||||
player.properties.teleportLocation = Location.create(3212, 9620, 0)
|
player.properties.teleportLocation = Location.create(3212, 9620, 0)
|
||||||
}
|
}
|
||||||
player.graphics(SMOKE_GRAPHICS)
|
player.graphics(SMOKE_GRAPHICS)
|
||||||
|
Discord.postPlayerAlert(player.username, "Ignored Random")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import rs09.game.world.GameWorld
|
||||||
import core.game.world.map.Location
|
import core.game.world.map.Location
|
||||||
import rs09.game.world.repository.Repository
|
import rs09.game.world.repository.Repository
|
||||||
import core.plugin.Initializable
|
import core.plugin.Initializable
|
||||||
|
import rs09.ServerStore
|
||||||
|
import rs09.ServerStore.Companion.addToList
|
||||||
import rs09.game.system.command.Privilege
|
import rs09.game.system.command.Privilege
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
@ -84,6 +86,59 @@ class ModerationCommandSet : CommandSet(Privilege.MODERATOR){
|
||||||
* =============================================================================================================
|
* =============================================================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ban all players on a given IP
|
||||||
|
* =============================================================================================================
|
||||||
|
*/
|
||||||
|
define("ipban", Privilege.ADMIN, "::ipban <lt>IP<gt> <lt>TIME<gt>", "Bans all players on the given ip. Time format: <lt>INT<gt>d/s/m/h ex: 30d for 30 days."){ player, args ->
|
||||||
|
val ip = args[1]
|
||||||
|
val durationString = args[2]
|
||||||
|
val durationTokens = durationString.toCharArray()
|
||||||
|
var intToken = ""
|
||||||
|
var durationMillis = 0L
|
||||||
|
var durationUnit: TimeUnit = TimeUnit.NANOSECONDS
|
||||||
|
for(token in durationTokens){
|
||||||
|
if(token.toString().toIntOrNull() != null) intToken += token
|
||||||
|
else {
|
||||||
|
val durationInt: Int = (intToken.toIntOrNull() ?: -1).also { if(it == -1) reject(player, "Invalid duration: $intToken") }
|
||||||
|
durationUnit = when(token) {
|
||||||
|
'd' -> TimeUnit.DAYS
|
||||||
|
's' -> TimeUnit.SECONDS
|
||||||
|
'm' -> TimeUnit.MINUTES
|
||||||
|
'h' -> TimeUnit.HOURS
|
||||||
|
else -> TimeUnit.SECONDS
|
||||||
|
}
|
||||||
|
durationMillis = durationUnit.toMillis(durationInt.toLong())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val playersToBan = GameWorld.accountStorage.getUsernamesWithIP(ip)
|
||||||
|
if (playersToBan.isEmpty()) {
|
||||||
|
reject(player, "No accounts found on IP $ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p in playersToBan) {
|
||||||
|
val playerToKick = Repository.getPlayerByName(p)
|
||||||
|
playerToKick?.details?.accountInfo?.banEndTime = System.currentTimeMillis() + durationMillis
|
||||||
|
playerToKick?.clear(true)
|
||||||
|
GameWorld.Pulser.submit(object : Pulse(2) {
|
||||||
|
override fun pulse(): Boolean {
|
||||||
|
val info = GameWorld.accountStorage.getAccountInfo(p)
|
||||||
|
info.banEndTime = System.currentTimeMillis() + durationMillis
|
||||||
|
GameWorld.accountStorage.update(info)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerStore.getArchive("flagged-ips").addToList("ips", ip)
|
||||||
|
|
||||||
|
notify(player, "Banned all accounts on $ip for $intToken ${durationUnit.name.toLowerCase()}.")
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* =============================================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mute a player
|
* Mute a player
|
||||||
* =============================================================================================================
|
* =============================================================================================================
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ object ServerConfigParser {
|
||||||
ServerConstants.USE_AUTH = data.getBoolean("server.use_auth", true)
|
ServerConstants.USE_AUTH = data.getBoolean("server.use_auth", true)
|
||||||
ServerConstants.PERSIST_ACCOUNTS = data.getBoolean("server.persist_accounts", true)
|
ServerConstants.PERSIST_ACCOUNTS = data.getBoolean("server.persist_accounts", true)
|
||||||
ServerConstants.DAILY_ACCOUNT_LIMIT = data.getLong("server.daily_accounts_per_ip", 3L).toInt()
|
ServerConstants.DAILY_ACCOUNT_LIMIT = data.getLong("server.daily_accounts_per_ip", 3L).toInt()
|
||||||
|
ServerConstants.DISCORD_MOD_WEBHOOK = data.getString("server.moderation_webhook", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import core.game.node.entity.player.info.login.LoginType
|
||||||
import core.net.Constants
|
import core.net.Constants
|
||||||
import core.net.IoSession
|
import core.net.IoSession
|
||||||
import core.tools.StringUtils
|
import core.tools.StringUtils
|
||||||
|
import discord.Discord
|
||||||
import proto.management.JoinClanRequest
|
import proto.management.JoinClanRequest
|
||||||
import proto.management.PlayerStatusUpdate
|
import proto.management.PlayerStatusUpdate
|
||||||
import proto.management.RequestContactInfo
|
import proto.management.RequestContactInfo
|
||||||
|
|
@ -124,6 +125,12 @@ object Login {
|
||||||
details.session = session
|
details.session = session
|
||||||
details.info.translate(UIDInfo(details.ipAddress, "DEPRECATED", "DEPRECATED", "DEPRECATED"))
|
details.info.translate(UIDInfo(details.ipAddress, "DEPRECATED", "DEPRECATED", "DEPRECATED"))
|
||||||
|
|
||||||
|
val archive = ServerStore.getArchive("flagged-ips")
|
||||||
|
val flaggedIps = archive.getList<String>("ips")
|
||||||
|
if (flaggedIps.contains(details.ipAddress)) {
|
||||||
|
Discord.postPlayerAlert(details.username, "Login from flagged IP ${details.ipAddress}")
|
||||||
|
}
|
||||||
|
|
||||||
if (checkAccountLimit(details.ipAddress, details.username)) {
|
if (checkAccountLimit(details.ipAddress, details.username)) {
|
||||||
val player = Player(details)
|
val player = Player(details)
|
||||||
if (Repository.getPlayerByName(player.name) == null) {
|
if (Repository.getPlayerByName(player.name) == null) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import rs09.auth.UserAccountInfo
|
||||||
interface AccountStorageProvider {
|
interface AccountStorageProvider {
|
||||||
fun checkUsernameTaken(username: String): Boolean
|
fun checkUsernameTaken(username: String): Boolean
|
||||||
fun getAccountInfo(username: String): UserAccountInfo
|
fun getAccountInfo(username: String): UserAccountInfo
|
||||||
|
fun getUsernamesWithIP(ip: String) : List<String>
|
||||||
fun store(info: UserAccountInfo)
|
fun store(info: UserAccountInfo)
|
||||||
fun update(info: UserAccountInfo)
|
fun update(info: UserAccountInfo)
|
||||||
fun remove(info: UserAccountInfo)
|
fun remove(info: UserAccountInfo)
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,8 @@ class InMemoryStorageProvider : AccountStorageProvider {
|
||||||
override fun getOnlineFriends(username: String): List<String> {
|
override fun getOnlineFriends(username: String): List<String> {
|
||||||
return ArrayList()
|
return ArrayList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getUsernamesWithIP(ip: String): List<String> {
|
||||||
|
return ArrayList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,9 +177,24 @@ class SQLStorageProvider : AccountStorageProvider {
|
||||||
return friends
|
return friends
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getUsernamesWithIP(ip: String): List<String> {
|
||||||
|
val conn = getConnection()
|
||||||
|
val res = ArrayList<String>()
|
||||||
|
conn.use {
|
||||||
|
val query = it.prepareStatement(accountsByIPQuery)
|
||||||
|
query.setString(1, ip)
|
||||||
|
val r = query.executeQuery()
|
||||||
|
while (r.next()) {
|
||||||
|
res.add(r.getString(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val usernameQuery = "SELECT username FROM members WHERE username = ?;"
|
private const val usernameQuery = "SELECT username FROM members WHERE username = ?;"
|
||||||
private const val removeInfoQuery = "DELETE FROM members WHERE username = ?;"
|
private const val removeInfoQuery = "DELETE FROM members WHERE username = ?;"
|
||||||
|
private const val accountsByIPQuery = "SELECT username FROM members WHERE lastGameIp = ?;"
|
||||||
private const val accountInfoQuery = "SELECT " +
|
private const val accountInfoQuery = "SELECT " +
|
||||||
"username," +
|
"username," +
|
||||||
"password," +
|
"password," +
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue