packages feed

github-webhook-handler (empty) → 0.0.1

raw patch · 4 files changed

+149/−0 lines, 4 filesdep +aesondep +basedep +bytestringsetup-changed

Dependencies added: aeson, base, bytestring, cryptohash, github-types, text, transformers, vector

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Tomas Carnecky++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ github-webhook-handler.cabal view
@@ -0,0 +1,37 @@+name:                github-webhook-handler+version:             0.0.1++synopsis:            GitHub WebHook Handler+description:+  Generic definition of a GitHub Webhook Handler. Specialized version for Snap+  can be found in the 'github-webhook-handler-snap' package.++license:             MIT+license-file:        LICENSE++author:              Tomas Carnecky+maintainer:          tomas.carnecky@gmail.com++category:            GitHub++build-type:          Simple+cabal-version:       >=1.10+++library+  hs-source-dirs:      src+  default-language:    Haskell2010+  ghc-options:         -Wall++  build-depends:+     base >=4.8 && <4.9+   , bytestring+   , github-types+   , transformers+   , aeson+   , text+   , vector+   , cryptohash++  exposed-modules:+     GitHub.WebHook.Handler
+ src/GitHub/WebHook/Handler.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE OverloadedStrings #-}++module GitHub.WebHook.Handler+  ( Handler(..)+  , Error(..)+  , runHandler+  ) where+++import           Crypto.Hash++import           Data.Aeson (eitherDecodeStrict')+import           Data.Aeson.Types (parseEither)++import           Data.Monoid++import           Data.Text+import qualified Data.Text as T+import           Data.Text.Encoding++import           Data.ByteString+import qualified Data.ByteString.Char8 as BC8++import           GitHub.Types++++data Handler m = Handler+    { hSecretKey :: Maybe String+      -- ^ Optional key which is used to authenticate the incoming request.++    , hBody :: m ByteString+      -- ^ Action which is used to read the request body.++    , hHeader :: ByteString -> m (Maybe ByteString)+      -- ^ Action which is used to retrieve a particular header from the+      -- request.++    , hAction :: Either Error Event -> m ()+      -- ^ Action which is executed once we've processed all the information+      -- in the request.+    }+++data Error+    = InvalidRequest+    | ParseError !Text+    | UnsignedRequest+    | InvalidSignature++toParseError :: String -> Either Error Event+toParseError = Left . ParseError . T.pack++runHandler :: Monad m => Handler m -> m ()+runHandler h = do+    res <- do+        rawBody     <- hBody h+        mbSignature <- hHeader h "X-Hub-Signature"++        authenticatedBody <- return $ case (hSecretKey h, mbSignature) of++            -- No secret key and no signature. Pass along the body unverified.+            (Nothing, Nothing) -> Right rawBody++            -- Signature is available but no secret key to verify it. This is+            -- not a fatal error, we can still process the event.+            (Nothing, Just _) -> Right rawBody++            -- Secret token is available but the request is not signed. Reject+            -- the request.+            (Just _, 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))+                    then Right rawBody+                    else Left InvalidSignature++        mbEventName <- hHeader h "X-GitHub-Event"+        return $ do+            eventName <- maybe (Left InvalidRequest) Right mbEventName+            body      <- authenticatedBody+            case eitherDecodeStrict' body of+                Left e -> toParseError e+                Right value -> either toParseError Right $+                    parseEither (eventParser $ decodeUtf8 eventName) value++    hAction h res