{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} -- | -- Module : Credentials.Types -- Copyright : (c) 2015-2016 Brendan Hay -- License : Mozilla Public License, v. 2.0. -- Maintainer : Brendan Hay -- Stability : provisional -- Portability : non-portable (GHC extensions) -- module Credentials.Types where import Control.Exception.Lens (exception) import Control.Lens (Prism', prism) import Control.Monad.Catch (Exception, SomeException) import Crypto.Hash (SHA256) import Crypto.MAC.HMAC (HMAC) import Data.ByteString (ByteString) import Data.HashMap.Strict (HashMap) import Data.Text (Text) import Data.Typeable (Typeable) import Network.AWS.Data -- | The KMS master key identifier. newtype KeyId = KeyId Text deriving (Eq, Ord, Show, FromText, ToText, ToByteString, ToLog) -- | The default KMS master key alias. -- -- /Value:/ @alias\/credentials@ defaultKeyId :: KeyId defaultKeyId = KeyId "alias/credentials" -- | A shared/readable name for a secret. newtype Name = Name Text deriving (Eq, Ord, Show, FromText, ToText, ToByteString, ToLog) -- | An opaque, non-monotonic revision number. newtype Revision = Revision ByteString deriving (Eq, Ord, Show, FromText, ToText, ToByteString, ToLog) -- | A KMS encryption context. -- -- /See:/ KMS -- documentation for more information. newtype Context = Context { fromContext :: HashMap Text Text } deriving (Eq, Show, Monoid) -- | The encryption parameters required to perform decryption. data Encrypted = Encrypted { wrappedKey :: !ByteString -- ^ The wrapped (encrypted) data encryption key. , ciphertext :: !ByteString -- ^ The encrypted ciphertext. , digest :: !(HMAC SHA256) -- ^ HMAC SHA256 digest of the ciphertext. } -- | Denotes idempotency of an action. That is, whether an action resulted -- in any setup being performed. data Setup = Created | Exists deriving (Eq, Show) instance ToText Setup where toText = \case Created -> "created" Exists -> "exists" instance ToLog Setup where build = build . toText data CredentialError = MasterKeyMissing KeyId (Maybe Text) -- ^ The specified master key id doesn't exist. | IntegrityFailure Name ByteString ByteString -- ^ The computed HMAC doesn't matched the stored HMAC. | EncryptFailure Context Name Text -- ^ Failure occured during local encryption. | DecryptFailure Context Name Text -- ^ Failure occured during local decryption. | StorageMissing Text -- ^ Storage doesn't exist, or has gone on holiday. | StorageFailure Text -- ^ Some storage pre-condition wasn't met. -- For example: DynamoDB column size exceeded. | FieldMissing Text [Text] -- ^ Missing field from the storage engine. | FieldInvalid Text String -- ^ Unable to parse field from the storage engine. | SecretMissing Name (Maybe Revision) Text -- ^ Secret with the specified name cannot found. | OptimisticLockFailure Name Revision Text -- ^ Attempting to insert a revision that already exists. deriving (Eq, Show, Typeable) instance Exception CredentialError class AsCredentialError a where _CredentialError :: Prism' a CredentialError _MasterKeyMissing :: Prism' a (KeyId, Maybe Text) _IntegrityFailure :: Prism' a (Name, ByteString, ByteString) _EncryptFailure :: Prism' a (Context, Name, Text) _DecryptFailure :: Prism' a (Context, Name, Text) _StorageMissing :: Prism' a Text _StorageFailure :: Prism' a Text _FieldMissing :: Prism' a (Text, [Text]) _FieldInvalid :: Prism' a (Text, String) _SecretMissing :: Prism' a (Name, Maybe Revision, Text) _OptimisticLockFailure :: Prism' a (Name, Revision, Text) _MasterKeyMissing = (.) _CredentialError _MasterKeyMissing _IntegrityFailure = (.) _CredentialError _IntegrityFailure _EncryptFailure = (.) _CredentialError _EncryptFailure _DecryptFailure = (.) _CredentialError _DecryptFailure _StorageMissing = (.) _CredentialError _StorageMissing _StorageFailure = (.) _CredentialError _StorageFailure _FieldMissing = (.) _CredentialError _FieldMissing _FieldInvalid = (.) _CredentialError _FieldInvalid _SecretMissing = (.) _CredentialError _SecretMissing _OptimisticLockFailure = (.) _CredentialError _OptimisticLockFailure instance AsCredentialError CredentialError where _CredentialError = id _MasterKeyMissing = prism (\(key, msg) -> MasterKeyMissing key msg) (\case MasterKeyMissing key msg -> Right (key, msg) x -> Left x) _IntegrityFailure = prism (\(name, a, b) -> IntegrityFailure name a b) (\case IntegrityFailure name a b -> Right (name, a, b) x -> Left x) _EncryptFailure = prism (\(ctx, name, msg) -> EncryptFailure ctx name msg) (\case EncryptFailure ctx name msg -> Right (ctx, name, msg) x -> Left x) _DecryptFailure = prism (\(ctx, name, msg) -> DecryptFailure ctx name msg) (\case DecryptFailure ctx name msg -> Right (ctx, name, msg) x -> Left x) _StorageMissing = prism StorageMissing (\case StorageMissing msg -> Right msg x -> Left x) _StorageFailure = prism StorageFailure (\case StorageFailure msg -> Right msg x -> Left x) _FieldMissing = prism (\(field, found) -> FieldMissing field found) (\case FieldMissing field found -> Right (field, found) x -> Left x) _FieldInvalid = prism (\(field, msg) -> FieldInvalid field msg) (\case FieldInvalid field msg -> Right (field, msg) x -> Left x) _SecretMissing = prism (\(name, rev, msg) -> SecretMissing name rev msg) (\case SecretMissing name rev msg -> Right (name, rev, msg) x -> Left x) _OptimisticLockFailure = prism (\(name, rev, msg) -> OptimisticLockFailure name rev msg) (\case OptimisticLockFailure name rev msg -> Right (name, rev, msg) x -> Left x) instance AsCredentialError SomeException where _CredentialError = exception