]> git.immae.eu Git - github/fretlink/hmacaroons.git/blame_incremental - src/Crypto/Macaroon/Verifier/Internal.hs
Merge travis config from master
[github/fretlink/hmacaroons.git] / src / Crypto / Macaroon / Verifier / Internal.hs
... / ...
CommitLineData
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE RankNTypes #-}
3{-|
4Module : Crypto.Macaroon.Verifier.Internal
5Copyright : (c) 2015 Julien Tanguy
6License : BSD3
7
8Maintainer : julien.tanguy@jhome.fr
9Stability : experimental
10Portability : portable
11
12
13
14-}
15module Crypto.Macaroon.Verifier.Internal where
16
17import Control.Monad
18import Control.Monad.IO.Class
19import Crypto.Hash
20import Data.Bool
21import Data.Byteable
22import qualified Data.ByteString as BS
23import Data.Either
24import Data.Either.Validation
25import Data.Foldable
26import Data.Maybe
27import Data.Monoid
28
29import Crypto.Macaroon.Internal
30
31-- | Type representing different validation errors.
32-- Only 'ParseError' and 'ValidatorError' are exported, 'SigMismatch' and
33-- 'NoVerifier' are used internally and should not be used by the user
34data ValidationError = SigMismatch -- ^ Signatures do not match
35 | NoVerifier -- ^ No verifier can handle a given caveat
36 | ParseError String -- ^ A verifier had a parse error
37 | ValidatorError String -- ^ A verifier failed
38 deriving (Show,Eq)
39
40-- | The 'Monoid' instance is written so 'SigMismatch' is an annihilator,
41-- and 'NoVerifier' is the identity element
42instance Monoid ValidationError where
43 mempty = NoVerifier
44 NoVerifier `mappend` e = e
45 e `mappend` NoVerifier = e
46 SigMismatch `mappend` _ = SigMismatch
47 _ `mappend` SigMismatch = SigMismatch
48 (ValidatorError e) `mappend` (ParseError _) = ValidatorError e
49 (ParseError _) `mappend` (ValidatorError e) = ValidatorError e
50
51-- | Check that the given macaroon has a correct signature
52verifySig :: Key -> Macaroon -> Either ValidationError Macaroon
53verifySig k m = bool (Left SigMismatch) (Right m) $
54 signature m == foldl' hash (toBytes (hmac derivedKey (identifier m) :: HMAC SHA256)) (caveats m)
55 where
56 hash s c = toBytes (hmac s (vid c `BS.append` cid c) :: HMAC SHA256)
57 derivedKey = toBytes (hmac "macaroons-key-generator" k :: HMAC SHA256)
58
59-- | Given a list of verifiers, verify each caveat of the given macaroon
60verifyCavs :: MonadIO m
61 => [Caveat -> m (Maybe (Either ValidationError ()))]
62 -> Macaroon
63 -> m (Either ValidationError Macaroon)
64verifyCavs verifiers m = gatherEithers <$> mapM validateCaveat (caveats m)
65 where
66 {-
67 - validateCaveat :: Caveat -> m (Validation String Caveat)
68 - We can use fromJust here safely since we use a `Just Failure` as a
69 - starting value for the foldM. We are guaranteed to have a `Just something`
70 - from it.
71 -}
72 validateCaveat c = fmap (const c) . fromJust <$> foldM (\res v -> mappend res . fmap eitherToValidation <$> v c) (defErr c) verifiers
73 -- defErr :: Caveat -> Maybe (Validation String Caveat)
74 defErr c = Just $ Failure NoVerifier
75 -- gatherEithers :: [Validation String Caveat] -> Either String Caveat
76 gatherEithers vs = case partitionEithers . map validationToEither $ vs of
77 ([],_) -> Right m
78 (errs,_) -> Left (mconcat errs)