module Network.Pusher.Internal.Auth
( authenticatePresence
, authenticatePresenceWithEncoder
, authenticatePrivate, makeQS
) where
import Data.Monoid ((<>))
import Data.Text.Encoding (encodeUtf8)
import GHC.Exts (sortWith)
import qualified Data.Aeson as A
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString.Lazy as BL
import qualified Data.Text as T
import qualified Crypto.Hash.MD5 as MD5
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Crypto.MAC.HMAC as HMAC
import Data.Pusher (Credentials(..))
makeQS
:: B.ByteString
-> B.ByteString
-> T.Text
-> T.Text
-> [(B.ByteString, B.ByteString)]
-> B.ByteString
-> Int
-> [(B.ByteString, B.ByteString)]
makeQS appKey appSecret method path params body ts =
let
allParams = sortWith fst $ params ++
[ ("auth_key", appKey)
, ("auth_timestamp", BC.pack $ show ts)
, ("auth_version", "1.0")
, ("body_md5", B16.encode (MD5.hash body))
]
authSig = authSignature appSecret $ B.intercalate "\n"
[ encodeUtf8 method
, encodeUtf8 path
, formQueryString allParams
]
in
("auth_signature", authSig) : allParams
formQueryString :: [(B.ByteString, B.ByteString)] -> B.ByteString
formQueryString =
B.intercalate "&" . map (\(a, b) -> a <> "=" <> b)
authSignature :: B.ByteString -> B.ByteString -> B.ByteString
authSignature appSecret authString =
B16.encode $ HMAC.hmac SHA256.hash 64 appSecret authString
authenticatePrivate
:: Credentials -> B.ByteString -> B.ByteString -> B.ByteString
authenticatePrivate cred socketID channelName =
let
sig = authSignature
(credentialsAppSecret cred)
(socketID <> ":" <> channelName)
in
credentialsAppKey cred <> ":" <> sig
authenticatePresence
:: A.ToJSON a
=> Credentials -> B.ByteString -> B.ByteString -> a -> B.ByteString
authenticatePresence =
authenticatePresenceWithEncoder (BL.toStrict . A.encode)
authenticatePresenceWithEncoder
:: A.ToJSON a
=> (a -> B.ByteString)
-> Credentials
-> B.ByteString
-> B.ByteString
-> a
-> B.ByteString
authenticatePresenceWithEncoder userEncoder cred socketID channelName userData =
let
sig = authSignature (credentialsAppSecret cred)
( socketID <> ":"
<> channelName <> ":"
<> userEncoder userData
)
in
credentialsAppKey cred <> ":" <> sig