refactor firewall

This commit is contained in:
Thibault Duplessis 2013-03-15 00:19:58 +01:00
parent 15817b8195
commit b3e6bf8614
4 changed files with 73 additions and 54 deletions

View file

@ -28,6 +28,7 @@ trait operator {
def $in[A: Writes](values: Seq[A]) = Json.obj("$in" -> Json.arr(values))
def $reg(value: String, flags: String = "") = BSONRegex(value, flags)
// def $date(value: DateTime) = Json.obj("$date" -> value.getMillis)
private def wrap[K, V : Writes](pairs: Seq[(K, V)]): Seq[(K, JsValueWrapper)] = pairs map {
case (k, v) k -> Json.toJsFieldJsValueWrapper(v)

View file

@ -1,21 +0,0 @@
package lila.memo
import scalaz.effects._
final class MonoMemo[A](ttl: Int, f: IO[A]) {
def apply: A = {
if (expired) refresh
value
}
private var value: A = _
private var ts: Double = 0
def refresh {
value = f.unsafePerformIO
ts = nowMillis
}
private def expired = nowMillis > ts + ttl
}

42
memo/VarMemo.scala Normal file
View file

@ -0,0 +1,42 @@
package lila.memo
import scala.concurrent.{ Future, Await }
import scala.concurrent.duration._
import scala.reflect._
import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.concurrent.Akka
import play.api.Play.current
final class VarMemo[A : ClassTag](load: Fu[A], atMost: FiniteDuration = 10.seconds) {
private case object Get
private implicit val timeout = Timeout(atMost)
def get: Fu[A] = (actor ? Get).mapTo[A]
def reload(fa: Fu[A]): Funit = fuccess(actor ! fa)
private val actor = Akka.system.actorOf(Props(new Actor {
private var value: Option[A] = none
private def reset(a: A) { value = a.some }
def receive = {
case Get value match {
case None sender ! (load.await ~ reset)
case Some(v) sender ! v
}
case fa: Fu[A] reset(fa.await)
}
}))
}
object VarMemo {
}

View file

@ -1,20 +1,23 @@
package lila.app
package security
package lila.security
import http.LilaCookie
import controllers.routes
import lila.common.LilaCookie
import lila.memo.VarMemo
import lila.db.Implicits._
import lila.db.DbApi
import scala.concurrent.duration._
import akka.util.Timeout
import play.api.mvc.{ RequestHeader, Handler, Action, Cookies }
import play.api.mvc.Results.Redirect
import com.mongodb.casbah.MongoCollection
import com.mongodb.casbah.Imports._
import java.util.Date
import play.api.libs.json._
import play.api.libs.concurrent.Execution.Implicits._
import play.modules.reactivemongo.Implicits._
import org.joda.time.DateTime
import ornicar.scalalib.Random
final class Firewall(
collection: MongoCollection,
cookieName: Option[String],
enabled: Boolean) {
final class Firewall(coll: ReactiveColl, cookieName: Option[String], enabled: Boolean) {
val requestHandler: (RequestHeader Option[Handler]) = enabled.fold(
cookieName.fold((_: RequestHeader) none[Handler]) { cn
@ -36,27 +39,19 @@ final class Firewall(
def accepts(req: RequestHeader): Boolean = !blocks(req)
def refresh { ips = fetch }
def refresh: Funit = ipsMemo reload fetch
def blockIp(ip: String) {
if (validIp(ip)) {
if (!blocksIp(ip)) {
log("Block IP: " + ip)
collection += DBObject("_id" -> ip, "date" -> new Date)
refresh
}
def blockIp(ip: String): Funit =
if (validIp(ip) && !blocksIp(ip)) {
log("Block IP: " + ip)
coll.insert(Json.obj("_id" -> ip, "date" -> DateTime.now)) >> refresh
}
else log("Invalid IP block: " + ip)
}
private def redirectHome(implicit req: RequestHeader) = Action {
Redirect(routes.Lobby.home())
}
else fuccess(log("Invalid IP block: " + ip))
private def infectCookie(name: String)(implicit req: RequestHeader) = Action {
log("Infect cookie " + formatReq(req))
val cookie = LilaCookie.cookie(name, Random nextString 32)
Redirect(routes.Lobby.home()) withCookies cookie
Redirect("/") withCookies cookie
}
def logBlock(req: RequestHeader) {
@ -70,7 +65,7 @@ final class Firewall(
private def formatReq(req: RequestHeader) =
"%s %s %s".format(req.remoteAddress, req.uri, req.headers.get("User-Agent") | "?")
private def blocksIp(ip: String) = ips contains ip
private def blocksIp(ip: String): Boolean = ips contains ip
private def blocksCookies(cookies: Cookies, name: String) =
(cookies get name).isDefined
@ -81,11 +76,13 @@ final class Firewall(
private def validIp(ip: String) =
(ipRegex matches ip) && ip != "127.0.0.1" && ip != "0.0.0.0"
private var ips = fetch
private implicit val timeout = Timeout(2.seconds)
private val ipsMemo = new VarMemo(fetch, 2.seconds)
private def fetch = {
collection.find().toList map { obj
obj.getAs[String]("_id")
}
}.flatten.toSet
private def ips: Set[String] = ipsMemo.get.await
private def fetch: Fu[Set[String]] =
coll.genericQueryBuilder
.projection(Json.obj("_id" -> true))
.cursor.toList map2 { (obj: JsObject) obj.get[String]("_id") } map (_.flatten.toSet)
}