Skip to content

Commit 80760f3

Browse files
authored
Revert "Revert "Filter out invalid topics from registration requests""
1 parent 48d6a0b commit 80760f3

3 files changed

Lines changed: 66 additions & 12 deletions

File tree

common/src/main/scala/models/Registration.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ object Registration {
2121
val n = (v \ "name").asOpt[String].getOrElse("unknown")
2222
s"$t (id=$n)"
2323
}
24-
val all = (json \ "topics").asOpt[JsArray].toSeq.flatMap(_.value.map(topicSummary))
25-
val invalid = (json \ "topics").asOpt[JsArray].toSeq.flatMap { arr =>
26-
arr.value.flatMap { v =>
27-
if (v.validate[Topic].isError) Some(topicSummary(v)) else None
28-
}
29-
}
30-
if (invalid.nonEmpty) {
31-
MDC.put("invalidTopics", invalid.mkString(", "))
32-
if (all.nonEmpty) MDC.put("allTopics", all.mkString(", "))
24+
25+
val topicsArray = (json \ "topics").asOpt[JsArray].getOrElse(JsArray())
26+
val (validTopics, invalidTopics) = topicsArray.value.partition(_.validate[Topic].isSuccess)
27+
28+
if (invalidTopics.nonEmpty) {
29+
MDC.put("invalidTopics", invalidTopics.map(topicSummary).mkString(", "))
30+
MDC.put("validTopics", validTopics.map(topicSummary).mkString(", "))
3331
}
34-
base.reads(json)
32+
33+
val filteredJson = json.as[JsObject] + ("topics" -> JsArray(validTopics))
34+
base.reads(filteredJson)
3535
},
3636
base
3737
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package models
2+
3+
import models.TopicTypes.{Breaking, FootballMatch}
4+
import org.specs2.mutable.Specification
5+
import play.api.libs.json.Json
6+
7+
class RegistrationSpec extends Specification {
8+
"Registration" should {
9+
"parse a valid registration" in {
10+
val json = Json.parse(
11+
"""{"deviceToken":"abc","platform":"ios","topics":[{"type":"breaking","name":"uk"}]}"""
12+
)
13+
val result = json.validate[Registration]
14+
result.isSuccess must beTrue
15+
result.get.topics must_== Set(Topic(Breaking, "uk"))
16+
}
17+
18+
"filter out invalid topic types and keep valid ones" in {
19+
val json = Json.parse(
20+
"""{"deviceToken":"abc","platform":"ios","topics":[{"type":"tag","name":"some-tag"},{"type":"breaking","name":"uk"}]}"""
21+
)
22+
val result = json.validate[Registration]
23+
result.isSuccess must beTrue
24+
result.get.topics must_== Set(Topic(Breaking, "uk"))
25+
}
26+
27+
"parse successfully with an empty topic set if all topics are invalid (controller will reject)" in {
28+
val json = Json.parse(
29+
"""{"deviceToken":"abc","platform":"ios","topics":[{"type":"tag","name":"some-tag"}]}"""
30+
)
31+
val result = json.validate[Registration]
32+
result.isSuccess must beTrue
33+
result.get.topics must beEmpty
34+
}
35+
36+
"still fail for other invalid fields" in {
37+
val json = Json.parse(
38+
"""{"deviceToken":"abc","platform":"unknown-platform","topics":[{"type":"breaking","name":"uk"}]}"""
39+
)
40+
json.validate[Registration].isError must beTrue
41+
}
42+
}
43+
}

registration/app/registration/controllers/Main.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import registration.services._
1414
import registration.services.topic.TopicValidator
1515

1616
import scala.concurrent.{ExecutionContext, Future}
17-
import org.slf4j.{Logger, LoggerFactory}
17+
import org.slf4j.{Logger, LoggerFactory, MDC}
1818
import play.api.http.HttpEntity
1919
import providers.ProviderError
2020

@@ -62,7 +62,18 @@ final class Main(
6262
registerWithConverter(legacyRegistrationConverter)
6363

6464
def register: Action[Registration] = actionWithTimeout(parse.json[Registration]) { request: Request[Registration] =>
65-
registerCommon(request.body).map(processResponse(_))
65+
Option(MDC.get("invalidTopics")).foreach { invalidTopics =>
66+
val validTopics = Option(MDC.get("validTopics")).getOrElse("")
67+
val userAgent = request.headers.get("User-Agent").getOrElse("unknown")
68+
val deviceToken = request.body.deviceToken
69+
logger.warn(s"Request contains invalid topic type(s): [$invalidTopics]. Filtering them out. Keeping: [$validTopics]. Device token: $deviceToken. User agent: $userAgent")
70+
MDC.remove("invalidTopics")
71+
MDC.remove("validTopics")
72+
}
73+
if (request.body.topics.isEmpty)
74+
Future.successful(BadRequest("Request contains no valid topics"))
75+
else
76+
registerCommon(request.body).map(processResponse(_))
6677
}
6778

6879
private def registerWithConverter[T](converter: RegistrationConverter[T])(implicit format: Format[T]): Action[T] = actionWithTimeout(parse.json[T]) { request =>

0 commit comments

Comments
 (0)