module WaiMiddlewareSlackVerifySpec ( spec ) where import Crypto.Hash import Crypto.Hash.Algorithms import Crypto.MAC.HMAC import Data.ByteArray.Encoding (convertToBase, Base(Base16)) import Data.ByteString (ByteString) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BC import Data.Time.Clock.POSIX import Test.Hspec import Test.HUnit hiding (Test) import Network.Wai import Network.Wai.Test import Network.Wai.Middleware.SlackVerify import Network.HTTP.Types spec :: Spec spec = describe "Network.Wai.Middleware.SlackVerify" $ do it "authenticates valid signatures" caseValidSignature it "rejects missing signature" caseMissingSignature it "rejects signature mismatch" caseSignatureMismatch testApp :: ByteString -> FailureResponse -> Application testApp secret h = verifySlackRequest' secret h $ \_ f -> f $ responseLBS status200 [] "" testSecret = "" testHandler e _ res = res $ responseLBS status403 [] msg where msg = case e of NoSignature -> "No signature" SignatureMismatch -> "Signature Mismatch" createHeaders :: ByteString -> ByteString -> [(HeaderName, ByteString)] createHeaders sig timestamp = [ ("Content-Type" , "application/json") , ("X-Slack-Request-Timestamp", timestamp) , ("X-Slack-Signature" , sig) ] getTimestamp :: IO ByteString getTimestamp = BC.pack . show . floor <$> getPOSIXTime caseValidSignature :: Assertion caseValidSignature = do timestamp <- getTimestamp flip runSession (testApp testSecret testHandler) $ do res <- request defaultRequest { requestHeaders = createHeaders (generateSignature timestamp) timestamp } assertStatus 200 res assertBody "" res where generateSignature t = let HMAC h = hmac testSecret $ (BS.concat ["v0", ":", t, ":", ""]) :: HMAC SHA256 in BS.append "v0=" (convertToBase Base16 h) caseMissingSignature :: Assertion caseMissingSignature = do flip runSession (testApp testSecret testHandler) $ do res <- request defaultRequest assertStatus 403 res assertBody "No signature" res caseSignatureMismatch :: Assertion caseSignatureMismatch = do timestamp <- getTimestamp flip runSession (testApp testSecret testHandler) $ do res <- request defaultRequest { requestHeaders = createHeaders "" timestamp } assertStatus 403 res assertBody "Signature Mismatch" res