{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, TypeApplications #-} -- | -- Example usage: -- -- > {-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-} -- > -- > import Network.AWS.CloudFront.SignedCookies -- > -- > import qualified Data.Text.IO -- > -- > main :: IO () -- > main = do -- > -- > -- Construct an IAM policy that expires three days from now -- > policy :: Policy <- simplePolicy -- > (Resource "https://example.com/secrets/*") -- > (Lifespan (3 * nominalDay)) -- > -- > -- Parse the .pem file to get the private key -- > key :: PrivateKey <- readPrivateKeyPemFile -- > (PemFilePath "./pk-APKAIATXN3RCIOVT5WRQ.pem") -- > -- > -- Construct signed cookies -- > cookies :: CookiesText <- createSignedCookies -- > (KeyPairId "APKAIATXN3RCIOVT5WRQ") key policy -- > -- > Data.Text.IO.putStrLn (renderCookiesText cookies) -- -- Output: -- -- > Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc29... -- > Cookie: CloudFront-Signature=wMN6V3Okxk7sdSPZeebMh-wo... -- > Cookie: CloudFront-Key-Pair-Id=APKAIATXN3RCIOVT5WRQ -- -- You can see a very similar example in action in the -- "Network.AWS.CloudFront.SignedCookies.CLI" module. module Network.AWS.CloudFront.SignedCookies ( -- * Creating signed cookies createSignedCookies -- ** Defining a CloudFront policy , simplePolicy , Policy (..) , Resource (..) , Lifespan (..) , StartTime (..) , EndTime (..) , IpAddress (..) -- ** Getting your private key , readPrivateKeyPemFile , PemFilePath (..) , KeyPairId (..) , PrivateKey -- * Policy JSON , policyJSON , jsonTextPolicy , jsonValPolicy -- * Reading cookies , cookiePolicy -- * Miscellaneous -- ** Cookies , CookiesText , renderCookiesText , PolicyCookie (..) , SignatureCookie (..) -- ** Time , NominalDiffTime , POSIXTime , nominalDay , getPOSIXTime -- ** Text , Text ) where import Network.AWS.CloudFront.SignedCookies.Crypto import Network.AWS.CloudFront.SignedCookies.Encoding import Network.AWS.CloudFront.SignedCookies.Policy import Network.AWS.CloudFront.SignedCookies.Types -- aeson import qualified Data.Aeson as A -- base import Control.Monad ((>=>)) import Data.Coerce (coerce) import Data.Semigroup ((<>)) -- bytestring import qualified Data.ByteString.Lazy as LBS -- text import qualified Data.Text as Text -- time import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Time.Clock (nominalDay) createSignedCookies :: KeyPairId -- ^ A CloudFront key pair ID, which must be associated with a -- trusted signer in the CloudFront distribution that you -- specify in the 'policyResource'. -> PrivateKey -- ^ The private key associated with the 'KeyPairId'. See -- 'readPrivateKeyPemFile' for how to read this key from a -- @.pem@ file you downloaded from AWS. -> Policy -- ^ The policy specifies what resource is being granted, for what -- time period, and to what IP addresses. Construct a policy -- using the 'Policy' constructor or with the 'simplePolicy' -- function. -> IO CookiesText createSignedCookies kpid key policy = do let policyBS :: ByteString = policyJSON policy sigBS <- sign key policyBS pure [ ( "CloudFront-Policy" , base64Encode policyBS ) , ( "CloudFront-Signature" , base64Encode sigBS ) , ( "CloudFront-Key-Pair-Id" , coerce @KeyPairId @Text kpid ) ] -- | Format a list of cookies as HTTP request headers. renderCookiesText :: CookiesText -> Text renderCookiesText = Text.unlines . map (\(k, v) -> "Cookie: " <> k <> "=" <> v) -- | Parse the text value of a @CloudFront-Policy@ cookie into a 'Policy' -- value, producing 'Left' with an error message if parsing fails. cookiePolicy :: PolicyCookie -> Either String Policy cookiePolicy = (base64Decode . coerce @PolicyCookie @Text) >=> (A.eitherDecode' . LBS.fromStrict) >=> jsonValPolicy