{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Network.OAuth.ThreeLegged (
ThreeLegged (..), parseThreeLegged, P.Callback (..),
P.Verifier,
requestTemporaryToken, buildAuthorizationUrl, requestPermanentToken,
requestTemporaryTokenRaw, requestPermanentTokenRaw,
requestTokenProtocol, requestTokenProtocol'
) where
import Control.Monad.IO.Class (MonadIO, liftIO)
import Crypto.Random (MonadRandom)
import qualified Data.ByteString.Lazy as SL
import Data.Data
import qualified Network.HTTP.Client as C
import Network.HTTP.Types (renderQuery)
import qualified Network.OAuth as O
import Network.OAuth.MuLens
import qualified Network.OAuth.Types.Credentials as Cred
import qualified Network.OAuth.Types.Params as P
import Network.URI
data ThreeLegged =
ThreeLegged { temporaryTokenRequest :: C.Request
, resourceOwnerAuthorization :: C.Request
, permanentTokenRequest :: C.Request
, callback :: P.Callback
}
deriving ( Show, Typeable )
parseThreeLegged :: String -> String -> String -> P.Callback -> Maybe ThreeLegged
parseThreeLegged a b c d =
ThreeLegged <$> C.parseRequest a
<*> C.parseRequest b
<*> C.parseRequest c
<*> pure d
requestTemporaryTokenRaw
:: (MonadIO m, MonadRandom m) => O.Cred O.Client -> O.Server
-> ThreeLegged -> C.Manager
-> m(C.Response SL.ByteString)
requestTemporaryTokenRaw cr srv (ThreeLegged {..}) man = do
oax <- O.freshOa cr
let req = O.sign (oax { P.workflow = P.TemporaryTokenRequest callback }) srv temporaryTokenRequest
liftIO $ C.httpLbs req man
requestTemporaryToken
:: (MonadIO m, MonadRandom m) => O.Cred O.Client -> O.Server
-> ThreeLegged -> C.Manager
-> m (C.Response (Either SL.ByteString (O.Token O.Temporary)))
requestTemporaryToken cr srv tl man = do
raw <- requestTemporaryTokenRaw cr srv tl man
return $ tryParseToken <$> raw
where
tryParseToken lbs = case maybeParseToken lbs of
Nothing -> Left lbs
Just tok -> Right tok
maybeParseToken lbs =
do (confirmed, tok) <- O.fromUrlEncoded $ SL.toStrict lbs
case P.oAuthVersion srv of
O.OAuthCommunity1 -> return tok
_ -> if confirmed then return tok else fail "Must be confirmed"
buildAuthorizationUrl :: O.Cred O.Temporary -> ThreeLegged -> URI
buildAuthorizationUrl cr (ThreeLegged {..}) =
C.getUri $ resourceOwnerAuthorization {
C.queryString = renderQuery True [ ("oauth_token", Just (cr ^. Cred.resourceToken . Cred.key)) ]
}
requestPermanentTokenRaw
:: (MonadIO m, MonadRandom m) => O.Cred O.Temporary -> O.Server
-> P.Verifier
-> ThreeLegged -> C.Manager
-> m (C.Response SL.ByteString)
requestPermanentTokenRaw cr srv verifier (ThreeLegged {..}) man = do
oax <- O.freshOa cr
let req = O.sign (oax { P.workflow = P.PermanentTokenRequest verifier }) srv permanentTokenRequest
liftIO $ C.httpLbs req man
requestPermanentToken
:: (MonadIO m, MonadRandom m) => O.Cred O.Temporary -> O.Server
-> P.Verifier
-> ThreeLegged -> C.Manager
-> m (C.Response (Either SL.ByteString (O.Token O.Permanent)))
requestPermanentToken cr srv verifier tl man = do
raw <- requestPermanentTokenRaw cr srv verifier tl man
return $ tryParseToken <$> raw
where
tryParseToken lbs = case maybeParseToken lbs of
Nothing -> Left lbs
Just tok -> Right tok
maybeParseToken = fmap snd . O.fromUrlEncoded . SL.toStrict
requestTokenProtocol'
:: (MonadIO m, MonadRandom m) => C.ManagerSettings -> O.Cred O.Client -> O.Server -> ThreeLegged
-> (URI -> m P.Verifier)
-> m (Maybe (O.Cred O.Permanent))
requestTokenProtocol' mset cr srv tl getVerifier = do
man <- liftIO $ C.newManager mset
respTempToken <- requestTemporaryToken cr srv tl man
case C.responseBody respTempToken of
Left _ -> return Nothing
Right tok -> do
let tempCr = O.temporaryCred tok cr
verifier <- getVerifier $ buildAuthorizationUrl tempCr tl
respPermToken <- requestPermanentToken tempCr srv verifier tl man
case C.responseBody respPermToken of
Left _ -> return Nothing
Right tok' -> return (Just $ O.permanentCred tok' cr)
requestTokenProtocol
:: (MonadIO m, MonadRandom m) => O.Cred O.Client -> O.Server -> ThreeLegged
-> (URI -> m P.Verifier)
-> m (Maybe (O.Cred O.Permanent))
requestTokenProtocol = requestTokenProtocol' C.defaultManagerSettings