File: Session.hs

package info (click to toggle)
haskell-tls 2.1.8-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,056 kB
  • sloc: haskell: 15,695; makefile: 3
file content (92 lines) | stat: -rw-r--r-- 3,354 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
{-# OPTIONS_GHC -Wno-orphans #-}

module Session (
    readClientSessionRef,
    clearClientSessionRef,
    twoSessionRefs,
    twoSessionManagers,
    setPairParamsSessionManagers,
    setPairParamsSessionResuming,
    oneSessionTicket,
) where

import Codec.Serialise
import Control.Monad
import qualified Data.ByteString.Lazy as L
import Data.IORef
import Network.TLS
import Network.TLS.Internal

----------------------------------------------------------------

readClientSessionRef :: (IORef (Maybe c), IORef (Maybe s)) -> IO (Maybe c)
readClientSessionRef refs = readIORef (fst refs)

clearClientSessionRef :: (IORef (Maybe c), IORef (Maybe s)) -> IO ()
clearClientSessionRef refs = writeIORef (fst refs) Nothing

twoSessionRefs :: IO (IORef (Maybe client), IORef (Maybe server))
twoSessionRefs = (,) <$> newIORef Nothing <*> newIORef Nothing

-- | simple session manager to store one session id and session data for a single thread.
-- a Real concurrent session manager would use an MVar and have multiples items.
oneSessionManager :: IORef (Maybe (SessionID, SessionData)) -> SessionManager
oneSessionManager ref =
    noSessionManager
        { sessionResume = \myId -> readIORef ref >>= maybeResume False myId
        , sessionResumeOnlyOnce = \myId -> readIORef ref >>= maybeResume True myId
        , sessionEstablish = \myId dat -> writeIORef ref (Just (myId, dat)) >> return Nothing
        , sessionInvalidate = \_ -> return ()
        , sessionUseTicket = False
        }
  where
    maybeResume onlyOnce myId (Just (sid, sdata))
        | sid == myId = when onlyOnce (writeIORef ref Nothing) >> return (Just sdata)
    maybeResume _ _ _ = return Nothing

twoSessionManagers
    :: (IORef (Maybe (SessionID, SessionData)), IORef (Maybe (SessionID, SessionData)))
    -> (SessionManager, SessionManager)
twoSessionManagers (cRef, sRef) = (oneSessionManager cRef, oneSessionManager sRef)

setPairParamsSessionManagers
    :: (SessionManager, SessionManager)
    -> (ClientParams, ServerParams)
    -> (ClientParams, ServerParams)
setPairParamsSessionManagers (clientManager, serverManager) (clientParams, serverParams) = (nc, ns)
  where
    nc =
        clientParams
            { clientShared = updateSessionManager clientManager $ clientShared clientParams
            }
    ns =
        serverParams
            { serverShared = updateSessionManager serverManager $ serverShared serverParams
            }
    updateSessionManager manager shared = shared{sharedSessionManager = manager}

----------------------------------------------------------------

setPairParamsSessionResuming
    :: (SessionID, SessionData)
    -> (ClientParams, ServerParams)
    -> (ClientParams, ServerParams)
setPairParamsSessionResuming sessionStuff (clientParams, serverParams) =
    ( clientParams{clientWantSessionResume = Just sessionStuff}
    , serverParams
    )

oneSessionTicket :: SessionManager
oneSessionTicket =
    noSessionManager
        { sessionResume = resume
        , sessionResumeOnlyOnce = resume
        , sessionEstablish = \_ dat -> return $ Just $ L.toStrict $ serialise dat
        , sessionInvalidate = \_ -> return ()
        , sessionUseTicket = True
        }

resume :: Ticket -> IO (Maybe SessionData)
resume ticket
    | isTicket ticket = return $ Just $ deserialise $ L.fromStrict ticket
    | otherwise = return Nothing