servant-hmac-auth 0.1.3 → 0.1.4
raw patch · 4 files changed
+74/−14 lines, 4 filesdep +filepathdep +hspecdep +hspec-goldendep ~base64-bytestringdep ~servantdep ~servant-clientPVP ok
version bump matches the API change (PVP)
Dependencies added: filepath, hspec, hspec-golden, text
Dependency ranges changed: base64-bytestring, servant, servant-client, servant-client-core, servant-server
API changes (from Hackage documentation)
Files
- servant-hmac-auth.cabal +16/−7
- src/Servant/Auth/Hmac/Client.hs +12/−4
- test/Servant/Auth/Hmac/CryptoSpec.hs +45/−0
- test/Spec.hs +1/−3
servant-hmac-auth.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: servant-hmac-auth-version: 0.1.3+version: 0.1.4 synopsis: Servant authentication with HMAC description: Servant authentication with HMAC. See README.md for usage example. homepage: https://github.com/holmusk/servant-hmac-auth@@ -15,7 +15,8 @@ extra-source-files: README.md , CHANGELOG.md tested-with: GHC == 8.6.5- GHC == 8.8.3+ GHC == 8.8.4+ GHC == 8.10.7 source-repository head type: git@@ -64,7 +65,7 @@ Servant.Auth.Hmac.Client Servant.Auth.Hmac.Server - build-depends: base64-bytestring ^>= 1.0+ build-depends: base64-bytestring >= 1.0 && <= 2 , binary ^>= 0.8 , bytestring ^>= 0.10 , case-insensitive ^>= 1.2@@ -74,10 +75,10 @@ , http-client >= 0.6.4 && < 0.8 , memory >= 0.15 && < 0.17 , mtl ^>= 2.2.2- , servant ^>= 0.18- , servant-client ^>= 0.18- , servant-client-core ^>= 0.18- , servant-server ^>= 0.18+ , servant ^>= 0.18 || ^>= 0.19+ , servant-client ^>= 0.18 || ^>= 0.19+ , servant-client-core ^>= 0.18 || ^>= 0.19+ , servant-server ^>= 0.18 || ^>= 0.19 , transformers ^>= 0.5 , wai ^>= 3.2.2.1 @@ -88,3 +89,11 @@ main-is: Spec.hs ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: servant-hmac-auth+ , case-insensitive ^>= 1.2+ , filepath+ , hspec+ , hspec-golden ^>= 0.2+ , http-types ^>= 0.12+ , text+ other-modules: Servant.Auth.Hmac.CryptoSpec+ build-tool-depends: hspec-discover:hspec-discover == 2.*
src/Servant/Auth/Hmac/Client.hs view
@@ -20,10 +20,12 @@ import Control.Monad.Reader (MonadReader (..), ReaderT, asks, runReaderT) import Control.Monad.Trans.Class (lift) import Data.ByteString (ByteString)+import Data.CaseInsensitive (mk) import Data.Foldable (toList) import Data.List (sort) import Data.Proxy (Proxy (..)) import Data.Sequence (fromList, (<|))+import Data.String (fromString) import Servant.Client (BaseUrl, Client, ClientEnv (baseUrl), ClientError, ClientM, HasClient, runClientM) import Servant.Client.Core (RunClient (..), clientIn)@@ -109,11 +111,11 @@ { rpMethod = Client.method req , rpContent = "" -- toBsBody $ Client.requestBody req , rpHeaders = keepWhitelistedHeaders- $ ("Host", host)+ $ ("Host", hostAndPort) : ("Accept-Encoding", "gzip") : Client.requestHeaders req - , rpRawUrl = host <> Client.path req <> Client.queryString req+ , rpRawUrl = hostAndPort <> Client.path req <> Client.queryString req } where req :: Client.Request@@ -122,8 +124,14 @@ fromList $ sort $ toList $ Servant.requestQueryString sreq } - host :: ByteString- host = Client.host req+ hostAndPort :: ByteString+ hostAndPort = case lookup (mk "Host") (Client.requestHeaders req) of+ Just hp -> hp+ Nothing ->+ case (Client.secure req, Client.port req) of+ (True, 443) -> Client.host req+ (False, 80) -> Client.host req+ (_, p) -> Client.host req <> ":" <> fromString (show p) -- toBsBody :: RequestBody -> ByteString -- toBsBody (RequestBodyBS bs) = bs
+ test/Servant/Auth/Hmac/CryptoSpec.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE TemplateHaskellQuotes #-}++module Servant.Auth.Hmac.CryptoSpec (spec) where++import Data.CaseInsensitive+import Data.Text (Text)+import qualified Data.Text as Text+import qualified Data.Text.Encoding as TE+import qualified Data.Text.IO as TIO+import Network.HTTP.Types+import Servant.Auth.Hmac.Crypto (RequestPayload (..), SecretKey (..), Signature (..), requestSignature, signSHA256)+import System.FilePath+import Test.Hspec+import Test.Hspec.Golden++goldenTest :: String -> Text -> Golden Text+goldenTest name actualOutput =+ Golden+ { output = actualOutput+ , encodePretty = Text.unpack+ , writeToFile = TIO.writeFile+ , readFromFile = TIO.readFile+ , goldenFile = ".golden" </> name </> "golden"+ , actualFile = Just (".golden" </> name </> "actual")+ , failFirstTime = False+ }++sha256Scenarios :: [(SecretKey, RequestPayload)]+sha256Scenarios =+ [ (SecretKey "Some-s3cr3t", RequestPayload methodGet "" [(mk "Host", "my-server.local")] "my-server.local/test")+ , (SecretKey "s3cret2!", RequestPayload methodPost "This is a text content." [(mk "Host", "www.haskell.server"), (mk "Authentication", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==")] "www.haskell.server/test")+ , (SecretKey "123456789abcdef", RequestPayload methodPatch "\00HellowORLD" [(mk "Host", "files.myrepository.org"), (mk "Accept-Encoding", "gzip")] "files.myrepository.org/files/4601237722")+ ]++formatResponse :: [Signature] -> Text+formatResponse = Text.unlines . fmap (TE.decodeLatin1 . unSignature)++spec :: Spec+spec =+ describe "requestSignature" $+ context "when using SHA256 for signature" $+ it "should compute the request's signature" $+ let signatures = uncurry (requestSignature signSHA256) <$> sha256Scenarios+ actualOutput = formatResponse signatures+ in goldenTest (show 'requestSignature) actualOutput
test/Spec.hs view
@@ -1,3 +1,1 @@-main :: IO ()-main = putStrLn ("Test suite not yet implemented" :: String)-+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}