rate limit lobby joins by IP, not socket UID

This commit is contained in:
Thibault Duplessis 2016-03-03 06:29:22 +07:00
parent 9d48c224c9
commit 0129c0e7db
7 changed files with 31 additions and 28 deletions

View file

@ -43,7 +43,7 @@ object Lobby extends LilaController {
def socket(apiVersion: Int) = SocketOption[JsValue] { implicit ctx =>
get("sri") ?? { uid =>
Env.lobby.socketHandler(uid = uid, user = ctx.me) map some
Env.lobby.socketHandler(uid = uid, ip = ctx.req.remoteAddress, user = ctx.me) map some
}
}

View file

@ -1,3 +1,3 @@
package lila
package object common extends PackageObject with WithPlay
package object common extends PackageObject with WithPlay

View file

@ -36,9 +36,9 @@ private[lobby] final class Socket(
history.since(v).fold(resync(m))(_ foreach sendMessage(m))
}
case Join(uid, user, blocks) =>
case Join(uid, ip, user, blocks) =>
val (enumerator, channel) = Concurrent.broadcast[JsValue]
val member = Member(channel, user, blocks, uid)
val member = Member(channel, user, blocks, uid, ip)
addMember(uid, member)
sender ! Connected(enumerator, member)

View file

@ -27,27 +27,28 @@ private[lobby] final class SocketHandler(
uid: String,
member: Member): Handler.Controller = {
case ("p", o) => o int "v" foreach { v => socket ! PingVersion(uid, v) }
case ("join", o) => JoinRateLimit(uid) {
case ("join", o) =>
o str "d" foreach { id =>
lobby ! BiteHook(id, uid, member.user)
JoinRateLimit(member.ip, s"hook:$id") {
lobby ! BiteHook(id, uid, member.user)
}
}
}
case ("cancel", o) => lobby ! CancelHook(uid)
case ("joinSeek", o) => JoinRateLimit(uid) {
for {
case ("joinSeek", o) => for {
id <- o str "d"
user <- member.user
} lobby ! BiteSeek(id, user)
}
} JoinRateLimit(member.ip, s"seek:$id") {
lobby ! BiteSeek(id, user)
}
case ("cancelSeek", o) => for {
id <- o str "d"
user <- member.user
} lobby ! CancelSeek(id, user)
}
def apply(uid: String, user: Option[User]): Fu[JsSocketHandler] =
def apply(uid: String, ip: String, user: Option[User]): Fu[JsSocketHandler] =
(user ?? (u => blocking(u.id))) flatMap { blockedUserIds =>
val join = Join(uid = uid, user = user, blocking = blockedUserIds)
val join = Join(uid = uid, ip = ip, user = user, blocking = blockedUserIds)
Handler(hub, socket, uid, join, user map (_.id)) {
case Connected(enum, member) =>
(controller(socket, uid, member), enum, member)

View file

@ -6,13 +6,13 @@ import lila.socket.SocketMember
import lila.user.User
private[lobby] case class LobbyUser(
id: String,
username: String,
troll: Boolean,
engine: Boolean,
booster: Boolean,
ratingMap: Map[String, Int],
blocking: Set[String]) {
id: String,
username: String,
troll: Boolean,
engine: Boolean,
booster: Boolean,
ratingMap: Map[String, Int],
blocking: Set[String]) {
def lame = engine || booster
}
@ -31,7 +31,8 @@ private[lobby] object LobbyUser {
private[lobby] case class Member(
channel: JsChannel,
user: Option[LobbyUser],
uid: String) extends SocketMember {
uid: String,
ip: String) extends SocketMember {
val userId = user map (_.id)
val troll = user ?? (_.troll)
@ -39,10 +40,11 @@ private[lobby] case class Member(
private[lobby] object Member {
def apply(channel: JsChannel, user: Option[User], blocking: Set[String], uid: String): Member = Member(
def apply(channel: JsChannel, user: Option[User], blocking: Set[String], uid: String, ip: String): Member = Member(
channel = channel,
user = user map { LobbyUser.make(_, blocking) },
uid = uid)
uid = uid,
ip = ip)
}
private[lobby] case class HookMeta(hookId: Option[String] = None)
@ -62,7 +64,7 @@ private[lobby] case class BiteHook(hookId: String, uid: String, user: Option[Lob
private[lobby] case class BiteSeek(seekId: String, user: LobbyUser)
private[lobby] case class JoinHook(uid: String, hook: Hook, game: Game, creatorColor: chess.Color)
private[lobby] case class JoinSeek(userId: String, seek: Seek, game: Game, creatorColor: chess.Color)
private[lobby] case class Join(uid: String, user: Option[User], blocking: Set[String])
private[lobby] case class Join(uid: String, ip: String, user: Option[User], blocking: Set[String])
private[lobby] case object Resync
private[lobby] case class HookIds(ids: List[String])

View file

@ -19,7 +19,7 @@ final class RateLimit(nb: Int, duration: Duration, name: String) {
logger.info(s"[start] $name ($nb/$duration)")
def apply[A](key: String)(op: => A)(implicit default: Zero[A]): A =
def apply[A](key: String, msg: => String = "")(op: => A)(implicit default: Zero[A]): A =
Option(storage getIfPresent key) match {
case None =>
storage.put(key, 1 -> makeClearAt)
@ -31,7 +31,7 @@ final class RateLimit(nb: Int, duration: Duration, name: String) {
storage.put(key, 1 -> makeClearAt)
op
case _ =>
logger.info(s"$name ($nb/$duration) $key")
logger.info(s"$name ($nb/$duration) $msg $key")
default.zero
}
}

View file

@ -3,5 +3,5 @@ package lila
import play.api.libs.iteratee._
import play.api.libs.json._
package object socket
extends PackageObject with WithPlay with socket.WithSocket
package object socket
extends PackageObject with WithPlay with socket.WithSocket