packages feed

slack-web-1.5.0.0: tests/Web/Slack/Experimental/RequestVerificationSpec.hs

module Web.Slack.Experimental.RequestVerificationSpec where

import Data.Aeson
import Data.Aeson.KeyMap qualified as KeyMap
import Data.Time.Clock.POSIX
import TestImport
import Web.Slack.Experimental.RequestVerification

spec :: Spec
spec = do
  let timestamp = SlackRequestTimestamp "1665615887" -- Oct 12 2022 23:04:47 GMT+0000
  let sig = SlackSignature "v0=f7f0a2f48ae5fe2c923813af0a7c7636396fea6e03edb3d73580a99cd1913575"
  let slackSigningSecret = SlackSigningSecret "SIGNING_SECRET"
      -- matches the test timestamp within one minute
      goodUtcTime = utcTimeToPOSIXSeconds $ UTCTime (fromGregorian 2022 10 12) (23 * 60 * 60 + 5 * 60)
      -- back to the future
      someoneGotATimeMachineUtcTime = utcTimeToPOSIXSeconds $ UTCTime (fromGregorian 2020 1 1) 0
      oldUtcTime = utcTimeToPOSIXSeconds $ UTCTime (fromGregorian 2025 10 12) (23 * 60 * 60 + 5 * 60)

      -- the simplest possible JSON; this thing just parses it straight through
      -- anyway
      requestBody = "{}"

  describe "Slack Webhook" $ do
    it "Correctly validates webhooks" $ do
      validateRequest' goodUtcTime slackSigningSecret sig timestamp requestBody
        `shouldBe` (Right $ Object KeyMap.empty)

    it "Handles incorrect timestamp" $ do
      validateRequest' @Value goodUtcTime slackSigningSecret sig (SlackRequestTimestamp "bad") requestBody
        `shouldBe` Left (VerificationMalformedTimestamp "bad")

    it "Handles invalid signature" $ do
      validateRequest' @Value goodUtcTime slackSigningSecret (SlackSignature "the_v0_prefix_missing") timestamp requestBody
        `shouldBe` Left (VerificationUnknownSignatureVersion "the_v0_prefix_missing")

    it "Handles signature mismatch" $ do
      let badSignature = SlackSignature "v0=bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0bad0"
      validateRequest' @Value goodUtcTime slackSigningSecret badSignature timestamp requestBody
        `shouldBe` Left VerificationSignatureMismatch

    it "Handles timestamp in the future" $ do
      -- it's "in 2020" and someone gave us a 2022 timestamp
      validateRequest' @Value someoneGotATimeMachineUtcTime slackSigningSecret sig timestamp requestBody
        `shouldBe` Left (VerificationTimestampOutOfRange 1665615887)

    it "Handles timestamp in the past" $ do
      -- it's "in 2025" and someone gave us a 2022 timestamp
      validateRequest' @Value oldUtcTime slackSigningSecret sig timestamp requestBody
        `shouldBe` (Left (VerificationTimestampOutOfRange 1665615887))