aboutsummaryrefslogtreecommitdiff
path: root/src/Sproxy/Application
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2016-11-25 23:40:29 +0300
committerIgor Pashev <pashev.igor@gmail.com>2016-11-25 23:51:25 +0300
commitea17e9c2a3350ba670f95a6fa0ce7716adfa4176 (patch)
tree1cde3e92d68a816a54ea7b0cca8af0b97e7c291e /src/Sproxy/Application
parent7ba0b2158124bbf10fbdeeec70fb7e631a32a364 (diff)
downloadsproxy2-ea17e9c2a3350ba670f95a6fa0ce7716adfa4176.tar.gz
Make sure all HTTP headers are UTF8-encoded
Especially X-Family-Name, X-Given-Name. Since we get all the data from JSON and JSON is in UTF8 by default RFC 7159, we are safe. Refactored to make it less error-prone and to get as small number of encoding/decoding as possible.
Diffstat (limited to 'src/Sproxy/Application')
-rw-r--r--src/Sproxy/Application/Cookie.hs45
-rw-r--r--src/Sproxy/Application/OAuth2/Common.hs3
-rw-r--r--src/Sproxy/Application/OAuth2/Google.hs15
-rw-r--r--src/Sproxy/Application/OAuth2/LinkedIn.hs19
4 files changed, 61 insertions, 21 deletions
diff --git a/src/Sproxy/Application/Cookie.hs b/src/Sproxy/Application/Cookie.hs
index 07cc162..a86f42a 100644
--- a/src/Sproxy/Application/Cookie.hs
+++ b/src/Sproxy/Application/Cookie.hs
@@ -1,20 +1,30 @@
+{-# LANGUAGE OverloadedStrings #-}
module Sproxy.Application.Cookie (
AuthCookie(..)
-, AuthUser(..)
+, AuthUser
, cookieDecode
, cookieEncode
+, getEmail
+, getEmailUtf8
+, getFamilyNameUtf8
+, getGivenNameUtf8
+, newUser
+, setFamilyName
+, setGivenName
) where
import Data.ByteString (ByteString)
+import Data.Text (Text, toLower, strip)
+import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Foreign.C.Types (CTime(..))
import qualified Data.Serialize as DS
import qualified Sproxy.Application.State as State
data AuthUser = AuthUser {
- auEmail :: String
-, auGivenName :: String
-, auFamilyName :: String
+ auEmail :: ByteString
+, auGivenName :: ByteString
+, auFamilyName :: ByteString
}
data AuthCookie = AuthCookie {
@@ -37,8 +47,33 @@ instance DS.Serialize AuthCookie where
cookieDecode :: ByteString -> ByteString -> Either String AuthCookie
cookieDecode key d = State.decode key d >>= DS.decode
-
cookieEncode :: ByteString -> AuthCookie -> ByteString
cookieEncode key = State.encode key . DS.encode
+getEmail :: AuthUser -> Text
+getEmail = decodeUtf8 . auEmail
+
+getEmailUtf8 :: AuthUser -> ByteString
+getEmailUtf8 = auEmail
+
+getGivenNameUtf8 :: AuthUser -> ByteString
+getGivenNameUtf8 = auGivenName
+
+getFamilyNameUtf8 :: AuthUser -> ByteString
+getFamilyNameUtf8 = auFamilyName
+
+
+newUser :: Text -> AuthUser
+newUser email = AuthUser {
+ auEmail = encodeUtf8 . toLower . strip $ email
+ , auGivenName = ""
+ , auFamilyName = ""
+ }
+
+setGivenName :: Text -> AuthUser -> AuthUser
+setGivenName given au = au{ auGivenName = encodeUtf8 . strip $ given }
+
+setFamilyName :: Text -> AuthUser -> AuthUser
+setFamilyName family au = au{ auFamilyName = encodeUtf8 . strip $ family }
+
diff --git a/src/Sproxy/Application/OAuth2/Common.hs b/src/Sproxy/Application/OAuth2/Common.hs
index 07fb759..0324e62 100644
--- a/src/Sproxy/Application/OAuth2/Common.hs
+++ b/src/Sproxy/Application/OAuth2/Common.hs
@@ -8,6 +8,7 @@ module Sproxy.Application.OAuth2.Common (
import Control.Applicative (empty)
import Data.Aeson (FromJSON, parseJSON, Value(Object), (.:))
import Data.ByteString(ByteString)
+import Data.Text (Text)
import Sproxy.Application.Cookie (AuthUser)
@@ -29,7 +30,7 @@ type OAuth2Provider = (ByteString, ByteString) -> OAuth2Client
-- and expires_in because we don't use them, *and* expires_in creates troubles:
-- it's an integer from Google and string from LinkedIn (sic!)
data AccessTokenBody = AccessTokenBody {
- accessToken :: String
+ accessToken :: Text
} deriving (Eq, Show)
instance FromJSON AccessTokenBody where
diff --git a/src/Sproxy/Application/OAuth2/Google.hs b/src/Sproxy/Application/OAuth2/Google.hs
index 6b68f44..5a1834c 100644
--- a/src/Sproxy/Application/OAuth2/Google.hs
+++ b/src/Sproxy/Application/OAuth2/Google.hs
@@ -9,12 +9,13 @@ import Control.Exception (Exception, throwIO)
import Data.Aeson (FromJSON, decode, parseJSON, Value(Object), (.:))
import Data.ByteString.Lazy (ByteString)
import Data.Monoid ((<>))
+import Data.Text (Text, unpack)
import Data.Typeable (Typeable)
import Network.HTTP.Types (hContentType)
import Network.HTTP.Types.URI (urlEncode)
import qualified Network.HTTP.Conduit as H
-import Sproxy.Application.Cookie (AuthUser(..))
+import Sproxy.Application.Cookie (newUser, setFamilyName, setGivenName)
import Sproxy.Application.OAuth2.Common (AccessTokenBody(accessToken), OAuth2Client(..), OAuth2Provider)
@@ -48,11 +49,13 @@ provider (client_id, client_secret) =
case decode $ H.responseBody tresp of
Nothing -> throwIO $ GoogleException tresp
Just atResp -> do
- ureq <- H.parseRequest $ "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" ++ accessToken atResp
+ ureq <- H.parseRequest $ unpack ("https://www.googleapis.com/oauth2/v1/userinfo?access_token=" <> accessToken atResp)
uresp <- H.httpLbs ureq mgr
case decode $ H.responseBody uresp of
Nothing -> throwIO $ GoogleException uresp
- Just u -> return AuthUser { auEmail = email u, auGivenName = givenName u, auFamilyName = familyName u }
+ Just u -> return $ setFamilyName (familyName u) $
+ setGivenName (givenName u) $
+ newUser (email u)
}
@@ -64,9 +67,9 @@ instance Exception GoogleException
data GoogleUserInfo = GoogleUserInfo {
- email :: String
-, givenName :: String
-, familyName :: String
+ email :: Text
+, givenName :: Text
+, familyName :: Text
} deriving (Eq, Show)
instance FromJSON GoogleUserInfo where
diff --git a/src/Sproxy/Application/OAuth2/LinkedIn.hs b/src/Sproxy/Application/OAuth2/LinkedIn.hs
index b60afde..b35c566 100644
--- a/src/Sproxy/Application/OAuth2/LinkedIn.hs
+++ b/src/Sproxy/Application/OAuth2/LinkedIn.hs
@@ -7,15 +7,16 @@ module Sproxy.Application.OAuth2.LinkedIn (
import Control.Applicative (empty)
import Control.Exception (Exception, throwIO)
import Data.Aeson (FromJSON, decode, parseJSON, Value(Object), (.:))
-import Data.ByteString.Char8 (pack)
import Data.ByteString.Lazy (ByteString)
import Data.Monoid ((<>))
+import Data.Text (Text)
+import Data.Text.Encoding (encodeUtf8)
import Data.Typeable (Typeable)
import Network.HTTP.Types (hContentType)
import Network.HTTP.Types.URI (urlEncode)
import qualified Network.HTTP.Conduit as H
-import Sproxy.Application.Cookie (AuthUser(..))
+import Sproxy.Application.Cookie (newUser, setFamilyName, setGivenName)
import Sproxy.Application.OAuth2.Common (AccessTokenBody(accessToken), OAuth2Client(..), OAuth2Provider)
@@ -50,14 +51,14 @@ provider (client_id, client_secret) =
Just atResp -> do
let ureq = (H.parseRequest_ "https://api.linkedin.com/v1/people/\
\~:(email-address,first-name,last-name)?format=json") {
- H.requestHeaders = [ ("Authorization", "Bearer " <> pack (accessToken atResp)) ]
+ H.requestHeaders = [ ("Authorization", "Bearer " <> encodeUtf8 (accessToken atResp)) ]
}
uresp <- H.httpLbs ureq mgr
case decode $ H.responseBody uresp of
Nothing -> throwIO $ LinkedInException uresp
- Just u -> return AuthUser { auEmail = emailAddress u
- , auGivenName = firstName u
- , auFamilyName = lastName u }
+ Just u -> return $ setFamilyName (lastName u) $
+ setGivenName (firstName u) $
+ newUser (emailAddress u)
}
@@ -69,9 +70,9 @@ instance Exception LinkedInException
data LinkedInUserInfo = LinkedInUserInfo {
- emailAddress :: String
-, firstName :: String
-, lastName :: String
+ emailAddress :: Text
+, firstName :: Text
+, lastName :: Text
} deriving (Eq, Show)
instance FromJSON LinkedInUserInfo where