You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
4.6 KiB
116 lines
4.6 KiB
{-# OPTIONS_HADDOCK hide #-} |
|
{-# LANGUAGE OverloadedStrings #-} |
|
module Network.Xmpp.Session where |
|
|
|
import qualified Control.Exception as Ex |
|
import Control.Monad.Error |
|
import Data.Text as Text |
|
import Data.XML.Pickle |
|
import Data.XML.Types(Element) |
|
import Network |
|
import qualified Network.TLS as TLS |
|
import Network.Xmpp.Bind |
|
import Network.Xmpp.Concurrent.Types |
|
import Network.Xmpp.Concurrent |
|
import Network.Xmpp.Connection_ |
|
import Network.Xmpp.Marshal |
|
import Network.Xmpp.Pickle |
|
import Network.Xmpp.Sasl |
|
import Network.Xmpp.Sasl.Mechanisms |
|
import Network.Xmpp.Sasl.Types |
|
import Network.Xmpp.Stream |
|
import Network.Xmpp.Tls |
|
import Network.Xmpp.Types |
|
import Control.Concurrent.STM.TMVar |
|
import Data.Maybe |
|
|
|
-- | Creates a 'Session' object by setting up a connection with an XMPP server. |
|
-- |
|
-- Will connect to the specified host. If the fourth parameters is a 'Just' |
|
-- value, @session@ will attempt to secure the connection with TLS. If the fifth |
|
-- parameters is a 'Just' value, @session@ will attempt to authenticate and |
|
-- acquire an XMPP resource. |
|
session :: HostName -- ^ Host to connect to |
|
-> Text -- ^ The realm host name (to |
|
-- distinguish the XMPP service) |
|
-> PortID -- ^ Port to connect to |
|
-> Maybe TLS.TLSParams -- ^ TLS settings, if securing the |
|
-- connection to the server is |
|
-- desired |
|
-> Maybe ([SaslHandler], Maybe Text) -- ^ SASL handlers and the desired |
|
-- JID resource (or Nothing to let |
|
-- the server decide) |
|
-> IO (Either XmppFailure (Session, Maybe AuthFailure)) |
|
session hostname realm port tls sasl = runErrorT $ do |
|
con <- ErrorT $ connect hostname port realm |
|
case tls of |
|
Just tls' -> ErrorT $ startTls tls' con |
|
Nothing -> return () |
|
aut <- case sasl of |
|
Just sasl' -> ErrorT $ auth (fst sasl) (snd sasl) con |
|
Nothing -> return Nothing |
|
ses <- ErrorT $ newSession con |
|
return (ses, aut) |
|
|
|
-- | Connects to the XMPP server and opens the XMPP stream against the given |
|
-- host name, port, and realm. |
|
connect :: HostName -> PortID -> Text -> IO (Either XmppFailure (TMVar Connection)) |
|
connect address port hostname = do |
|
con <- connectTcp address port hostname |
|
case con of |
|
Right con' -> do |
|
result <- withConnection startStream con' |
|
return $ Right con' |
|
Left e -> do |
|
return $ Left e |
|
|
|
sessionXml :: Element |
|
sessionXml = pickleElem |
|
(xpElemBlank "{urn:ietf:params:xml:ns:xmpp-session}session") |
|
() |
|
|
|
sessionIQ :: Stanza |
|
sessionIQ = IQRequestS $ IQRequest { iqRequestID = "sess" |
|
, iqRequestFrom = Nothing |
|
, iqRequestTo = Nothing |
|
, iqRequestLangTag = Nothing |
|
, iqRequestType = Set |
|
, iqRequestPayload = sessionXml |
|
} |
|
|
|
-- Sends the session IQ set element and waits for an answer. Throws an error if |
|
-- if an IQ error stanza is returned from the server. |
|
startSession :: TMVar Connection -> IO () |
|
startSession con = do |
|
answer <- pushIQ' "session" Nothing Set Nothing sessionXml con |
|
case answer of |
|
Left e -> error $ show e |
|
Right _ -> return () |
|
|
|
-- | Authenticate to the server using the first matching method and bind a |
|
-- resource. |
|
auth :: [SaslHandler] |
|
-> Maybe Text |
|
-> TMVar Connection |
|
-> IO (Either XmppFailure (Maybe AuthFailure)) |
|
auth mechanisms resource con = runErrorT $ do |
|
ErrorT $ xmppSasl mechanisms con |
|
jid <- lift $ xmppBind resource con |
|
lift $ startSession con |
|
return Nothing |
|
|
|
-- | Authenticate to the server with the given username and password |
|
-- and bind a resource. |
|
-- |
|
-- Prefers SCRAM-SHA1 over DIGEST-MD5. |
|
simpleAuth :: Text.Text -- ^ The username |
|
-> Text.Text -- ^ The password |
|
-> Maybe Text -- ^ The desired resource or 'Nothing' to let the |
|
-- server assign one |
|
-> TMVar Connection |
|
-> IO (Either XmppFailure (Maybe AuthFailure)) |
|
simpleAuth username passwd resource = flip auth resource $ |
|
[ -- TODO: scramSha1Plus |
|
scramSha1 username Nothing passwd |
|
, digestMd5 username Nothing passwd |
|
]
|
|
|