diff options
author | James Crayne <jim.crayne@gmail.com> | 2019-09-28 13:43:29 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-01 19:27:53 -0500 |
commit | 11987749fc6e6d3e53ea737d46d5ab13a16faeb8 (patch) | |
tree | 5716463275c2d3e902889db619908ded2a73971c /dht/HandshakeCache.hs | |
parent | add2c76bced51fde5e9917e7449ef52be70faf87 (diff) |
Factor out some new libraries
word64-map:
Data.Word64Map
network-addr:
Network.Address
tox-crypto:
Crypto.Tox
lifted-concurrent:
Control.Concurrent.Lifted.Instrument
Control.Concurrent.Async.Lifted.Instrument
psq-wrap:
Data.Wrapper.PSQInt
Data.Wrapper.PSQ
minmax-psq:
Data.MinMaxPSQ
tasks:
Control.Concurrent.Tasks
kad:
Network.Kademlia
Network.Kademlia.Bootstrap
Network.Kademlia.Routing
Network.Kademlia.CommonAPI
Network.Kademlia.Persistence
Network.Kademlia.Search
Diffstat (limited to 'dht/HandshakeCache.hs')
-rw-r--r-- | dht/HandshakeCache.hs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/dht/HandshakeCache.hs b/dht/HandshakeCache.hs new file mode 100644 index 00000000..61735e8a --- /dev/null +++ b/dht/HandshakeCache.hs | |||
@@ -0,0 +1,132 @@ | |||
1 | module HandshakeCache where | ||
2 | |||
3 | import Control.Concurrent.STM | ||
4 | import Control.Monad | ||
5 | import Data.Functor.Identity | ||
6 | import qualified Data.Map.Strict as Map | ||
7 | ;import Data.Map.Strict (Map) | ||
8 | import Data.Time.Clock.POSIX | ||
9 | import Network.Socket | ||
10 | import Data.Bool | ||
11 | |||
12 | import Crypto.Hash | ||
13 | |||
14 | import Crypto.Tox | ||
15 | import qualified Data.MinMaxPSQ as MM | ||
16 | ;import Data.MinMaxPSQ (MinMaxPSQ') | ||
17 | import DPut | ||
18 | import DebugTag | ||
19 | import Network.Tox.Crypto.Transport (Handshake, HandshakeData (..)) | ||
20 | import Network.Tox.DHT.Handlers (createCookieSTM) | ||
21 | import Network.Tox.DHT.Transport (Cookie (..), CookieData (..), NodeInfo, | ||
22 | key2id, nodeInfo) | ||
23 | import Network.Tox.Handshake | ||
24 | |||
25 | data HandshakeCache = HandshakeCache | ||
26 | { -- Note that currently we are storing sent handshakes keyed by the | ||
27 | -- locally issued cookie nonce. | ||
28 | hscTable :: TVar (MinMaxPSQ' Nonce24 POSIXTime (SecretKey,HandshakeData)) | ||
29 | , hscSend :: SockAddr -> Handshake Encrypted -> IO () | ||
30 | , hscCrypto :: TransportCrypto | ||
31 | , hscPendingCookies :: TVar (Map (PublicKey,PublicKey) ()) | ||
32 | } | ||
33 | |||
34 | |||
35 | newHandshakeCache :: TransportCrypto -> (SockAddr -> Handshake Encrypted -> IO ()) -> IO HandshakeCache | ||
36 | newHandshakeCache crypto send = atomically $ do | ||
37 | tbl <- newTVar MM.empty | ||
38 | pcs <- newTVar Map.empty | ||
39 | return HandshakeCache | ||
40 | { hscTable = tbl | ||
41 | , hscSend = send | ||
42 | , hscCrypto = crypto | ||
43 | , hscPendingCookies = pcs | ||
44 | } | ||
45 | |||
46 | getSentHandshake :: HandshakeCache | ||
47 | -> SecretKey | ||
48 | -> SockAddr | ||
49 | -> Cookie Identity -- locally issued | ||
50 | -> Cookie Encrypted -- remotely issued | ||
51 | -> IO (Maybe (SecretKey, HandshakeData)) | ||
52 | getSentHandshake hscache me their_addr (Cookie n24 (Identity cd)) ecookie = do | ||
53 | now <- getPOSIXTime | ||
54 | io <- atomically $ do | ||
55 | m <- checkExpiry now . MM.lookup' n24 <$> readTVar (hscTable hscache) | ||
56 | case m of | ||
57 | Just s -> return $ return $ Just s | ||
58 | Nothing -> do | ||
59 | let them = longTermKey cd | ||
60 | case nodeInfo (key2id $ dhtKey cd) their_addr of | ||
61 | Left _ -> return $ return Nothing -- Non-internet address. | ||
62 | Right their_node -> do | ||
63 | (s,hs) <- cacheHandshakeSTM hscache me them their_node ecookie now | ||
64 | return $ do | ||
65 | dput XNetCrypto $ "getSentHandshake sending new handshake." | ||
66 | hscSend hscache their_addr hs | ||
67 | return $ Just s | ||
68 | r <- io | ||
69 | dput XNetCrypto $ "getSentHandshake me="++show (key2id $ toPublic me)++" their_addr="++show their_addr++" --> " ++ show r | ||
70 | return r | ||
71 | |||
72 | |||
73 | checkExpiry :: POSIXTime -> Maybe (POSIXTime,r) -> Maybe r | ||
74 | checkExpiry now m = do | ||
75 | (tm,s) <- m | ||
76 | guard $ tm + 5 {- seconds -} > now | ||
77 | return s | ||
78 | |||
79 | hashCookie :: HashAlgorithm a => Cookie Encrypted -> Digest a | ||
80 | hashCookie (Cookie n24 encrypted) | ||
81 | = hashFinalize $ hashUpdate (hashUpdate hashInit n24) encrypted | ||
82 | |||
83 | cacheHandshakeSTM :: HandshakeCache | ||
84 | -> SecretKey -- ^ my ToxID key | ||
85 | -> PublicKey -- ^ them | ||
86 | -> NodeInfo -- ^ their DHT node | ||
87 | -> Cookie Encrypted -- ^ issued to me by them | ||
88 | -> POSIXTime -- ^ current time | ||
89 | -> STM ((SecretKey,HandshakeData), Handshake Encrypted) | ||
90 | cacheHandshakeSTM hscache me them their_node ecookie timestamp = do | ||
91 | newsession <- transportNewKey (hscCrypto hscache) | ||
92 | freshCookie <- createCookieSTM timestamp (hscCrypto hscache) their_node them | ||
93 | n24 <- transportNewNonce (hscCrypto hscache) | ||
94 | let hsdata = HandshakeData | ||
95 | { baseNonce = n24 | ||
96 | , sessionKey = toPublic newsession | ||
97 | , cookieHash = hashCookie ecookie | ||
98 | , otherCookie = freshCookie | ||
99 | } | ||
100 | hs <- encodeHandshake timestamp (hscCrypto hscache) me them ecookie hsdata | ||
101 | let Cookie cnonce _ = freshCookie | ||
102 | modifyTVar' (hscTable hscache) $ MM.insertTake' 20 cnonce (newsession,hsdata) timestamp | ||
103 | return ((newsession,hsdata),hs) | ||
104 | |||
105 | cacheHandshake :: HandshakeCache | ||
106 | -> SecretKey | ||
107 | -> PublicKey | ||
108 | -> NodeInfo | ||
109 | -> Cookie Encrypted | ||
110 | -> IO (Handshake Encrypted) | ||
111 | cacheHandshake hscache me them their_node ecookie = do | ||
112 | timestamp <- getPOSIXTime | ||
113 | dput XNetCrypto $ "cacheHandshake " ++ show (key2id them,ecookie) | ||
114 | atomically $ snd <$> cacheHandshakeSTM hscache me them their_node ecookie timestamp | ||
115 | |||
116 | haveCachedCookie :: HandshakeCache | ||
117 | -> PublicKey | ||
118 | -> PublicKey | ||
119 | -> STM Bool | ||
120 | haveCachedCookie hscache me them = do | ||
121 | m <- Map.lookup (me,them) <$> readTVar (hscPendingCookies hscache) | ||
122 | return $ maybe True (const False) m | ||
123 | |||
124 | |||
125 | setPendingCookie :: HandshakeCache | ||
126 | -> PublicKey | ||
127 | -> PublicKey | ||
128 | -> Bool | ||
129 | -> STM () | ||
130 | setPendingCookie hscache me them pending = do | ||
131 | modifyTVar' (hscPendingCookies hscache) $ Map.alter (const $ bool Nothing (Just ()) pending) | ||
132 | (me,them) | ||