1 {-# LANGUAGE OverloadedStrings #-}
3 Module : Crypto.Macaroon.Internal
4 Copyright : (c) 2015 Julien Tanguy
7 Maintainer : julien.tanguy@jhome.fr
8 Stability : experimental
12 Internal representation of a macaroon
14 module Crypto.Macaroon.Internal where
17 import Control.DeepSeq
20 import qualified Data.ByteString as BS
21 import qualified Data.ByteString.Base64 as B64
22 import qualified Data.ByteString.Char8 as B8
26 -- |Type alias for Macaroons and Caveat keys and identifiers
27 type Key = BS.ByteString
29 -- |Type alias for Macaroons and Caveat locations
30 type Location = BS.ByteString
32 -- |Type alias for Macaroons signatures
33 type Sig = BS.ByteString
35 -- | Main structure of a macaroon
36 data Macaroon = MkMacaroon { location :: Location
39 -- ^ Macaroon Identifier
43 -- ^ Macaroon HMAC signature
46 -- | Constant-time Eq instance
47 instance Eq Macaroon where
48 (MkMacaroon l1 i1 c1 s1) == (MkMacaroon l2 i2 c2 s2) =
49 (l1 `constEqBytes` l2) &&!
50 (i1 `constEqBytes` i2) &&!
52 (s1 `constEqBytes` s2)
55 -- | show instance conforming to the @inspect@ "specification"
56 instance Show Macaroon where
57 -- We use intercalate because unlines would add a trailing newline
58 show (MkMacaroon l i c s) = intercalate "\n" [
59 "location " ++ B8.unpack l
60 , "identifier " ++ B8.unpack i
61 , intercalate "\n" (map show c)
62 , "signature " ++ B8.unpack (hex s)
65 -- | NFData instance for use in the benchmark
66 instance NFData Macaroon where
67 rnf (MkMacaroon loc ident cavs sig) = rnf loc `seq` rnf ident `seq` rnf cavs `seq` rnf sig
71 data Caveat = MkCaveat { cid :: Key
72 -- ^ Caveat identifier
74 -- ^ Caveat verification key identifier
76 -- ^ Caveat target location
79 -- | Constant-time Eq instance
80 instance Eq Caveat where
81 (MkCaveat c1 v1 l1) == (MkCaveat c2 v2 l2) =
82 (c1 `constEqBytes` c2) &&!
83 (v1 `constEqBytes` v2) &&!
84 (l1 `constEqBytes` l2)
86 -- | show instance conforming to the @inspect@ "specification"
87 instance Show Caveat where
88 show (MkCaveat c v l) | v == BS.empty = "cid " ++ B8.unpack c
89 | otherwise = unlines [ "cid " ++ B8.unpack c
90 , "vid " ++ B8.unpack v
91 , "cl " ++ B8.unpack l
95 -- | NFData instance for use in the benchmark
96 instance NFData Caveat where
97 rnf (MkCaveat cid vid cl) = rnf cid `seq` rnf vid `seq` rnf cl
99 -- | Primitive to add a First or Third party caveat to a macaroon
100 -- For internal use only
101 addCaveat :: Location
106 addCaveat loc cid vid m = m { caveats = cavs ++ [cav'], signature = sig}
109 cav' = MkCaveat cid vid loc
110 sig = toBytes (hmac (signature m) (BS.append vid cid) :: HMAC SHA256)
112 -- | Utility non-short circuiting '&&' function.
113 (&&!) :: Bool -> Bool -> Bool
115 True &&! False = False
116 False &&! True = False
117 False &&! False = False