feat: WIP preparing other OIDC

This commit is contained in:
GitBluub
2022-02-18 14:09:20 +01:00
parent d67c2c0646
commit 7beda9788f
8 changed files with 291 additions and 12 deletions
+4
View File
@@ -40,7 +40,11 @@ library
Db.User
Lib
OIDC
OIDC.Discord
OIDC.Github
OIDC.Google
OIDC.Spotify
OIDC.Twitter
Password
Repository
Repository.Pipeline
+2
View File
@@ -1,6 +1,8 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use newtype instead of data" #-}
module Api.About where
+68
View File
@@ -0,0 +1,68 @@
{-# LANGUAGE OverloadedStrings #-}
module OIDC.Discord where
import qualified Data.Text as T
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString.Char8 as B8
import System.Environment.MrEnv ( envAsBool, envAsInt, envAsInteger, envAsString )
import Network.HTTP.Simple (JSONException, parseRequest, setRequestMethod, addRequestHeader, setRequestQueryString, httpJSONEither, getResponseBody)
import Data.Aeson.Types (Object, Value (String))
import Data.Text ( Text, pack )
import App (AppM)
import Core.User (ExternalToken (ExternalToken), Service (Github))
import Utils (lookupObj)
data DiscordOAuth2 = DiscordOAuth2
{ oauthClientId :: String
, oauthClientSecret :: String
, oauthOAuthorizeEndpoint :: String
, oauthAccessTokenEndpoint :: String
, oauthCallback :: String
} deriving (Show, Eq)
getDiscordConfig :: IO DiscordOAuth2
getDiscordConfig = DiscordOAuth2
<$> envAsString "DISCORD_CLIENT_ID" ""
<*> envAsString "DISCORD_SECRET" ""
<*> pure "https://github.com/login/oauth/authorize"
<*> pure "https://github.com/login/oauth/access_token"
<*> pure "http://localhost:8080/auth/github/token"
githubAuthEndpoint :: DiscordOAuth2 -> String
githubAuthEndpoint oa = concat [ oauthOAuthorizeEndpoint oa
, "?client_id=", oauthClientId oa
, "&response_type=", "code"
, "&redirect_uri=", oauthCallback oa]
tokenEndpoint :: String -> DiscordOAuth2 -> String
tokenEndpoint code oa = concat [ oauthAccessTokenEndpoint oa
, "?client_id=", oauthClientId oa
, "&client_secret=", oauthClientSecret oa
, "&code=", code]
getGithubAuthEndpoint :: IO String
getGithubAuthEndpoint = githubAuthEndpoint <$> getDiscordConfig
-- Step 3. Exchange code for auth token
getGithubTokens :: String -> IO (Maybe ExternalToken)
getGithubTokens code = do
gh <- getDiscordConfig
let endpoint = tokenEndpoint code gh
request' <- parseRequest endpoint
let request = setRequestMethod "POST"
$ addRequestHeader "Accept" "application/json"
$ setRequestQueryString [ ("client_id", Just . B8.pack . oauthClientId $ gh)
, ("client_secret", Just . B8.pack . oauthClientSecret $ gh)
, ("code", Just . B8.pack $ code)]
$ request'
response <- httpJSONEither request
return $ case (getResponseBody response :: Either JSONException Object) of
Left _ -> Nothing
Right obj -> do
access <- lookupObj obj "access_token"
refresh <- lookupObj obj "refresh_token"
Just $ ExternalToken (pack access) (pack refresh) 0 Github
+4 -11
View File
@@ -1,20 +1,19 @@
{-# LANGUAGE OverloadedStrings #-}
module OIDC.Github where
import qualified Data.Text as T
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString.Char8 as B8
import System.Environment.MrEnv ( envAsBool, envAsInt, envAsInteger, envAsString )
import Network.HTTP.Simple (JSONException, parseRequest, setRequestMethod, addRequestHeader, setRequestQueryString, httpJSONEither, getResponseBody)
import Data.Aeson.Types (Object, Value (String))
import Data.Text (Text)
import Data.Text ( Text, pack )
import App (AppM)
import Core.User (ExternalToken (ExternalToken), Service (Github))
import Data.Text (pack)
import Utils (lookupObj)
data GithubOAuth2 = GithubOAuth2
data GithubOAuth2 = GithubOAuth2
{ oauthClientId :: String
, oauthClientSecret :: String
, oauthOAuthorizeEndpoint :: String
@@ -45,12 +44,6 @@ tokenEndpoint code oa = concat [ oauthAccessTokenEndpoint oa
, "&client_secret=", oauthClientSecret oa
, "&code=", code]
lookupObj :: Object -> Text -> Maybe String
lookupObj obj key = case HM.lookup key obj of
Just (String x) -> Just . T.unpack $ x
_ -> Nothing
getGithubAuthEndpoint :: IO String
getGithubAuthEndpoint = githubAuthEndpoint <$> getGithubConfig
@@ -69,7 +62,7 @@ getGithubTokens code = do
response <- httpJSONEither request
return $ case (getResponseBody response :: Either JSONException Object) of
Left _ -> Nothing
Right obj -> do
Right obj -> do
access <- lookupObj obj "access_token"
refresh <- lookupObj obj "refresh_token"
Just $ ExternalToken (pack access) (pack refresh) 0 Github
+54
View File
@@ -0,0 +1,54 @@
{-# LANGUAGE OverloadedStrings #-}
module OIDC.Github where
import qualified Data.Text as T
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString.Char8 as B8
import System.Environment.MrEnv ( envAsBool, envAsInt, envAsInteger, envAsString )
import Network.HTTP.Simple (JSONException, parseRequest, setRequestMethod, addRequestHeader, setRequestQueryString, httpJSONEither, getResponseBody)
import Data.Aeson.Types (Object, Value (String))
import Data.Text ( Text, pack )
import App (AppM)
import Core.User (ExternalToken (ExternalToken), Service (Github))
import Utils (lookupObj)
data GoogleOAuth2 = GoogleOAuth2
{ oauthClientId :: String
, oauthClientSecret :: String
, oauthAccessTokenEndpoint :: String
} deriving (Show, Eq)
getGoogleConfig :: IO GoogleOAuth2
getGoogleConfig = GoogleOAuth2
<$> envAsString "GOOGLE_CLIENT_ID" ""
<*> envAsString "GOOGLE_SECRET" ""
<*> pure "https://github.com/login/oauth/access_token"
tokenEndpoint :: String -> GoogleOAuth2 -> String
tokenEndpoint code oa = concat [ oauthAccessTokenEndpoint oa
, "?client_id=", oauthClientId oa
, "&client_secret=", oauthClientSecret oa
, "&code=", code]
-- Step 3. Exchange code for auth token
getGithubTokens :: String -> IO (Maybe ExternalToken)
getGithubTokens code = do
gh <- getGoogleConfig
let endpoint = tokenEndpoint code gh
request' <- parseRequest endpoint
let request = setRequestMethod "POST"
$ addRequestHeader "Accept" "application/json"
$ setRequestQueryString [ ("client_id", Just . B8.pack . oauthClientId $ gh)
, ("client_secret", Just . B8.pack . oauthClientSecret $ gh)
, ("code", Just . B8.pack $ code)]
$ request'
response <- httpJSONEither request
return $ case (getResponseBody response :: Either JSONException Object) of
Left _ -> Nothing
Right obj -> do
access <- lookupObj obj "access_token"
refresh <- lookupObj obj "refresh_token"
Just $ ExternalToken (pack access) (pack refresh) 0 Github
+74
View File
@@ -0,0 +1,74 @@
{-# LANGUAGE OverloadedStrings #-}
module OIDC.Github where
import qualified Data.Text as T
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString.Char8 as B8
import System.Environment.MrEnv ( envAsBool, envAsInt, envAsInteger, envAsString )
import Network.HTTP.Simple (JSONException, parseRequest, setRequestMethod, addRequestHeader, setRequestQueryString, httpJSONEither, getResponseBody)
import Data.Aeson.Types (Object, Value (String))
import Data.Text ( Text, pack )
import App (AppM)
import Core.User (ExternalToken (ExternalToken), Service (Github))
data GithubOAuth2 = GithubOAuth2
{ oauthClientId :: String
, oauthClientSecret :: String
, oauthOAuthorizeEndpoint :: String
, oauthAccessTokenEndpoint :: String
, oauthCallback :: String
} deriving (Show, Eq)
getGithubConfig :: IO GithubOAuth2
getGithubConfig = GithubOAuth2
<$> envAsString "GITHUB_CLIENT_ID" ""
<*> envAsString "GITHUB_SECRET" ""
<*> pure "https://github.com/login/oauth/authorize"
<*> pure "https://github.com/login/oauth/access_token"
<*> pure "http://localhost:8080/auth/github/token"
githubAuthEndpoint :: GithubOAuth2 -> String
githubAuthEndpoint oa = concat [ oauthOAuthorizeEndpoint oa
, "?client_id=", oauthClientId oa
, "&response_type=", "code"
, "&redirect_uri=", oauthCallback oa]
tokenEndpoint :: String -> GithubOAuth2 -> String
tokenEndpoint code oa = concat [ oauthAccessTokenEndpoint oa
, "?client_id=", oauthClientId oa
, "&client_secret=", oauthClientSecret oa
, "&code=", code]
lookupObj :: Object -> Text -> Maybe String
lookupObj obj key = case HM.lookup key obj of
Just (String x) -> Just . T.unpack $ x
_ -> Nothing
getGithubAuthEndpoint :: IO String
getGithubAuthEndpoint = githubAuthEndpoint <$> getGithubConfig
-- Step 3. Exchange code for auth token
getGithubTokens :: String -> IO (Maybe ExternalToken)
getGithubTokens code = do
gh <- getGithubConfig
let endpoint = tokenEndpoint code gh
request' <- parseRequest endpoint
let request = setRequestMethod "POST"
$ addRequestHeader "Accept" "application/json"
$ setRequestQueryString [ ("client_id", Just . B8.pack . oauthClientId $ gh)
, ("client_secret", Just . B8.pack . oauthClientSecret $ gh)
, ("code", Just . B8.pack $ code)]
$ request'
response <- httpJSONEither request
return $ case (getResponseBody response :: Either JSONException Object) of
Left _ -> Nothing
Right obj -> do
access <- lookupObj obj "access_token"
refresh <- lookupObj obj "refresh_token"
Just $ ExternalToken (pack access) (pack refresh) 0 Github
+74
View File
@@ -0,0 +1,74 @@
{-# LANGUAGE OverloadedStrings #-}
module OIDC.Github where
import qualified Data.Text as T
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString.Char8 as B8
import System.Environment.MrEnv ( envAsBool, envAsInt, envAsInteger, envAsString )
import Network.HTTP.Simple (JSONException, parseRequest, setRequestMethod, addRequestHeader, setRequestQueryString, httpJSONEither, getResponseBody)
import Data.Aeson.Types (Object, Value (String))
import Data.Text ( Text, pack )
import App (AppM)
import Core.User (ExternalToken (ExternalToken), Service (Github))
data GithubOAuth2 = GithubOAuth2
{ oauthClientId :: String
, oauthClientSecret :: String
, oauthOAuthorizeEndpoint :: String
, oauthAccessTokenEndpoint :: String
, oauthCallback :: String
} deriving (Show, Eq)
getGithubConfig :: IO GithubOAuth2
getGithubConfig = GithubOAuth2
<$> envAsString "GITHUB_CLIENT_ID" ""
<*> envAsString "GITHUB_SECRET" ""
<*> pure "https://github.com/login/oauth/authorize"
<*> pure "https://github.com/login/oauth/access_token"
<*> pure "http://localhost:8080/auth/github/token"
githubAuthEndpoint :: GithubOAuth2 -> String
githubAuthEndpoint oa = concat [ oauthOAuthorizeEndpoint oa
, "?client_id=", oauthClientId oa
, "&response_type=", "code"
, "&redirect_uri=", oauthCallback oa]
tokenEndpoint :: String -> GithubOAuth2 -> String
tokenEndpoint code oa = concat [ oauthAccessTokenEndpoint oa
, "?client_id=", oauthClientId oa
, "&client_secret=", oauthClientSecret oa
, "&code=", code]
lookupObj :: Object -> Text -> Maybe String
lookupObj obj key = case HM.lookup key obj of
Just (String x) -> Just . T.unpack $ x
_ -> Nothing
getGithubAuthEndpoint :: IO String
getGithubAuthEndpoint = githubAuthEndpoint <$> getGithubConfig
-- Step 3. Exchange code for auth token
getGithubTokens :: String -> IO (Maybe ExternalToken)
getGithubTokens code = do
gh <- getGithubConfig
let endpoint = tokenEndpoint code gh
request' <- parseRequest endpoint
let request = setRequestMethod "POST"
$ addRequestHeader "Accept" "application/json"
$ setRequestQueryString [ ("client_id", Just . B8.pack . oauthClientId $ gh)
, ("client_secret", Just . B8.pack . oauthClientSecret $ gh)
, ("code", Just . B8.pack $ code)]
$ request'
response <- httpJSONEither request
return $ case (getResponseBody response :: Either JSONException Object) of
Left _ -> Nothing
Right obj -> do
access <- lookupObj obj "access_token"
refresh <- lookupObj obj "refresh_token"
Just $ ExternalToken (pack access) (pack refresh) 0 Github
+11 -1
View File
@@ -1,4 +1,14 @@
module Utils where
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.HashMap.Strict as HM
import Data.Aeson.Types (Object, Value (String))
mapInd :: (a -> Int -> b) -> [a] -> [b]
mapInd f l = zipWith f l [0..]
mapInd f l = zipWith f l [0..]
lookupObj :: Object -> Text -> Maybe String
lookupObj obj key = case HM.lookup key obj of
Just (String x) -> Just . T.unpack $ x
_ -> Nothing