-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ETCM-331] Add ip limit in the faucet for sendFunds requests
- Loading branch information
1 parent
65c23ba
commit 84929cb
Showing
7 changed files
with
202 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
src/main/scala/io/iohk/ethereum/jsonrpc/server/http/FaucetJsonRpcHttpServer.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package io.iohk.ethereum.jsonrpc.server.http | ||
|
||
import java.security.SecureRandom | ||
import java.time.Clock | ||
|
||
import akka.actor.ActorSystem | ||
import akka.http.scaladsl.model.{RemoteAddress, StatusCodes} | ||
import akka.http.scaladsl.server.Directives._ | ||
import akka.http.scaladsl.server.{Route, StandardRoute} | ||
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.cors | ||
import com.twitter.util.LruMap | ||
import io.iohk.ethereum.faucet.jsonrpc.FaucetJsonRpcController | ||
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController | ||
import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig | ||
import io.iohk.ethereum.jsonrpc.{JsonRpcHealthChecker, JsonRpcRequest} | ||
import io.iohk.ethereum.utils.Logger | ||
import monix.execution.Scheduler.Implicits.global | ||
|
||
trait FaucetJsonRpcHttpServer extends JsonRpcHttpServer { | ||
|
||
val minRequestInterval: Int | ||
|
||
val latestTimestampCacheSize: Int | ||
|
||
val latestRequestTimestamps: LruMap[RemoteAddress, Long] | ||
|
||
val clock: Clock = Clock.systemUTC() | ||
|
||
override def route: Route = cors(corsSettings) { | ||
(pathEndOrSingleSlash & post) { | ||
(extractClientIP & entity(as[JsonRpcRequest])) { (clientAddress: RemoteAddress, request: JsonRpcRequest) => | ||
handleRequest(clientAddress, request) | ||
} | ||
} | ||
} | ||
|
||
def handleRequest(clientAddr: RemoteAddress, request: JsonRpcRequest): StandardRoute = { | ||
val timeMillis = clock.instant().toEpochMilli | ||
|
||
if (request.method == FaucetJsonRpcController.SendFunds) { | ||
val latestRequestTimestamp = latestRequestTimestamps.getOrElse(clientAddr, 0L) | ||
if (latestRequestTimestamp + minRequestInterval < timeMillis) { | ||
latestRequestTimestamps.put(clientAddr, timeMillis) | ||
complete(jsonRpcController.handleRequest(request).runToFuture) | ||
} else { | ||
complete(StatusCodes.TooManyRequests) | ||
} | ||
} else complete(jsonRpcController.handleRequest(request).runToFuture) | ||
} | ||
} | ||
|
||
object FaucetJsonRpcHttpServer extends Logger { | ||
def apply( | ||
jsonRpcController: JsonRpcBaseController, | ||
jsonRpcHealthchecker: JsonRpcHealthChecker, | ||
config: JsonRpcHttpServerConfig, | ||
secureRandom: SecureRandom | ||
)(implicit actorSystem: ActorSystem): Either[String, JsonRpcHttpServer] = | ||
config.mode match { | ||
case "http" => | ||
Right(new FaucetBasicJsonRpcHttpServer(jsonRpcController, jsonRpcHealthchecker, config)(actorSystem)) | ||
case "https" => | ||
Right(new FaucetJsonRpcHttpsServer(jsonRpcController, jsonRpcHealthchecker, config, secureRandom)(actorSystem)) | ||
case _ => Left(s"Cannot start JSON RPC server: Invalid mode ${config.mode} selected") | ||
} | ||
} | ||
|
||
class FaucetBasicJsonRpcHttpServer( | ||
jsonRpcController: JsonRpcBaseController, | ||
jsonRpcHealthChecker: JsonRpcHealthChecker, | ||
config: JsonRpcHttpServerConfig | ||
)(implicit actorSystem: ActorSystem) | ||
extends BasicJsonRpcHttpServer(jsonRpcController, jsonRpcHealthChecker, config)(actorSystem) | ||
with FaucetJsonRpcHttpServer { | ||
|
||
//FIXME: these 2 variables should be retrieved from a config file | ||
override val minRequestInterval: Int = 10000 | ||
override val latestTimestampCacheSize: Int = 1024 | ||
|
||
override val latestRequestTimestamps = new LruMap[RemoteAddress, Long](latestTimestampCacheSize) | ||
} | ||
|
||
class FaucetJsonRpcHttpsServer( | ||
jsonRpcController: JsonRpcBaseController, | ||
jsonRpcHealthChecker: JsonRpcHealthChecker, | ||
config: JsonRpcHttpServerConfig, | ||
secureRandom: SecureRandom | ||
)(implicit actorSystem: ActorSystem) | ||
extends JsonRpcHttpsServer(jsonRpcController, jsonRpcHealthChecker, config, secureRandom)(actorSystem) | ||
with FaucetJsonRpcHttpServer { | ||
|
||
//FIXME: these 2 variables should be retrieved from a config file | ||
val minRequestInterval: Int = 10000 | ||
val latestTimestampCacheSize: Int = 1024 | ||
|
||
override val latestRequestTimestamps = new LruMap[RemoteAddress, Long](latestTimestampCacheSize) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/main/scala/io/iohk/ethereum/jsonrpc/server/http/NodeJsonRpcHttpServer.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package io.iohk.ethereum.jsonrpc.server.http | ||
|
||
import java.security.SecureRandom | ||
|
||
import akka.actor.ActorSystem | ||
import akka.http.scaladsl.model.{ContentTypes, HttpEntity, HttpResponse, StatusCodes} | ||
import akka.http.scaladsl.server.{Route, StandardRoute} | ||
import io.iohk.ethereum.jsonrpc.JsonRpcHealthChecker | ||
import io.iohk.ethereum.jsonrpc.server.http.JsonRpcHttpServer.JsonRpcHttpServerConfig | ||
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.cors | ||
import akka.http.scaladsl.server.Directives._ | ||
import io.iohk.ethereum.jsonrpc._ | ||
import io.iohk.ethereum.jsonrpc.server.controllers.JsonRpcBaseController | ||
import io.iohk.ethereum.utils.Logger | ||
import monix.eval.Task | ||
import monix.execution.Scheduler.Implicits.global | ||
|
||
trait NodeJsonRpcHttpServer extends JsonRpcHttpServer { | ||
|
||
private def handleHealthcheck(): StandardRoute = { | ||
val responseF = jsonRpcHealthChecker.healthCheck() | ||
val httpResponseF = | ||
responseF.map { | ||
case response if response.isOK => | ||
HttpResponse( | ||
status = StatusCodes.OK, | ||
entity = HttpEntity(ContentTypes.`application/json`, serialization.writePretty(response)) | ||
) | ||
case response => | ||
HttpResponse( | ||
status = StatusCodes.InternalServerError, | ||
entity = HttpEntity(ContentTypes.`application/json`, serialization.writePretty(response)) | ||
) | ||
} | ||
complete(httpResponseF) | ||
} | ||
|
||
private def handleRequest(request: JsonRpcRequest) = { | ||
complete(jsonRpcController.handleRequest(request).runToFuture) | ||
} | ||
|
||
private def handleBatchRequest(requests: Seq[JsonRpcRequest]) = { | ||
complete { | ||
Task | ||
.traverse(requests)(request => jsonRpcController.handleRequest(request)) | ||
.runToFuture | ||
} | ||
} | ||
|
||
override def route: Route = cors(corsSettings) { | ||
(path("healthcheck") & pathEndOrSingleSlash & get) { | ||
handleHealthcheck() | ||
} ~ (pathEndOrSingleSlash & post) { | ||
entity(as[JsonRpcRequest]) { request: JsonRpcRequest => handleRequest(request) } ~ entity( | ||
as[Seq[JsonRpcRequest]] | ||
) { request => | ||
handleBatchRequest(request) | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
object NodeJsonRpcHttpServer extends Logger { | ||
def apply( | ||
jsonRpcController: JsonRpcBaseController, | ||
jsonRpcHealthchecker: JsonRpcHealthChecker, | ||
config: JsonRpcHttpServerConfig, | ||
secureRandom: SecureRandom | ||
)(implicit actorSystem: ActorSystem): Either[String, JsonRpcHttpServer] = | ||
config.mode match { | ||
case "http" => Right(new NodeBasicJsonRpcHttpServer(jsonRpcController, jsonRpcHealthchecker, config)(actorSystem)) | ||
case "https" => | ||
Right(new NodeJsonRpcHttpsServer(jsonRpcController, jsonRpcHealthchecker, config, secureRandom)(actorSystem)) | ||
case _ => Left(s"Cannot start JSON RPC server: Invalid mode ${config.mode} selected") | ||
} | ||
|
||
} | ||
|
||
class NodeBasicJsonRpcHttpServer( | ||
jsonRpcController: JsonRpcBaseController, | ||
jsonRpcHealthChecker: JsonRpcHealthChecker, | ||
config: JsonRpcHttpServerConfig | ||
)(implicit actorSystem: ActorSystem) | ||
extends BasicJsonRpcHttpServer(jsonRpcController, jsonRpcHealthChecker, config)(actorSystem) | ||
with NodeJsonRpcHttpServer {} | ||
|
||
class NodeJsonRpcHttpsServer( | ||
jsonRpcController: JsonRpcBaseController, | ||
jsonRpcHealthChecker: JsonRpcHealthChecker, | ||
config: JsonRpcHttpServerConfig, | ||
secureRandom: SecureRandom | ||
)(implicit actorSystem: ActorSystem) | ||
extends JsonRpcHttpsServer(jsonRpcController, jsonRpcHealthChecker, config, secureRandom)(actorSystem) | ||
with NodeJsonRpcHttpServer {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters