This repository has been archived by the owner on Jul 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
208 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
module Reddit.Actions.OAuth | ||
( accessTokenWithCode | ||
, accessTokenWithRefreshToken | ||
) where | ||
|
||
import Data.ByteString.Base64 (encode) | ||
import Data.Text (Text) | ||
import qualified Data.Text.Encoding as Text | ||
import Network.API.Builder hiding (runRoute) | ||
import Network.HTTP.Types (Header) | ||
import Reddit.Types.OAuth | ||
import Reddit.Types.Reddit | ||
|
||
accessTokenWithCodeRoute :: AuthorizationCode -> Client -> Route | ||
accessTokenWithCodeRoute AuthorizationCode {authorizationCode = code} client = | ||
Route | ||
["api", "v1", "access_token"] | ||
[ ("grant_type" :: Text) =. ("authorization_code" :: Text) | ||
, "code" =. code | ||
, "redirect_uri" =. redirectUrl client | ||
] | ||
"POST" | ||
|
||
accessTokenWithCode :: | ||
Monad m | ||
=> AuthorizationCode | ||
-> Client | ||
-> RedditT m (AccessToken, RefreshToken) | ||
accessTokenWithCode code client = | ||
withHeaders (authorizationHeader client :) $ | ||
receiveRoute $ accessTokenWithCodeRoute code client | ||
|
||
accessTokenWithRefreshTokenRoute :: RefreshToken -> Route | ||
accessTokenWithRefreshTokenRoute RefreshToken {refreshToken = token} = | ||
Route | ||
["api", "v1", "access_token"] | ||
[ ("grant_type" :: Text) =. ("refresh_token" :: Text) | ||
, "refresh_token" =. token | ||
] | ||
"POST" | ||
|
||
accessTokenWithRefreshToken :: | ||
Monad m => RefreshToken -> Client -> RedditT m AccessToken | ||
accessTokenWithRefreshToken refreshToken client = | ||
withHeaders (authorizationHeader client :) $ | ||
receiveRoute $ accessTokenWithRefreshTokenRoute refreshToken | ||
|
||
authorizationHeader :: Client -> Header | ||
authorizationHeader Script {clientId = clientId, secret = secret} = | ||
( "Authorization" | ||
, "Basic " <> encode (Text.encodeUtf8 (clientId <> ":" <> secret))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
module Reddit.Types.OAuth where | ||
|
||
import Data.Aeson | ||
import Data.Aeson.Types (Parser) | ||
import Data.Text as Text | ||
import Network.API.Builder | ||
|
||
data Client = | ||
Script | ||
{ clientId :: Text | ||
, secret :: Text | ||
, redirectUrl :: Text | ||
} | ||
deriving (Show) | ||
|
||
newtype RefreshToken = | ||
RefreshToken | ||
{ refreshToken :: Text | ||
} | ||
deriving (Show) | ||
|
||
instance Receivable RefreshToken where | ||
receive = useFromJSON | ||
|
||
instance FromJSON RefreshToken where | ||
parseJSON (Object o) = RefreshToken <$> (o .: "refresh_token") | ||
|
||
newtype AuthorizationCode = | ||
AuthorizationCode | ||
{ authorizationCode :: Text | ||
} | ||
deriving (Show) | ||
|
||
data TokenType = | ||
Bearer | ||
deriving (Show, Enum) | ||
|
||
instance FromJSON TokenType where | ||
parseJSON (String raw) = | ||
case lookup raw $ | ||
Prelude.map (\elem -> (toLower $ pack $ show elem, elem)) [Bearer ..] of | ||
Just result -> return result | ||
Nothing -> fail $ "Unsupported token type in response: " ++ unpack raw | ||
|
||
data AccessToken = | ||
AccessToken | ||
{ accessToken :: Text | ||
, tokenType :: TokenType | ||
, expiresIn :: Word | ||
, scope :: [Scope] | ||
} | ||
deriving (Show) | ||
|
||
instance FromJSON AccessToken where | ||
parseJSON (Object o) = | ||
AccessToken <$> (o .: "access_token") <*> (o .: "token_type") <*> | ||
(o .: "expires_in") <*> | ||
(o .: "scope" >>= parseJSONScopeString) | ||
|
||
instance Receivable AccessToken where | ||
receive = useFromJSON | ||
|
||
data Scope | ||
= Identity | ||
| Edit | ||
| Flair | ||
| History | ||
| ModConfig | ||
| ModFlair | ||
| ModLog | ||
| ModPosts | ||
| ModWiki | ||
| MySubreddits | ||
| PrivateMessages | ||
| Read | ||
| Report | ||
| Save | ||
| Submit | ||
| Subscribe | ||
| Vote | ||
| WikiEdit | ||
| WikiRead | ||
| All | ||
deriving (Show, Enum) | ||
|
||
parseJSONScopeString :: Value -> Parser [Scope] | ||
parseJSONScopeString (String text) = | ||
Prelude.mapM textToScope $ | ||
split | ||
(\c -> | ||
case c of | ||
' ' -> True | ||
',' -> True | ||
_ -> False) | ||
text | ||
where | ||
textToScope "*" = return All | ||
textToScope raw = | ||
case lookup raw $ | ||
Prelude.map | ||
(\elem -> (toLower $ pack $ show elem, elem)) | ||
[Identity ..] of | ||
Just result -> return result | ||
Nothing -> fail $ "Unsupported token type in response: " ++ unpack raw |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters