packages feed

aws-sns-verify 0.0.0.2 → 0.0.0.3

raw patch · 10 files changed

+250/−209 lines, 10 filesdep +crypton-x509dep +crypton-x509-validationdep −x509dep −x509-validationdep ~aesondep ~aeson-qqdep ~asyncPVP ok

version bump matches the API change (PVP)

Dependencies added: crypton-x509, crypton-x509-validation

Dependencies removed: x509, x509-validation

Dependency ranges changed: aeson, aeson-qq, async, bytestring, errors, hspec, http-conduit, http-types, memory, network-uri, pem, regex-tdfa, text, wai, warp

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,10 +1,15 @@-## [_Unreleased_](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.2...main)+## [_Unreleased_](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.3...main) -## [v0.0.0.2](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.2...v0.0.0.1)+## [v0.0.0.3](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.2...v0.0.0.3) +- Migrate to `crypton-x509*`+- Remove CI for GHC's 8.6 and 8.8++## [v0.0.0.2](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.1...v0.0.0.2)+ - Validate PEM has come from AWS before checking signature. -## [v0.0.0.1](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.1...v0.0.0.0)+## [v0.0.0.1](https://github.com/freckle/aws-sns-verify/compare/v0.0.0.0...v0.0.0.1)  - Fix typo in subscribe signature 
aws-sns-verify.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.18 name:               aws-sns-verify-version:            0.0.0.2+version:            0.0.0.3 license:            MIT license-file:       LICENSE copyright:          2022 Freckle By Renaissance@@ -59,18 +59,18 @@         -Wno-all-missed-specialisations      build-depends:-        aeson >=1.3.1.1,+        aeson,         base >=4.7 && <5,-        bytestring >=0.10.8.2,-        errors >=2.3.0,-        http-conduit >=2.3.2,-        memory >=0.14.18,-        network-uri >=2.6.1.0,-        pem >=0.2.4,-        regex-tdfa >=1.2.3.1,-        text >=1.2.3.1,-        x509 >=1.7.5,-        x509-validation >=1.6.11+        bytestring,+        crypton-x509,+        crypton-x509-validation,+        errors,+        http-conduit,+        memory,+        network-uri,+        pem,+        regex-tdfa,+        text      if impl(ghc >=8.10)         ghc-options:@@ -110,17 +110,17 @@         -Wno-all-missed-specialisations -threaded -rtsopts -with-rtsopts=-N      build-depends:-        aeson-qq >=0.8.2,-        async >=2.2.1,-        aws-sns-verify -any,+        aeson-qq,+        async,+        aws-sns-verify,         base >=4.7 && <5,-        hspec >=2.5.5,-        http-types >=0.12.2,-        regex-tdfa >=1.2.3.1,-        text >=1.2.3.1,-        wai >=3.2.1.2,-        warp >=3.2.25,-        x509-validation >=1.6.11+        crypton-x509-validation,+        hspec,+        http-types,+        regex-tdfa,+        text,+        wai,+        warp      if impl(ghc >=8.10)         ghc-options:
library/Amazon/SNS/Verify.hs view
@@ -3,7 +3,7 @@   , verifySNSMessageEither   , verifySNSMessageJSON   , verifySNSMessageJSONEither-  , SNSNotificationValidationError(..)+  , SNSNotificationValidationError (..)   ) where  import Amazon.SNS.Verify.Prelude@@ -12,7 +12,7 @@ import Amazon.SNS.Verify.Validate import Control.Error (hoistEither, runExceptT) import Data.Aeson (FromJSON, Value, eitherDecode)-import Data.Aeson.Types (Result(Error, Success), fromJSON)+import Data.Aeson.Types (Result (Error, Success), fromJSON) import Data.Bifunctor (first) import Data.ByteString.Lazy (fromStrict) import Data.Text.Encoding (encodeUtf8)@@ -20,7 +20,6 @@ -- | Decode and verify an SNS message as JSON -- -- The same as 'verifySNSMessage', but decodes the message as `JSON`.--- verifySNSMessageJSON :: (FromJSON a, MonadIO m) => Value -> m a verifySNSMessageJSON = unTryIO id <=< verifySNSMessageJSONEither @@ -45,7 +44,6 @@ --    or `UnsubscribeConfirmation`. -- 2. Verified against its signature. -- 3. And in the case of subscription events responded to.--- verifySNSMessage :: MonadIO m => Value -> m Text verifySNSMessage = unTryIO id <=< verifySNSMessageEither 
library/Amazon/SNS/Verify/Payload.hs view
@@ -1,8 +1,8 @@ module Amazon.SNS.Verify.Payload-  ( SNSPayload(..)-  , SNSType(..)-  , SNSNotification(..)-  , SNSSubscription(..)+  ( SNSPayload (..)+  , SNSType (..)+  , SNSNotification (..)+  , SNSSubscription (..)   ) where  import Amazon.SNS.Verify.Prelude@@ -69,7 +69,7 @@   deriving stock (Show, Eq, Generic)  instance FromJSON SNSNotification where-  parseJSON = genericParseJSON $ defaultOptions { fieldLabelModifier = drop 3 }+  parseJSON = genericParseJSON $ defaultOptions {fieldLabelModifier = drop 3}  data SNSSubscription = SNSSubscription   { snsToken :: Text@@ -78,4 +78,4 @@   deriving stock (Show, Eq, Generic)  instance FromJSON SNSSubscription where-  parseJSON = genericParseJSON $ defaultOptions { fieldLabelModifier = drop 3 }+  parseJSON = genericParseJSON $ defaultOptions {fieldLabelModifier = drop 3}
library/Amazon/SNS/Verify/Prelude.hs view
@@ -20,7 +20,7 @@ unTryIO :: (MonadIO m, Exception e) => (a -> e) -> Either a b -> m b unTryIO e = either (throwIO . e) pure -unTryE :: (Monad m) => (a -> e) -> Either a b -> ExceptT e m b+unTryE :: Monad m => (a -> e) -> Either a b -> ExceptT e m b unTryE e = either (throwE . e) pure  fromMaybeM :: Monad m => m a -> Maybe a -> m a
library/Amazon/SNS/Verify/ValidURI.hs view
@@ -9,6 +9,14 @@  import Amazon.SNS.Verify.Prelude +_devScheme :: String+_devScheme = "http:"++_prodScheme :: String+_prodScheme = "https:"++{- FOURMOLU_DISABLE -}+ validScheme :: String validScheme = #ifdef DEVELOPMENT@@ -17,12 +25,6 @@   _prodScheme #endif -_devScheme :: String-_devScheme = "http:"--_prodScheme :: String-_prodScheme = "https:"- validRegPattern :: String validRegPattern = #ifdef DEVELOPMENT@@ -30,6 +32,8 @@ #else   prodRegPattern #endif++{- FOURMOLU_ENABLE -}  devRegPattern :: String devRegPattern = "^localhost$"
library/Amazon/SNS/Verify/Validate.hs view
@@ -1,8 +1,8 @@ module Amazon.SNS.Verify.Validate   ( validateSnsMessage   , handleSubscription-  , SNSNotificationValidationError(..)-  , ValidSNSMessage(..)+  , SNSNotificationValidationError (..)+  , ValidSNSMessage (..)   ) where  import Amazon.SNS.Verify.Prelude@@ -11,23 +11,30 @@ import Amazon.SNS.Verify.ValidURI (validRegPattern, validScheme) import Control.Error (ExceptT, catMaybes, headMay, runExceptT, throwE) import Control.Monad (when)-import Data.ByteArray.Encoding (Base(Base64), convertFromBase)+import Data.ByteArray.Encoding (Base (Base64), convertFromBase) import Data.PEM (pemContent, pemParseLBS) import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8) import Data.X509-  ( HashALG(..)-  , PubKeyALG(..)-  , SignatureALG(..)+  ( HashALG (..)+  , PubKeyALG (..)+  , SignatureALG (..)   , SignedCertificate   , certPubKey   , decodeSignedCertificate   , getCertificate   ) import Data.X509.Validation-  (SignatureFailure, SignatureVerification(..), verifySignature)+  ( SignatureFailure+  , SignatureVerification (..)+  , verifySignature+  ) import Network.HTTP.Simple-  (getResponseBody, getResponseStatusCode, httpLbs, parseRequest_)+  ( getResponseBody+  , getResponseStatusCode+  , httpLbs+  , parseRequest_+  ) import Network.URI (parseURI, uriAuthority, uriRegName, uriScheme) import Text.Regex.TDFA ((=~)) @@ -43,24 +50,26 @@ -- in the documentation below. -- -- <https://docs.aws.amazon.com/sns/latest/dg/sns-verify-signature-of-message.html>--- validateSnsMessage   :: MonadIO m   => SNSPayload   -> m (Either SNSNotificationValidationError ValidSNSMessage) validateSnsMessage payload@SNSPayload {..} = runExceptT $ do-  signature <- unTryE BadSignature $ convertFromBase Base64 $ encodeUtf8-    snsSignature+  signature <-+    unTryE BadSignature+      $ convertFromBase Base64+      $ encodeUtf8+        snsSignature   signedCert <- retrieveCertificate payload-  let-    valid = verifySignature-      (SignatureALG HashSHA1 PubKeyALG_RSA)-      (certPubKey $ getCertificate signedCert)-      (unsignedSignature payload)-      signature+  let valid =+        verifySignature+          (SignatureALG HashSHA1 PubKeyALG_RSA)+          (certPubKey $ getCertificate signedCert)+          (unsignedSignature payload)+          signature   case valid of     SignaturePass -> pure $ case snsTypePayload of-      Notification{} -> SNSMessage snsMessage+      Notification {} -> SNSMessage snsMessage       SubscriptionConfirmation x -> SNSSubscribe x       UnsubscribeConfirmation x -> SNSUnsubscribe x     SignatureFailed e -> throwE $ InvalidPayload e@@ -81,33 +90,37 @@ validateCertUrl certUrl = do   uri <- fromMaybeM (Left $ BadUri certUrlStr) $ parseURI certUrlStr   if uriScheme uri-      == validScheme-      && maybe "" uriRegName (uriAuthority uri)-      =~ validRegPattern+    == validScheme+    && maybe "" uriRegName (uriAuthority uri)+    =~ validRegPattern     then Right certUrlStr     else Left $ BadUri certUrlStr-  where certUrlStr = T.unpack certUrl+ where+  certUrlStr = T.unpack certUrl  unsignedSignature :: SNSPayload -> ByteString unsignedSignature SNSPayload {..} =-  encodeUtf8 $ mconcat $ (<> "\n") <$> catMaybes-    [ Just "Message"-    , Just snsMessage-    , Just "MessageId"-    , Just snsMessageId-    , "SubscribeURL" <$ mSubscribeUrl-    , mSubscribeUrl-    , "Subject" <$ mSubject-    , mSubject-    , Just "Timestamp"-    , Just snsTimestamp-    , "Token" <$ mToken-    , mToken-    , Just "TopicArn"-    , Just snsTopicArn-    , Just "Type"-    , Just snsType-    ]+  encodeUtf8+    $ mconcat+    $ (<> "\n")+    <$> catMaybes+      [ Just "Message"+      , Just snsMessage+      , Just "MessageId"+      , Just snsMessageId+      , "SubscribeURL" <$ mSubscribeUrl+      , mSubscribeUrl+      , "Subject" <$ mSubject+      , mSubject+      , Just "Timestamp"+      , Just snsTimestamp+      , "Token" <$ mToken+      , mToken+      , Just "TopicArn"+      , Just snsTopicArn+      , Just "Type"+      , Just snsType+      ]  where   (mSubject, mToken, mSubscribeUrl) = case snsTypePayload of     Notification x -> (snsSubject x, Nothing, Nothing)@@ -120,14 +133,15 @@   :: MonadIO m   => ValidSNSMessage   -> m (Either SNSNotificationValidationError Text)-handleSubscription = runExceptT . \case-  SNSMessage t -> pure t-  SNSSubscribe SNSSubscription {..} -> do-    response <- httpLbs $ parseRequest_ $ T.unpack snsSubscribeURL-    when (getResponseStatusCode response >= 300) $ do-      throwE BadSubscription-    throwE SubscribeMessageResponded-  SNSUnsubscribe{} -> throwE UnsubscribeMessage+handleSubscription =+  runExceptT . \case+    SNSMessage t -> pure t+    SNSSubscribe SNSSubscription {..} -> do+      response <- httpLbs $ parseRequest_ $ T.unpack snsSubscribeURL+      when (getResponseStatusCode response >= 300) $ do+        throwE BadSubscription+      throwE SubscribeMessageResponded+    SNSUnsubscribe {} -> throwE UnsubscribeMessage  data SNSNotificationValidationError   = BadPem String@@ -141,4 +155,4 @@   | UnsubscribeMessage   | SubscribeMessageResponded   deriving stock (Show, Eq)-  deriving anyclass Exception+  deriving anyclass (Exception)
tests/Amazon/SNS/Verify/TestPrelude.hs view
@@ -16,11 +16,12 @@ useCertServer :: IO () -> IO () useCertServer action = do   (setReady, whenReady) <- initReadyState-  race_ (whenReady action)-    $ runSettings (setBeforeMainLoop setReady . setPort 3000 $ defaultSettings)-    $ \req send -> if rawPathInfo req == "/404"-        then send $ responseLBS notFound404 [] ""-        else send $ responseFile ok200 [] "./tests/cert.pem" Nothing+  race_ (whenReady action) $+    runSettings (setBeforeMainLoop setReady . setPort 3000 $ defaultSettings) $+      \req send ->+        if rawPathInfo req == "/404"+          then send $ responseLBS notFound404 [] ""+          else send $ responseFile ok200 [] "./tests/cert.pem" Nothing  where   initReadyState = do     ready <- newEmptyMVar
tests/Amazon/SNS/Verify/ValidateSpec.hs view
@@ -6,137 +6,156 @@  import Amazon.SNS.Verify.Payload import Amazon.SNS.Verify.Validate-import Data.X509.Validation (SignatureFailure(..))+import Data.X509.Validation (SignatureFailure (..))  spec :: Spec spec = around_ useCertServer $ do   describe "validateSnsMessage" $ do     it "successfully validates an SNS notification" $ do       let message = "Some message"-      x <- validateSnsMessage $ SNSPayload-        { snsMessage = message-        , snsMessageId = "78d4d7a0-a3eb-5c4d-834f-8d5fa9813ab6"-        , snsTimestamp = "2022-05-18T14:52:26.952Z"-        , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"-        , snsType = "Notification"-        , snsSignatureVersion = "1"-        , snsSignature =-          "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="-        , snsSigningCertURL = cert-        , snsTypePayload = Notification $ SNSNotification-          { snsSubject =-            Just-              "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"-          }-        }+      x <-+        validateSnsMessage+          $ SNSPayload+            { snsMessage = message+            , snsMessageId = "78d4d7a0-a3eb-5c4d-834f-8d5fa9813ab6"+            , snsTimestamp = "2022-05-18T14:52:26.952Z"+            , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"+            , snsType = "Notification"+            , snsSignatureVersion = "1"+            , snsSignature =+                "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="+            , snsSigningCertURL = cert+            , snsTypePayload =+                Notification+                  $ SNSNotification+                    { snsSubject =+                        Just+                          "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"+                    }+            }       x `shouldBe` Right (SNSMessage message)      it "fails to validate a currupt SNS notification" $ do-      let-        go = validateSnsMessage $ SNSPayload-          { snsMessage = "Some message"-          , snsMessageId = "corrupt"-          , snsTimestamp = "2022-05-18T14:52:26.952Z"-          , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"-          , snsType = "Notification"-          , snsSignatureVersion = "1"-          , snsSignature =-            "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="-          , snsSigningCertURL = cert-          , snsTypePayload = Notification $ SNSNotification-            { snsSubject =-              Just-                "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"-            }-          }+      let go =+            validateSnsMessage+              $ SNSPayload+                { snsMessage = "Some message"+                , snsMessageId = "corrupt"+                , snsTimestamp = "2022-05-18T14:52:26.952Z"+                , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"+                , snsType = "Notification"+                , snsSignatureVersion = "1"+                , snsSignature =+                    "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="+                , snsSigningCertURL = cert+                , snsTypePayload =+                    Notification+                      $ SNSNotification+                        { snsSubject =+                            Just+                              "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"+                        }+                }       go `shouldReturn` Left (InvalidPayload SignatureInvalid)      it "fails to validate a bad PEM" $ do-      let-        go = validateSnsMessage $ SNSPayload-          { snsMessage = "Some message"-          , snsMessageId = "corrupt"-          , snsTimestamp = "2022-05-18T14:52:26.952Z"-          , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"-          , snsType = "Notification"-          , snsSignatureVersion = "1"-          , snsSignature =-            "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="-          , snsSigningCertURL = "http://localhost:3000/404"-          , snsTypePayload = Notification $ SNSNotification-            { snsSubject =-              Just-                "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"-            }-          }+      let go =+            validateSnsMessage+              $ SNSPayload+                { snsMessage = "Some message"+                , snsMessageId = "corrupt"+                , snsTimestamp = "2022-05-18T14:52:26.952Z"+                , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"+                , snsType = "Notification"+                , snsSignatureVersion = "1"+                , snsSignature =+                    "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="+                , snsSigningCertURL = "http://localhost:3000/404"+                , snsTypePayload =+                    Notification+                      $ SNSNotification+                        { snsSubject =+                            Just+                              "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"+                        }+                }       go `shouldReturn` Left (BadPem "Empty List")      it "fails to validate an unexpected url" $ do-      let-        go = validateSnsMessage $ SNSPayload-          { snsMessage = "Some message"-          , snsMessageId = "corrupt"-          , snsTimestamp = "2022-05-18T14:52:26.952Z"-          , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"-          , snsType = "Notification"-          , snsSignatureVersion = "1"-          , snsSignature =-            "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="-          , snsSigningCertURL = "http://attacker.com/evil.pem"-          , snsTypePayload = Notification $ SNSNotification-            { snsSubject =-              Just-                "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"-            }-          }+      let go =+            validateSnsMessage+              $ SNSPayload+                { snsMessage = "Some message"+                , snsMessageId = "corrupt"+                , snsTimestamp = "2022-05-18T14:52:26.952Z"+                , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"+                , snsType = "Notification"+                , snsSignatureVersion = "1"+                , snsSignature =+                    "Dg24trcOUiLjclt5JwyJS0JEOnEEbi6P30XS6KBxMCwzZ08a04UwjaFTW9Ae8xurhBS5YESz1fY28vTwvEmxh/20WmB3bWIDOMp9v5RI8XSZOvpMm+hdQJ43VqGhEDyAvRU6iCDLihDlZNc/sBCwl9X0H4kh/8vIElRif9gFBbYI94ZHGgqEV+Zc3gVKo9Udrl/MxNvMVadsO/+/oPVUeWibQr3xfGK95oc/ocuNAgi0MOxZmLVnibHu36KOTSvy2qSLonnRRFcbaauYZJ4js7oTq+1ujXNO72oPLaeG3pVJ2grqMc5z8tKQxFnSTE3es7wQarU/CLrbO8j0isbnWw=="+                , snsSigningCertURL = "http://attacker.com/evil.pem"+                , snsTypePayload =+                    Notification+                      $ SNSNotification+                        { snsSubject =+                            Just+                              "SynthesisTaskNotification { TaskId: 680a1f1b-f3ae-4474-aa8f-3b6dfe52e656, Status: COMPLETED }"+                        }+                }       go `shouldReturn` Left (BadUri "http://attacker.com/evil.pem")      it "successfully validates an SNS subscription" $ do       -- pendingWith "need valid subscription payload"       let-        message-          = "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:123456789012:MyTopic.\nTo confirm the subscription, visit the SubscribeURL included in this message."-        subscription = SNSSubscription-          { snsToken = "2336412f37..."-          , snsSubscribeURL =-            "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:123456789012:MyTopic&Token=2336412f37..."-          }-      x <- validateSnsMessage $ SNSPayload-        { snsMessage = message-        , snsMessageId = "165545c9-2a5c-472c-8df2-7ff2be2b3b1b"-        , snsTimestamp = "2012-04-26T20:45:04.751Z"-        , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"-        , snsType = "SubscriptionConfirmation"-        , snsSignatureVersion = "1"-        , snsSignature =-          "Jec/VlsopbiA2fCckj/IwTPjDbSuFkl2hNKL898sQuZcMeKeOLthYs7YlF+xLi+Ip6rG/X08GZKtCqpoiSgKW8D9PI6eHVM2JQa76sFJO5ZdPylrDH+URwBf28gT+1l/VYk4p3VK8RZo+3Wkn87HXwxTq1YoN390o5ncT34zaBDtLx2cUA8+JOnYjItmYjVXDhrEBF6xad/vIY8V2o5xyQOfEWLm71/Tcs3radzNoSj2xlLQyJKPOzV661fG6Xz1vVKfDVC03+Q4Pn67SmU1wWRRT1nDwPPzQlcDAiAGRjB1U/C5iHfLQFF3dKo4azylkrM2ReTCMm9KMyIWqjq5eg=="-        , snsSigningCertURL = cert-        , snsTypePayload = SubscriptionConfirmation subscription-        }+        message =+          "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:123456789012:MyTopic.\nTo confirm the subscription, visit the SubscribeURL included in this message."+        subscription =+          SNSSubscription+            { snsToken = "2336412f37..."+            , snsSubscribeURL =+                "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:123456789012:MyTopic&Token=2336412f37..."+            }+      x <-+        validateSnsMessage+          $ SNSPayload+            { snsMessage = message+            , snsMessageId = "165545c9-2a5c-472c-8df2-7ff2be2b3b1b"+            , snsTimestamp = "2012-04-26T20:45:04.751Z"+            , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"+            , snsType = "SubscriptionConfirmation"+            , snsSignatureVersion = "1"+            , snsSignature =+                "Jec/VlsopbiA2fCckj/IwTPjDbSuFkl2hNKL898sQuZcMeKeOLthYs7YlF+xLi+Ip6rG/X08GZKtCqpoiSgKW8D9PI6eHVM2JQa76sFJO5ZdPylrDH+URwBf28gT+1l/VYk4p3VK8RZo+3Wkn87HXwxTq1YoN390o5ncT34zaBDtLx2cUA8+JOnYjItmYjVXDhrEBF6xad/vIY8V2o5xyQOfEWLm71/Tcs3radzNoSj2xlLQyJKPOzV661fG6Xz1vVKfDVC03+Q4Pn67SmU1wWRRT1nDwPPzQlcDAiAGRjB1U/C5iHfLQFF3dKo4azylkrM2ReTCMm9KMyIWqjq5eg=="+            , snsSigningCertURL = cert+            , snsTypePayload = SubscriptionConfirmation subscription+            }       x `shouldBe` Right (SNSSubscribe subscription)      it "successfully validates an SNS unsubscribe" $ do       -- pendingWith "need valid subscription payload"       let-        message-          = "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:123456789012:MyTopic.\nTo confirm the subscription, visit the SubscribeURL included in this message."-        subscription = SNSSubscription-          { snsToken = "2336412f37..."-          , snsSubscribeURL =-            "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:123456789012:MyTopic&Token=2336412f37..."-          }-      x <- validateSnsMessage $ SNSPayload-        { snsMessage = message-        , snsMessageId = "165545c9-2a5c-472c-8df2-7ff2be2b3b1b"-        , snsTimestamp = "2012-04-26T20:45:04.751Z"-        , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"-        , snsType = "UnsubscribeConfirmation"-        , snsSignatureVersion = "1"-        , snsSignature =-          "fKtmZTE6xvGhbcCTchFPLmuhdoXI7hxWrE9qe1RjeLDecMaZGmqsn4rOrFDsteqot4ItLuJqvV7RtImGXrMa/JNnZdP71lG6FdrKTiGqZNrnxZZYbIuZMAsSQM4E8VaRwbxLXuPQY9IYFP4y9GfsdpDYx0tpbXOxGz/JFVQjTFpHY55BmV6Ec73g0X/eLSEdKfHtWg/gVf6W27ewa40jXvaa78VmcVXbPXIKwzGgSSSe9t6xxVe0kLjKXaDyJTl3rbZJZJgBLInbychWNq1vGHGZQhtCyxjKRfKIWNWDbHdM/fUBGUhuv089CblWpq8g/21HiJ9n+S3VSn0hCXB5hg=="-        , snsSigningCertURL = cert-        , snsTypePayload = UnsubscribeConfirmation subscription-        }+        message =+          "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:123456789012:MyTopic.\nTo confirm the subscription, visit the SubscribeURL included in this message."+        subscription =+          SNSSubscription+            { snsToken = "2336412f37..."+            , snsSubscribeURL =+                "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:123456789012:MyTopic&Token=2336412f37..."+            }+      x <-+        validateSnsMessage+          $ SNSPayload+            { snsMessage = message+            , snsMessageId = "165545c9-2a5c-472c-8df2-7ff2be2b3b1b"+            , snsTimestamp = "2012-04-26T20:45:04.751Z"+            , snsTopicArn = "arn:aws:sns:us-west-2:123456789012:MyTopic"+            , snsType = "UnsubscribeConfirmation"+            , snsSignatureVersion = "1"+            , snsSignature =+                "fKtmZTE6xvGhbcCTchFPLmuhdoXI7hxWrE9qe1RjeLDecMaZGmqsn4rOrFDsteqot4ItLuJqvV7RtImGXrMa/JNnZdP71lG6FdrKTiGqZNrnxZZYbIuZMAsSQM4E8VaRwbxLXuPQY9IYFP4y9GfsdpDYx0tpbXOxGz/JFVQjTFpHY55BmV6Ec73g0X/eLSEdKfHtWg/gVf6W27ewa40jXvaa78VmcVXbPXIKwzGgSSSe9t6xxVe0kLjKXaDyJTl3rbZJZJgBLInbychWNq1vGHGZQhtCyxjKRfKIWNWDbHdM/fUBGUhuv089CblWpq8g/21HiJ9n+S3VSn0hCXB5hg=="+            , snsSigningCertURL = cert+            , snsTypePayload = UnsubscribeConfirmation subscription+            }       x `shouldBe` Right (SNSUnsubscribe subscription)  cert :: Text
tests/Amazon/SNS/VerifySpec.hs view
@@ -13,8 +13,8 @@ spec = around_ useCertServer $ do   describe "verifySNSMessage" $ do     it "successfully validates an SNS notification" $ do-      let-        payload = [aesonQQ|+      let payload =+            [aesonQQ|           { Message: "Some message"           , MessageId: "78d4d7a0-a3eb-5c4d-834f-8d5fa9813ab6"           , Timestamp: "2022-05-18T14:52:26.952Z"@@ -31,8 +31,8 @@       x `shouldBe` "Some message"      it "successfully confirms a subscription" $ do-      let-        payload = [aesonQQ|+      let payload =+            [aesonQQ|           { Message: "Some message"           , MessageId: "78d4d7a0-a3eb-5c4d-834f-8d5fa9813ab6"           , Timestamp: "2022-05-18T14:52:26.952Z"@@ -48,7 +48,7 @@           |]        verifySNSMessage payload-        `shouldThrow` (\case-                        SubscribeMessageResponded -> True-                        _ -> False+        `shouldThrow` ( \case+                          SubscribeMessageResponded -> True+                          _ -> False                       )