module Aws.Signature
where
import Aws.Credentials
import Aws.Query
import Data.Time
import qualified Crypto.Classes as Crypto
import qualified Crypto.HMAC as HMAC
import qualified Crypto.Hash.SHA1 as SHA1
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as Base64
import qualified Data.Serialize as Serialize
data TimeInfo
= Timestamp
| ExpiresAt { fromExpiresAt :: UTCTime }
| ExpiresIn { fromExpiresIn :: NominalDiffTime }
deriving (Show)
data AbsoluteTimeInfo
= AbsoluteTimestamp { fromAbsoluteTimestamp :: UTCTime }
| AbsoluteExpires { fromAbsoluteExpires :: UTCTime }
deriving (Show)
fromAbsoluteTimeInfo :: AbsoluteTimeInfo -> UTCTime
fromAbsoluteTimeInfo (AbsoluteTimestamp time) = time
fromAbsoluteTimeInfo (AbsoluteExpires time) = time
makeAbsoluteTimeInfo :: TimeInfo -> UTCTime -> AbsoluteTimeInfo
makeAbsoluteTimeInfo Timestamp now = AbsoluteTimestamp now
makeAbsoluteTimeInfo (ExpiresAt t) _ = AbsoluteExpires t
makeAbsoluteTimeInfo (ExpiresIn s) now = AbsoluteExpires $ addUTCTime s now
data SignatureData
= SignatureData {
signatureTimeInfo :: AbsoluteTimeInfo
, signatureTime :: UTCTime
, signatureCredentials :: Credentials
}
signatureData :: TimeInfo -> Credentials -> IO SignatureData
signatureData rti cr = do
now <- getCurrentTime
let ti = makeAbsoluteTimeInfo rti now
return SignatureData { signatureTimeInfo = ti, signatureTime = now, signatureCredentials = cr }
class SignQuery r where
type Info r :: *
signQuery :: r -> Info r -> SignatureData -> SignedQuery
data AuthorizationHash
= HmacSHA1
| HmacSHA256
deriving (Show)
amzHash :: AuthorizationHash -> B.ByteString
amzHash HmacSHA1 = "HmacSHA1"
amzHash HmacSHA256 = "HmacSHA256"
signature :: Credentials -> AuthorizationHash -> B.ByteString -> B.ByteString
signature cr ah input = Base64.encode sig
where
sig = case ah of
HmacSHA1 -> computeSig (undefined :: SHA1.SHA1)
HmacSHA256 -> computeSig (undefined :: SHA256.SHA256)
computeSig :: Crypto.Hash c d => d -> B.ByteString
computeSig t = Serialize.encode (HMAC.hmac' key input `asTypeOf` t)
key :: HMAC.MacKey c d
key = HMAC.MacKey (secretAccessKey cr)