Skip to content

Commit

Permalink
replace ipintel with ip2proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasf committed Apr 28, 2020
1 parent e192c0a commit a1b17ec
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 92 deletions.
1 change: 0 additions & 1 deletion COPYING.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ Lichess as deployed on https://lichess.org/ also uses these external services:
* [stripe](https://stripe.com/) and [PayPal](https://www.paypal.com) for [Patron donations](https://lichess.org/patron)
* [Spreadshirt](https://shop.spreadshirt.com/lichess-org) for the [Swag store](https://lichess.org/swag)
* [check.torproject.org](https://check.torproject.org/exit-addresses) for a list or Tor exit nodes
* [getipintel.net](https://getipintel.net/)
* [detectlanguage.com](https://detectlanguage.com/)
* Fallback to [Google Fonts](https://fonts.google.com/)
* [Google Cloud Messaging](https://developers.google.com/cloud-messaging/) and [OneSignal](https://onesignal.com/) for mobile notifications
Expand Down
8 changes: 5 additions & 3 deletions app/controllers/Mod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import lila.chat.Chat
import lila.common.{ EmailAddress, HTTPRequest, IpAddress }
import lila.mod.UserSearch
import lila.report.{ Suspect, Mod => AsMod }
import lila.security.{ FingerHash, IpIntel, Permission }
import lila.security.{ FingerHash, Ip2Proxy, Permission }
import lila.user.{ User => UserModel, Title }
import ornicar.scalalib.Zero
import views._
Expand Down Expand Up @@ -268,8 +268,10 @@ final class Mod(
def communicationPublic(username: String) = communications(username, false)
def communicationPrivate(username: String) = communications(username, true)

def ipIntel(ip: String) = Secure(_.IpBan) { _ => _ =>
env.security.ipIntel.failable(IpAddress(ip), IpIntel.Reason.UserMod).map { Ok(_) }.recover {
def ip2proxy(ip: String) = Secure(_.IpBan) { _ => _ =>
env.security.ip2proxy.failable(IpAddress(ip), Ip2Proxy.Reason.UserMod).dmap { proxyType =>
Ok(proxyType.value)
}.recover {
case e: Exception => InternalServerError(e.getMessage)
}
}
Expand Down
5 changes: 2 additions & 3 deletions conf/base.conf
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,8 @@ security {
}
recaptcha = ${recaptcha}
mailgun = ${mailgun}
ipintel {
url = "https://check.getipintel.net/check.php"
email = ""
ip2proxy {
url = "http://ip2proxy.lichess.ovh:1929"
}
lame_name_check = true
}
Expand Down
2 changes: 1 addition & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ GET /mod/table controllers.Mod.table
POST /mod/:username/refreshUserAssess controllers.Mod.refreshUserAssess(username: String)
POST /mod/:username/email controllers.Mod.setEmail(username: String)
POST /mod/:username/notify-slack controllers.Mod.notifySlack(username: String)
GET /mod/ip-intel controllers.Mod.ipIntel(ip: String)
GET /mod/ip2proxy controllers.Mod.ip2proxy(ip: String)
GET /mod/leaderboard controllers.Mod.gamify
GET /mod/leaderboard/:period controllers.Mod.gamifyPeriod(period: String)
GET /mod/search controllers.Mod.search
Expand Down
5 changes: 2 additions & 3 deletions modules/common/src/main/mon.scala
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,8 @@ object mon {
val prints = gauge("security.firewall.prints").withoutTags
}
object proxy {
def ipintel(reason: String) = counter("security.proxy.ipintel").withTag("reason", reason)
val request = future("security.proxy.time")
val percent = histogram("security.proxy.percent").withoutTags
def reason(reason: String) = counter("security.proxy.reason").withTag("reason", reason)
val request = future("security.proxy.time")
}
def rateLimit(key: String) = counter("security.rateLimit.count").withTag("key", key)
def concurrencyLimit(key: String) = counter("security.concurrencyLimit.count").withTag("key", key)
Expand Down
8 changes: 4 additions & 4 deletions modules/security/src/main/Env.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import play.api.libs.ws.WSClient
import scala.concurrent.duration._

import lila.common.config._
import lila.common.{ Bus, EmailAddress, Strings }
import lila.common.{ Bus, Strings }
import lila.memo.SettingStore.Strings._
import lila.oauth.OAuthServer
import lila.user.{ Authenticator, UserRepo }
Expand Down Expand Up @@ -53,9 +53,9 @@ final class Env(

lazy val store = new Store(db(config.collection.security), net.ip)

lazy val ipIntel = {
def mk = (url: String, email: EmailAddress) => wire[IpIntel]
mk(config.ipIntelUrl, config.ipIntelEmail)
lazy val ip2proxy = {
def mk = (url: String) => wire[Ip2Proxy]
mk(config.ip2ProxyUrl)
}

lazy val ugcArmedSetting = settingStore[Boolean](
Expand Down
4 changes: 2 additions & 2 deletions modules/security/src/main/GarbageCollector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ final class GarbageCollector(
case ApplyData(user, ip, email, req) =>
for {
spy <- userSpy(user)
ipSusp <- ipTrust.isSuspicious(ip, IpIntel.Reason.GarbageCollector)
ipSusp <- ipTrust.isSuspicious(ip, Ip2Proxy.Reason.GarbageCollector)
} yield {
val printOpt = spy.prints.headOption
logger.debug(s"apply ${data.user.username} print=${printOpt}")
Expand All @@ -67,7 +67,7 @@ final class GarbageCollector(
badOtherAccounts(spy.otherUsers.map(_.user)) ?? { others =>
logger.debug(s"other ${data.user.username} others=${others.map(_.username)}")
lila.common.Future
.exists(spy.ips)(ipTrust.isSuspicious(_, IpIntel.Reason.GarbageCollector))
.exists(spy.ips)(ipTrust.isSuspicious(_, Ip2Proxy.Reason.GarbageCollector))
.map {
_ ?? collect(
user,
Expand Down
59 changes: 59 additions & 0 deletions modules/security/src/main/Ip2Proxy.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package lila.security

import play.api.libs.ws.WSClient
import scala.concurrent.duration._
import com.github.blemale.scaffeine.AsyncCache

import lila.common.IpAddress

final class Ip2Proxy(
ws: WSClient,
cacheApi: lila.memo.CacheApi,
checkUrl: String
)(implicit ec: scala.concurrent.ExecutionContext) {

import Ip2Proxy._

def apply(ip: IpAddress, reason: Reason): Fu[ProxyType] = failable(ip, reason).nevermind(ProxyType("-"))

def failable(ip: IpAddress, reason: Reason): Fu[ProxyType] =
if (isBlacklisted(ip)) fuccess(ProxyType("BLK"))
else cache.getFuture(ip, get(reason))

private val cache: AsyncCache[IpAddress, ProxyType] = cacheApi.scaffeine
.expireAfterWrite(1 days)
.buildAsync

private def get(reason: Reason)(ip: IpAddress): Fu[ProxyType] = {
lila.mon.security.proxy.reason(reason.toString).increment()
ws.url(checkUrl)
.addQueryStringParameters("ip" -> ip.value)
.get()
.map { body =>
ProxyType((body.json \ "proxy_type").asOpt[String] getOrElse "-")
}
.monSuccess(_.security.proxy.request)
}
}

object Ip2Proxy {

case class ProxyType(value: String) extends AnyVal {
def isProxy = value != "-"
}

sealed trait Reason
object Reason {
case object GarbageCollector extends Reason
case object UserMod extends Reason
case object Signup extends Reason
}

// Proxies ip2proxy does not detect
private val blackList = List(
"5.121.",
"5.122."
)

def isBlacklisted(ip: IpAddress): Boolean = blackList.exists(ip.value.startsWith)
}
62 changes: 0 additions & 62 deletions modules/security/src/main/IpIntel.scala

This file was deleted.

12 changes: 6 additions & 6 deletions modules/security/src/main/IpTrust.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@ package lila.security

import lila.common.IpAddress

final class IpTrust(intelApi: IpIntel, geoApi: GeoIP, torApi: Tor, firewallApi: Firewall) {
final class IpTrust(proxyApi: Ip2Proxy, geoApi: GeoIP, torApi: Tor, firewallApi: Firewall) {

def isSuspicious(ip: IpAddress, reason: IpIntel.Reason): Fu[Boolean] =
if (IpIntel isBlacklisted ip) fuTrue
def isSuspicious(ip: IpAddress, reason: Ip2Proxy.Reason): Fu[Boolean] =
if (Ip2Proxy isBlacklisted ip) fuTrue
else if (firewallApi blocksIp ip) fuTrue
else if (torApi isExitNode ip) fuTrue
else {
val location = geoApi orUnknown ip
if (location == Location.unknown || location == Location.tor) fuTrue
else if (isUndetectedProxy(location)) fuTrue
else intelApi(ip, reason).dmap { 75 < _ }
else proxyApi(ip, reason).dmap(_.isProxy)
}

def isSuspicious(ipData: UserSpy.IPData, reason: IpIntel.Reason): Fu[Boolean] =
def isSuspicious(ipData: UserSpy.IPData, reason: Ip2Proxy.Reason): Fu[Boolean] =
isSuspicious(ipData.ip.value, reason)

/* lichess blacklist of proxies that ipintel doesn't know about */
/* lichess blacklist of proxies that ip2proxy doesn't know about */
private def isUndetectedProxy(location: Location): Boolean =
location.shortCountry == "Iran" ||
location.shortCountry == "United Arab Emirates" ||
Expand Down
4 changes: 1 addition & 3 deletions modules/security/src/main/SecurityConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import io.methvin.play.autoconfig._
import scala.concurrent.duration.FiniteDuration

import lila.common.config._
import lila.common.EmailAddress

import SecurityConfig._

Expand All @@ -24,8 +23,7 @@ final private class SecurityConfig(
@ConfigName("check_mail_api") val checkMail: CheckMail,
val recaptcha: Recaptcha.Config,
val mailgun: Mailgun.Config,
@ConfigName("ipintel.url") val ipIntelUrl: String,
@ConfigName("ipintel.email") val ipIntelEmail: EmailAddress,
@ConfigName("ip2proxy.url") val ip2ProxyUrl: String,
@ConfigName("lame_name_check") val lameNameCheck: LameNameCheck
)

Expand Down
4 changes: 2 additions & 2 deletions modules/security/src/main/Signup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class Signup(
store.recentByPrintExists(fp) flatMap { printFound =>
if (printFound) fuccess(YesBecausePrintExists)
else
ipTrust.isSuspicious(ip, IpIntel.Reason.Signup).map {
ipTrust.isSuspicious(ip, Ip2Proxy.Reason.Signup).map {
case true => YesBecauseIpSusp
case _ => Nope
}
Expand Down Expand Up @@ -172,7 +172,7 @@ final class Signup(
s"fp: ${fingerPrint} mustConfirm: $mustConfirm fp: ${fingerPrint.??(_.value)} api: ${apiVersion.??(_.value)}"
)
val ip = HTTPRequest lastRemoteAddress req
ipTrust.isSuspicious(ip, IpIntel.Reason.Signup) foreach { susp =>
ipTrust.isSuspicious(ip, Ip2Proxy.Reason.Signup) foreach { susp =>
slack.signup(user, email, ip, fingerPrint.flatMap(_.hash).map(_.value), apiVersion, susp)
}
}
Expand Down
4 changes: 2 additions & 2 deletions ui/site/src/user-mod.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ function userMod($zone) {
var $li = $(this);
$(this).one('mouseover', function() {
$.ajax({
url: '/mod/ip-intel?ip=' + $(this).find('.address ip').text(),
url: '/mod/ip2proxy?ip=' + $(this).find('.address ip').text(),
success: function(res) {
$li.append($('<span class="intel">' + res + '% proxy</span>'));
$li.append($('<span class="intel"></span>').text(res));
}
});
});
Expand Down

0 comments on commit a1b17ec

Please sign in to comment.