Skip to content

Commit

Permalink
fixes #15
Browse files Browse the repository at this point in the history
  • Loading branch information
phelps-sg committed Dec 6, 2022
1 parent 895e944 commit a3677c6
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ class SlackSignatureVerifyAction @Inject() (
override val headerKeySignature: String = "X-Slack-Signature"
override val signingSecretConfigKey: String = "slack.signingSecret"

override def payload(timestamp: EpochSeconds, body: ByteString): String =
s"v0:$timestamp:${body.utf8String}"
override def payload(timestamp: EpochSeconds, body: ByteString): String = {
s"v0:${timestamp.value}:${body.utf8String}"
}

override def expectedSignature(macBytes: Array[Byte]): HmacSignature =
HmacSignature(
Expand Down
25 changes: 25 additions & 0 deletions src/test/scala/ActionTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2022 Steve Phelps
*/

import akka.util.ByteString
import com.mesonomics.playhmacsignatures.EpochSeconds
import org.scalatest.matchers.should
import org.scalatest.wordspec.AnyWordSpecLike

class ActionTests extends AnyWordSpecLike with should.Matchers {

trait TestFixtures extends CommonFixtures {
val timestamp: EpochSeconds = EpochSeconds(1000)
val body: ByteString = ByteString("test-body")
}

"SlackSignatureVerifyAction" should {
"compute the correct payload" in new TestFixtures {
slackSignatureVerifyAction.payload(
timestamp,
body
) shouldBe "v0:1000:test-body"
}
}
}
31 changes: 31 additions & 0 deletions src/test/scala/CommonFixtures.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2022 Steve Phelps
*/

import akka.actor.ActorSystem
import akka.stream.Materializer
import com.mesonomics.playhmacsignatures.{
SignatureVerifierService,
SlackSignatureVerifyAction
}
import org.scalamock.scalatest.MockFactory
import play.api.Configuration
import play.api.mvc.BodyParsers

import scala.concurrent.ExecutionContext.Implicits.global

trait CommonFixtures extends MockFactory {
val mockService: SignatureVerifierService = mock[SignatureVerifierService]
val config: Configuration = Configuration(
"slack.signingSecret" -> "test-secret"
)
implicit val system: ActorSystem = ActorSystem("ControllerTests")
implicit val mat: Materializer = Materializer(system)
val bp = new BodyParsers.Default()

val slackSignatureVerifyAction = new SlackSignatureVerifyAction(
bp,
config,
mockService
)
}
49 changes: 18 additions & 31 deletions src/test/scala/ControllerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@
* Copyright (c) 2022 Steve Phelps
*/

import akka.actor.ActorSystem
import akka.stream.Materializer
import akka.util.ByteString
import com.mesonomics.playhmacsignatures.{
EpochSeconds,
HmacSignature,
InvalidSignatureException,
SignatureVerifierService,
SlackSignatureVerifyAction
InvalidSignatureException
}
import org.scalamock.scalatest.MockFactory
import org.scalatest.matchers.must.Matchers.convertToAnyMustWrapper
import org.scalatest.matchers.should
import org.scalatest.wordspec.AnyWordSpecLike
import play.api.Configuration
import play.api.http.Status.{OK, UNAUTHORIZED}
import play.api.libs.json.Json
import play.api.mvc.BodyParsers
import play.api.libs.json.{JsValue, Json}
import play.api.test.Helpers.{POST, contentAsJson, defaultAwaitTimeout, status}
import play.api.test.{FakeRequest, Helpers}

Expand All @@ -33,44 +27,37 @@ class ControllerTests
with should.Matchers
with MockFactory {

"TestController" should {

val mockService = mock[SignatureVerifierService]
val config = Configuration("slack.signingSecret" -> "test-secret")
implicit val system: ActorSystem = ActorSystem("ControllerTests")
implicit val mat: Materializer = Materializer(system)
val bp = new BodyParsers.Default()

val slackSignatureVerifyAction = new SlackSignatureVerifyAction(
bp,
config,
mockService
)
trait TestFixtures extends CommonFixtures {

val testController = new TestController(
val testController: TestController = new TestController(
Helpers.stubControllerComponents(),
slackSignatureVerifyAction
)

val messageJson = Json.parse(""" { "message" : "Hello world!" } """)
val message = messageJson.toString()
val body = ByteString(message)
val messageJson: JsValue =
Json.parse(""" { "message" : "Hello world!" } """)
val message: String = messageJson.toString()
val body: ByteString = ByteString(message)

val signatureHeaders = Array(
val signatureHeaders: Array[(String, String)] = Array(
("X-Slack-Request-Timestamp", "1663156082"),
(
"X-Slack-Signature",
"v0=d1c387a20da72e5e07de4e2fb7e93cd9b44c2caa118868aad99c3b20c93de73a"
)
)

"return a 401 error when not supplying signatures" in {
}

"TestController" should {

"return a 401 error when not supplying signatures" in new TestFixtures {
val fakeRequest = FakeRequest(POST, "/").withBody(body)
val result = testController.test().apply(fakeRequest)
status(result) mustEqual UNAUTHORIZED
}

"return a 401 error when supplying empty timestamp" in {
"return a 401 error when supplying empty timestamp" in new TestFixtures {
val fakeRequest = FakeRequest(POST, "/").withBody(body)
val headersWithEmptyTimestamp = Array(
("X-Slack-Request-Timestamp", ""),
Expand All @@ -85,7 +72,7 @@ class ControllerTests
status(result) mustEqual UNAUTHORIZED
}

"return a 401 error when supplying non-numeric timestamp" in {
"return a 401 error when supplying non-numeric timestamp" in new TestFixtures {
val fakeRequest = FakeRequest(POST, "/").withBody(body)
val headersWithEmptyTimestamp = Array(
("X-Slack-Request-Timestamp", "non-numeric"),
Expand All @@ -100,7 +87,7 @@ class ControllerTests
status(result) mustEqual UNAUTHORIZED
}

"return a 401 error when supplying invalid signatures" in {
"return a 401 error when supplying invalid signatures" in new TestFixtures {

(mockService
.validate(_: Clock)(_: Duration)(
Expand All @@ -123,7 +110,7 @@ class ControllerTests
status(result) mustEqual UNAUTHORIZED
}

"return success when supplying valid signatures" in {
"return success when supplying valid signatures" in new TestFixtures {

(mockService
.validate(_: Clock)(_: Duration)(
Expand Down
7 changes: 2 additions & 5 deletions src/test/scala/ServiceTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,11 @@ class ServiceTests extends AnyWordSpecLike with should.Matchers {

"return success for a valid signature" in {
val verifier = new HmacSHA256SignatureVerifier()
val signature = validSignature(testBody, timestamp)
val result =
verifier.validate(clock)(timestampTolerance)(payload)(
expectedSignature
)(testSecret)(
timestamp,
testBody,
validSignature(testBody, timestamp)
)
)(testSecret)(timestamp, testBody, signature)
result should matchPattern { case Success(`testBody`) => }
}

Expand Down

0 comments on commit a3677c6

Please sign in to comment.