From 8f2028f600526ee370ed27260b0d0c4feeea091c Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:57:22 +0200 Subject: [PATCH] Limit default `from` and `to` API parameters (#2384) When not provided, we previously used unrestricted `from` and `to` parameters when reading from the DB. This can create issues when accidentally reading too much data. We now limit this to the last 24 hours, unless explicitly set by the caller. Note that when reading a lot of data, it's recommended to use postgres and read from a replica to ensure there's no impact on the running eclair instance. Fixes #2383 --- .../fr/acinq/eclair/api/directives/ExtraDirectives.scala | 6 ++++-- .../test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/directives/ExtraDirectives.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/directives/ExtraDirectives.scala index e7889d02ac..ff11b940e8 100644 --- a/eclair-node/src/main/scala/fr/acinq/eclair/api/directives/ExtraDirectives.scala +++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/directives/ExtraDirectives.scala @@ -30,6 +30,7 @@ import fr.acinq.eclair.payment.Bolt11Invoice import fr.acinq.eclair.{MilliSatoshi, ShortChannelId, TimestampSecond} import scala.concurrent.Future +import scala.concurrent.duration.DurationInt import scala.util.{Failure, Success} trait ExtraDirectives extends Directives { @@ -42,8 +43,9 @@ trait ExtraDirectives extends Directives { val nodeIdFormParam: NameReceptacle[PublicKey] = "nodeId".as[PublicKey] val nodeIdsFormParam: NameUnmarshallerReceptacle[List[PublicKey]] = "nodeIds".as[List[PublicKey]](pubkeyListUnmarshaller) val paymentHashFormParam: NameUnmarshallerReceptacle[ByteVector32] = "paymentHash".as[ByteVector32](sha256HashUnmarshaller) - val fromFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "from".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.min) - val toFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "to".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.max) + // we limit default values to avoid accidentally reading too much data from the DB + val fromFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "from".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.now() - 1.day) + val toFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "to".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.now()) val amountMsatFormParam: NameReceptacle[MilliSatoshi] = "amountMsat".as[MilliSatoshi] val invoiceFormParam: NameReceptacle[Bolt11Invoice] = "invoice".as[Bolt11Invoice] val routeFormatFormParam: NameUnmarshallerReceptacle[RouteFormat] = "format".as[RouteFormat](routeFormatUnmarshaller) diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala index ff8a479a84..7b9f6798e1 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala @@ -1096,7 +1096,10 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM check { assert(handled) assert(status == OK) - eclair.audit(TimestampSecond.min, TimestampSecond.max)(any[Timeout]).wasCalled(once) + // The default is to get data for the last day. + val from = TimestampSecond.now() - 1.day + val to = TimestampSecond.now() + eclair.audit(argThat[TimestampSecond](t => from - 1.minute <= t && t <= from + 1.minute), argThat[TimestampSecond](t => to - 1.minute <= t && t <= to + 1.minute))(any[Timeout]).wasCalled(once) } Post("/audit", FormData("from" -> TimestampSecond.min.toLong.toString, "to" -> TimestampSecond.max.toLong.toString)) ~> @@ -1105,7 +1108,7 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM check { assert(handled) assert(status == OK) - eclair.audit(TimestampSecond.min, TimestampSecond.max)(any[Timeout]).wasCalled(twice) + eclair.audit(TimestampSecond.min, TimestampSecond.max)(any[Timeout]).wasCalled(once) } Post("/audit", FormData("from" -> 123456.toString, "to" -> 654321.toString)) ~>