-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Extensible interface to Web APIs
--   
--   <a>goggles</a> helps with exchanging data with APIs that require
--   authentication. In particular, it handles the details of expiring
--   session tokens, so the user does not have to implement this logic in
--   her program.
@package goggles
@version 0.3.2

module Network.Goggles.Auth

-- | send a POST request over HTTPS to a given URI that will return a
--   OAuth2Token
requestOAuth2Token :: (MonadHttp m, MonadThrow m) => Url scheme -> [(Text, Text)] -> Option scheme -> m OAuth2Token
data OAuth2Token
OAuth2Token :: Int -> Text -> Maybe Text -> OAuth2Token
[oaTokenExpirySeconds] :: OAuth2Token -> Int
[oaTokenString] :: OAuth2Token -> Text
[oaTokenType] :: OAuth2Token -> Maybe Text
data OAuth2TokenUTC
OAuth2TokenUTC :: UTCTime -> Text -> Maybe Text -> OAuth2TokenUTC
[oauTokenExpiry] :: OAuth2TokenUTC -> UTCTime
[oauTokenString] :: OAuth2TokenUTC -> Text
[oauTokenType] :: OAuth2TokenUTC -> Maybe Text
mkOAuth2TokenUTC :: (MonadIO m, Integral t) => t -> OAuth2Token -> m OAuth2TokenUTC


-- | <h1>Introduction</h1>
--   
--   This library aims to abstract away (part of) the bookkeeping related
--   to exchanging data with web APIs.
--   
--   In particular, <tt>goggles</tt> can take care of automatically
--   refreshing a token that has a finite lifetime such that the program
--   never uses an invalid token. The token is furthermore cached such that
--   network usage is reduced to a minimum.
--   
--   <h1>Preliminaries</h1>
--   
--   <pre>
--   import Network.Goggles
--   </pre>
--   
--   Required language extensions: <tt>OverloadedStrings</tt>,
--   <tt>TypeFamilies</tt>, <tt>FlexibleInstances</tt> .
--   
--   <h1>Usage</h1>
--   
--   To begin with, the user provides a type for the remote service she
--   wishes to interface to, along with a couple typeclass instances.
--   
--   <pre>
--   data Remote
--   
--   newtype C = C { apiKey :: <tt>Text</tt> } deriving Eq   -- API authentication credentials
--   </pre>
--   
--   Notice we don't actually need any data constructor associated with the
--   <tt>Remote</tt> type. In the simplest case it can be a "phantom type",
--   only used to label typeclass instances.
--   
--   This library design allows to be general as possible (many instances
--   are polymorphic in this label, so the user doesn't need to write
--   them), and specific where needed (as we will see with the exception
--   handling mechanism further below.
--   
--   There are so far two main use cases for <tt>goggles</tt>,
--   corresponding to the complexity of the remote API authentication
--   mechanism.
--   
--   <h3>1. Simple authentication</h3>
--   
--   If calling the remote API only requires a key of some sort (i.e. does
--   not involve a session token), the <tt>Remote</tt> type should only be
--   extended with a <a>HasCredentials</a> interface:
--   
--   <pre>
--   instance HasCredentials Remote where
--     type Credentials Remote = C
--   </pre>
--   
--   <h3>2. Token-based authentication</h3>
--   
--   If the API requires a token as well (this is the case with
--   OAuth2-based implementations), the user must extend the
--   <a>HasToken</a> typeclass as well, by providing two associated types
--   and a method implementation :
--   
--   <pre>
--   instance HasToken Remote where
--     type Options Remote = ...                  -- any parameters that should be passed to the API call
--     type TokenContent Remote = ...             -- the raw token string type returned by the API, often a <tt>ByteString</tt>             
--     tokenFetch = ...                           -- function that creates and retrieves the token from the remote API
--   </pre>
--   
--   Once this is in place, a valid token can always be retrieved with
--   <a>accessToken</a>. This checks the validity of the locally cached
--   token and performs a <a>tokenFetch</a> only when this is about to
--   expire.
--   
--   <h1>Exception handling</h1>
--   
--   Internally, <tt>goggles</tt> uses <tt>req</tt> for HTTP connections,
--   so the user must always provide a <tt>MonadHttp</tt> instance for her
--   <tt>Remote</tt> type :
--   
--   <pre>
--   instance MonadHttp (WebApiM Remote) where
--     handleHttpExcepion = ...
--   </pre>
--   
--   The actual implementation of <tt>handleHttpException</tt> depends on
--   the actual API semantics, but the user can just use <tt>throwM</tt>
--   here (imported from the <a>Catch</a> module of the <tt>exceptions</tt>
--   package).
--   
--   <h1>Putting it all together</h1>
--   
--   The usual workflow is as follows:
--   
--   <ul>
--   <li>Create a <a>Handle</a> from the API credentials and any API
--   options with <a>createHandle</a>. This requires a surrounding IO block
--   because token refreshing is done as an atomic update in the STM
--   monad.</li>
--   <li>Build up the program that interacts with the external API in the
--   <a>WebApiM</a> monad.</li>
--   <li>Run the program using the handle with <a>evalWebApiIO</a>.</li>
--   </ul>
module Network.Goggles

-- | <a>GET</a> a lazy bytestring from an API endpoint
getLbs :: (HasCredentials c, MonadHttp (WebApiM c)) => Url scheme -> Option scheme -> WebApiM c LbsResponse

-- | <a>POST</a> a request to an API endpoint and receive a lazy bytestring
--   in return
postLbs :: (HasCredentials c, MonadHttp (WebApiM c)) => Url scheme -> Option scheme -> ByteString -> WebApiM c LbsResponse

-- | <a>PUT</a> a request to an API endpoint and receive a lazy bytestring
--   in return
putLbs :: (HasCredentials c, MonadHttp (WebApiM c)) => Url scheme -> Option scheme -> ByteString -> WebApiM c LbsResponse

-- | Create an authenticated <a>GET</a> call
getLbsWithToken :: (HasCredentials c, HasToken c, MonadHttp (WebApiM c)) => (TokenContent c -> Url scheme -> Option scheme -> (Url scheme, Option scheme)) -> Url scheme -> Option scheme -> WebApiM c LbsResponse

-- | Create an authenticated <a>POST</a> call
postLbsWithToken :: (HasCredentials c, HasToken c, MonadHttp (WebApiM c)) => (TokenContent c -> Url scheme -> Option scheme -> ByteString -> (Url scheme, Option scheme, ByteString)) -> Url scheme -> Option scheme -> ByteString -> WebApiM c LbsResponse

-- | Create an authenticated <a>PUT</a> call
putLbsWithToken :: (HasCredentials c, HasToken c, MonadHttp (WebApiM c)) => (TokenContent c -> Url scheme -> Option scheme -> ByteString -> (Url scheme, Option scheme, ByteString)) -> Url scheme -> Option scheme -> ByteString -> WebApiM c LbsResponse

-- | Create a <a>Handle</a> with an initially empty token
createHandle :: HasCredentials c => Credentials c -> Options c -> IO (Handle c)

-- | Evaluate a <a>WebApiM</a> action, given a <a>Handle</a>.
--   
--   NB : Assumes all exceptions are handled by <a>throwM</a>
evalWebApiIO :: Handle c -> WebApiM c a -> IO a

-- | Lift an `IO a` action into the <a>WebApiM</a> monad, and catch
--   synchronous exceptions, while rethrowing the asynchronous ones to IO
liftWebApiIO :: IO a -> WebApiM c a

-- | The main type of the library. It can easily be re-used in libraries
--   that interface with more than one cloud API provider because its type
--   parameter <tt>c</tt> lets us declare distinct behaviours for each.
newtype WebApiM c a
WebApiM :: ReaderT (Handle c) IO a -> WebApiM c a
[runWebApiM] :: WebApiM c a -> ReaderT (Handle c) IO a
class HasCredentials c where {
    type family Credentials c;
}
class HasToken c where {
    type family TokenContent c;
    type family Options c;
}
tokenFetch :: HasToken c => WebApiM c (Token c)

-- | An authentication <a>Token</a> with an expiry date
data Token c
Token :: TokenContent c -> UTCTime -> Token c
[tToken] :: Token c -> TokenContent c
[tTime] :: Token c -> UTCTime

-- | Extract the token content (needed to authenticate subsequent
--   requests). The token will be valid for at least 60 seconds
accessToken :: HasToken c => WebApiM c (TokenContent c)
refreshToken :: HasToken c => WebApiM c (Token c)

-- | A <a>Handle</a> contains all information necessary to communicating
--   with a cloud API provider:
--   
--   <ul>
--   <li>Authentication credentials (e.g. username/password)</li>
--   <li>Authentication token (used to authenticate every API call)</li>
--   <li>Options (e.g. GCP authentication scopes)</li>
--   </ul>
data Handle c
Handle :: Credentials c -> TVar (Maybe (Token c)) -> Options c -> Handle c
[credentials] :: Handle c -> Credentials c
[token] :: Handle c -> TVar (Maybe (Token c))
[options] :: Handle c -> Options c

-- | Parse a chunk of text into an RSA private key. For Google Cloud
--   Platform , this is the private key associated with the user's "service
--   account" (for server-to-server API use)
--   
--   <pre>
--   https://console.cloud.google.com/apis/credentials
--   </pre>
--   
--   Note: do <i>not</i> supply the RSA header and footer or any newlines
--   (they will be inserted by this function).
parseRSAPrivateKey :: MonadThrow m => Text -> m PrivateKey
data OAuth2Token
OAuth2Token :: Int -> Text -> Maybe Text -> OAuth2Token
[oaTokenExpirySeconds] :: OAuth2Token -> Int
[oaTokenString] :: OAuth2Token -> Text
[oaTokenType] :: OAuth2Token -> Maybe Text

-- | Authentication key exceptions
data KeyException
NoSecretFound :: !String -> KeyException
NoParsePK :: !String -> KeyException
NoRSAKey :: !String -> KeyException

-- | Errors associated with JWT-encoded token request
data JWTError
BadExpirationTime :: !String -> JWTError
CryptoSignError :: !String -> JWTError

-- | Token exchange exceptions
data TokenExchangeException

-- | Something went wrong with the request, token not found
NotFound :: !String -> TokenExchangeException

APICredentialsNotFound :: !String -> TokenExchangeException

-- | Cloud API exception
data CloudException
UnknownError :: !String -> CloudException
IOError :: !String -> CloudException
TimeoutError :: !String -> CloudException
JsonDecodeError :: !String -> CloudException
XMLDecodeError :: !String -> CloudException
urlEncode :: String -> String
