packages feed

github-webhook-handler 0.0.4 → 0.0.5

raw patch · 2 files changed

+25/−16 lines, 2 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- GitHub.WebHook.Handler: hAction :: Handler m -> Either Error (UUID, Payload) -> m ()
- GitHub.WebHook.Handler: hBody :: Handler m -> m ByteString
- GitHub.WebHook.Handler: hHeader :: Handler m -> ByteString -> m (Maybe ByteString)
- GitHub.WebHook.Handler: hSecretKey :: Handler m -> Maybe String
+ GitHub.WebHook.Handler: [hAction] :: Handler m -> Either Error (UUID, Payload) -> m ()
+ GitHub.WebHook.Handler: [hBody] :: Handler m -> m ByteString
+ GitHub.WebHook.Handler: [hHeader] :: Handler m -> ByteString -> m (Maybe ByteString)
+ GitHub.WebHook.Handler: [hSecretKeys] :: Handler m -> [String]
- GitHub.WebHook.Handler: Handler :: Maybe String -> m ByteString -> (ByteString -> m (Maybe ByteString)) -> (Either Error (UUID, Payload) -> m ()) -> Handler m
+ GitHub.WebHook.Handler: Handler :: [String] -> m ByteString -> (ByteString -> m (Maybe ByteString)) -> (Either Error (UUID, Payload) -> m ()) -> Handler m

Files

github-webhook-handler.cabal view
@@ -1,5 +1,5 @@ name:                github-webhook-handler-version:             0.0.4+version:             0.0.5  synopsis:            GitHub WebHook Handler description:
src/GitHub/WebHook/Handler.hs view
@@ -14,11 +14,11 @@  import           Data.Monoid -import           Data.Text+import           Data.Text hiding (any) import qualified Data.Text as T import           Data.Text.Encoding -import           Data.ByteString+import           Data.ByteString       hiding (any) import qualified Data.ByteString.Char8 as BC8  import           Data.UUID@@ -28,8 +28,12 @@   data Handler m = Handler-    { hSecretKey :: Maybe String-      -- ^ Optional key which is used to authenticate the incoming request.+    { hSecretKeys :: [String]+      -- ^ Secret keys which are used to authenticate the incoming request.+      -- If the list is empty then no authentication is required. The handler+      -- tries each key until it finds one which works. This makes it easier+      -- to rotate keys because you can have multiple ones active at any given+      -- point in time.      , hBody :: m ByteString       -- ^ Action which is used to read the request body.@@ -69,6 +73,11 @@ toParseError = Left . ParseError . T.pack  +verifySecretKey :: ByteString -> ByteString -> String -> Bool+verifySecretKey rawBody sig key = sig == ("sha1=" <> digestToHexByteString+    (hmacGetDigest (hmac (BC8.pack key) rawBody :: HMAC SHA1)))++ runHandler :: Monad m => Handler m -> m () runHandler h = do     mbDelivery <- return . (fromASCIIBytes =<<) =<< hHeader h "X-GitHub-Delivery"@@ -77,24 +86,24 @@         rawBody     <- hBody h         mbSignature <- hHeader h "X-Hub-Signature" -        authenticatedBody <- return $ case (hSecretKey h, mbSignature) of+        authenticatedBody <- return $ case (hSecretKeys h, mbSignature) of              -- No secret key and no signature. Pass along the body unverified.-            (Nothing, Nothing) -> Right rawBody+            ([], Nothing) -> Right rawBody -            -- Signature is available but no secret key to verify it. This is+            -- Signature is available but no secret keys to verify it. This is             -- not a fatal error, we can still process the event.-            (Nothing, Just _) -> Right rawBody+            ([], Just _) -> Right rawBody -            -- Secret token is available but the request is not signed. Reject+            -- Secret keys are available but the request is not signed. Reject             -- the request.-            (Just _, Nothing) -> Left UnsignedRequest+            (_, Nothing) -> Left UnsignedRequest -            -- Both the signature and secret token are available. Verify the-            -- signature and reject the request if that fails.-            (Just sc, Just sig) -> do-                let mac = hmac (BC8.pack sc) rawBody :: HMAC SHA1-                if sig == ("sha1=" <> digestToHexByteString (hmacGetDigest mac))+            -- Both the signature and secret keys are available. Verify the+            -- signature with the first key which works, otherwise reject the+            -- request.+            (secretKeys, Just sig) -> do+                if any (verifySecretKey rawBody sig) secretKeys                     then Right rawBody                     else Left InvalidSignature