Added BadIPDetection

This commit is contained in:
bluefireoly
2020-10-19 17:51:21 +02:00
parent 51fa10eb53
commit fd505cd902
20 changed files with 311 additions and 69 deletions

View File

@@ -0,0 +1,118 @@
package net.axay.kspigot.ipaddress
import net.axay.kspigot.ipaddress.badipdetectionservices.GetIPIntel
import net.axay.kspigot.ipaddress.badipdetectionservices.IPHub
import org.bukkit.entity.Player
import org.json.JSONException
import org.json.JSONObject
/**
* Checks if the IP address of the player is not a
* normal residential address.
*
* This function returns true if just one of all
* available detection services detects a bad IP address.
*
* @param detector The compound of detection services.
*/
fun Player.hasBadIP(detector: BadIPDetector = BadIPDetector.DEFAULT) =
checkIP(detector).filterValues { it.isBad }.isNotEmpty()
/**
* Checks if the IP address of the player is not a
* normal residential address.
*
* This function returns the result of each
* detection service given by the [detector].
*
* @param detector The compound of detection services.
*/
fun Player.checkIP(
detector: BadIPDetector = BadIPDetector.DEFAULT,
breakOnHit: Boolean = true
): Map<BadIPDetectionService, BadIPDetectionResult> {
val ip = address?.hostString ?: return emptyMap()
return detector.checkIP(ip, breakOnHit)
}
/**
* @param services A list of [BadIPDetectionService]s.
* The order matters!
*/
class BadIPDetector(
val services: List<BadIPDetectionService>
) {
constructor(vararg services: BadIPDetectionService) : this(services.toList())
companion object {
val DEFAULT = BadIPDetector(
listOf(
GetIPIntel(),
IPHub()
)
)
}
fun checkIP(ip: String, breakOnHit: Boolean = true) =
HashMap<BadIPDetectionService, BadIPDetectionResult>().apply {
for (it in services) {
val curResult = it.isBad(ip)
this[it] = curResult
if (curResult.isBad && breakOnHit) break
}
}
}
enum class BadIPDetectionResult(
val isBad: Boolean,
val typeName: String
) {
GENERAL_BAD(true, "bad ip"),
VPN(true, "vpn"),
PROXY(true, "proxy"),
TOR(true, "tor network"),
HOSTING(true, "hosting"),
GOOD(false, "valid ip"),
ERROR(false, "error"),
LIMIT(false, "limit");
}
abstract class BadIPDetectionService(
val name: String
) {
protected abstract fun requestString(ip: String): String
protected abstract fun interpreteResult(result: JSONObject): BadIPDetectionResult
fun isBad(ip: String): BadIPDetectionResult {
val response = khttp.get(requestString(ip))
if (response.statusCode == 429)
return BadIPDetectionResult.LIMIT
else {
val result = try {
response.jsonObject
} catch (exc: JSONException) {
null
} ?: return BadIPDetectionResult.ERROR
return try {
interpreteResult(result)
} catch (exc: Exception) {
return BadIPDetectionResult.ERROR
}
}
}
}

View File

@@ -3,9 +3,10 @@
package net.axay.kspigot.ipaddress
import com.google.gson.JsonObject
import net.axay.kspigot.languageextensions.fromUrlJson
import net.axay.kspigot.languageextensions.getStringOrNull
import net.axay.kspigot.main.ValueHolder
import org.bukkit.entity.Player
import java.net.URL
private const val IP_API = "http://ip-api.com/json/"
private const val IP_API_FIELDS =
@@ -27,9 +28,8 @@ fun Player.ipAddressData(language: IPAddressDataLanguage = IPAddressDataLanguage
val hostString = address?.hostString ?: return null
val jsonObject = ValueHolder.getGson(false).fromJson(
URL("$IP_API${hostString}?fields=${IP_API_FIELDS}?lang=${language.code}").readText(),
JsonObject::class.java
val jsonObject = ValueHolder.getGson().fromUrlJson(
"$IP_API${hostString}?fields=${IP_API_FIELDS}?lang=${language.code}"
) ?: return null
if (jsonObject["status"].toString() == "fail") return null
@@ -55,32 +55,26 @@ enum class IPAddressDataLanguage(val code: String) {
class IPAddressData(private val json: JsonObject) {
val ip get() = json.getString("query")
val ip get() = json.getStringOrNull("query")
// region
val continent get() = json.getString("continent")
val continentCode get() = json.getString("continentCode")
val country get() = json.getString("country")
val countryCode get() = json.getString("countryCode")
val region get() = json.getString("regionName")
val regionCode get() = json.getString("region")
val city get() = json.getString("city")
val district get() = json.getString("district")
val postalCode get() = json.getString("zip")
val timezone get() = json.getString("timezone")
val continent get() = json.getStringOrNull("continent")
val continentCode get() = json.getStringOrNull("continentCode")
val country get() = json.getStringOrNull("country")
val countryCode get() = json.getStringOrNull("countryCode")
val region get() = json.getStringOrNull("regionName")
val regionCode get() = json.getStringOrNull("region")
val city get() = json.getStringOrNull("city")
val district get() = json.getStringOrNull("district")
val postalCode get() = json.getStringOrNull("zip")
val timezone get() = json.getStringOrNull("timezone")
// position
val latitude get() = json.getString("lat")
val longitude get() = json.getString("lon")
val latitude get() = json.getStringOrNull("lat")
val longitude get() = json.getStringOrNull("lon")
// information
val internetServiceProvider get() = json.getString("isp")
val organisation get() = json.getString("org")
val internetServiceProvider get() = json.getStringOrNull("isp")
val organisation get() = json.getStringOrNull("org")
}
private fun JsonObject.getString(key: String) = try {
this[key].toString()
} catch (exc: Exception) {
null
}

View File

@@ -0,0 +1,23 @@
@file:Suppress("MemberVisibilityCanBePrivate")
package net.axay.kspigot.ipaddress.badipdetectionservices
import net.axay.kspigot.ipaddress.BadIPDetectionResult
import net.axay.kspigot.ipaddress.BadIPDetectionService
import net.axay.kspigot.languageextensions.getStringOrNull
import org.json.JSONObject
class GetIPIntel(
private val intensity: Float = 0.99f,
private val contactEmail: String = "foo@bar.com"
) : BadIPDetectionService("getipintel.net") {
override fun requestString(ip: String) = "http://check.getipintel.net/check.php?ip=$ip&contact=$contactEmail"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val probability = result.getStringOrNull("result")?.toFloatOrNull()
?: return BadIPDetectionResult.ERROR
return if (probability >= intensity) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD
}
}

View File

@@ -0,0 +1,21 @@
@file:Suppress("MemberVisibilityCanBePrivate")
package net.axay.kspigot.ipaddress.badipdetectionservices
import net.axay.kspigot.ipaddress.BadIPDetectionResult
import net.axay.kspigot.ipaddress.BadIPDetectionService
import net.axay.kspigot.languageextensions.getStringOrNull
import org.json.JSONObject
class IPHub(
private val ifStrict: Boolean = false
) : BadIPDetectionService("iphub.info") {
override fun requestString(ip: String) = "http://v2.api.iphub.info/ip/$ip"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val ifBlock = result.getStringOrNull("block")?.toInt() ?: return BadIPDetectionResult.ERROR
return if (ifBlock == 1 || (ifStrict && ifBlock == 2)) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD
}
}

View File

@@ -0,0 +1,24 @@
package net.axay.kspigot.ipaddress.badipdetectionservices
import net.axay.kspigot.ipaddress.BadIPDetectionResult
import net.axay.kspigot.ipaddress.BadIPDetectionService
import net.axay.kspigot.languageextensions.getStringOrNull
import org.json.JSONObject
class IPInfo(
private val token: String
) : BadIPDetectionService("ipinfo.io") {
override fun requestString(ip: String) = "https://ipinfo.io/$ip/privacy?token=$token"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
return when {
result.getStringOrNull("vpn").toBoolean() -> BadIPDetectionResult.VPN
result.getStringOrNull("proxy").toBoolean() -> BadIPDetectionResult.PROXY
result.getStringOrNull("tor").toBoolean() -> BadIPDetectionResult.TOR
result.getStringOrNull("hosting").toBoolean() -> BadIPDetectionResult.HOSTING
else -> BadIPDetectionResult.GOOD
}
}
}

View File

@@ -0,0 +1,24 @@
package net.axay.kspigot.ipaddress.badipdetectionservices
import net.axay.kspigot.ipaddress.BadIPDetectionResult
import net.axay.kspigot.ipaddress.BadIPDetectionService
import net.axay.kspigot.languageextensions.getStringOrNull
import org.json.JSONObject
class VPNBlocker : BadIPDetectionService("vpnblocker.net") {
override fun requestString(ip: String) = "http://api.vpnblocker.net/v2/json/$ip"
override fun interpreteResult(result: JSONObject): BadIPDetectionResult {
val isBad = result.getStringOrNull("host-ip")
return when {
isBad != null -> if (isBad.toBoolean()) BadIPDetectionResult.GENERAL_BAD else BadIPDetectionResult.GOOD
else -> {
val remaining = result.getStringOrNull("remaining_requests")?.toIntOrNull()
?: return BadIPDetectionResult.ERROR
if (remaining <= 0) BadIPDetectionResult.LIMIT else BadIPDetectionResult.ERROR
}
}
}
}