diff options
-rw-r--r-- | ToxToXMPP.hs | 120 |
1 files changed, 94 insertions, 26 deletions
diff --git a/ToxToXMPP.hs b/ToxToXMPP.hs index 8d28507a..8c57da5a 100644 --- a/ToxToXMPP.hs +++ b/ToxToXMPP.hs | |||
@@ -1,8 +1,8 @@ | |||
1 | {-# LANGUAGE ViewPatterns #-} | ||
2 | {-# LANGUAGE CPP #-} | 1 | {-# LANGUAGE CPP #-} |
3 | {-# LANGUAGE LambdaCase #-} | 2 | {-# LANGUAGE LambdaCase #-} |
4 | {-# LANGUAGE NamedFieldPuns #-} | 3 | {-# LANGUAGE NamedFieldPuns #-} |
5 | {-# LANGUAGE NondecreasingIndentation #-} | 4 | {-# LANGUAGE NondecreasingIndentation #-} |
5 | {-# LANGUAGE ViewPatterns #-} | ||
6 | module ToxToXMPP | 6 | module ToxToXMPP |
7 | ( forkAccountWatcher | 7 | ( forkAccountWatcher |
8 | , JabberClients | 8 | , JabberClients |
@@ -20,14 +20,15 @@ import qualified Data.Conduit.List as CL | |||
20 | import Data.XML.Types as XML | 20 | import Data.XML.Types as XML |
21 | import EventUtil | 21 | import EventUtil |
22 | import Network.Tox.Crypto.Transport as Tox | 22 | import Network.Tox.Crypto.Transport as Tox |
23 | import Network.Tox.Handshake (HandshakeParams (..)) | ||
23 | import Util (unsplitJID) | 24 | import Util (unsplitJID) |
24 | import XMPPServer as XMPP | 25 | import XMPPServer as XMPP |
25 | 26 | ||
26 | import Network.Tox.DHT.Handlers (nodeSearch, nodesOfInterest) | ||
27 | import Announcer | 27 | import Announcer |
28 | import Announcer.Tox | 28 | import Announcer.Tox |
29 | import Connection | 29 | import Connection |
30 | import Network.QueryResponse | 30 | import Network.QueryResponse |
31 | import Network.Tox.DHT.Handlers (nodeSearch, nodesOfInterest) | ||
31 | -- import Control.Concurrent | 32 | -- import Control.Concurrent |
32 | import Control.Concurrent.STM | 33 | import Control.Concurrent.STM |
33 | import Control.Monad | 34 | import Control.Monad |
@@ -42,6 +43,7 @@ import Network.Kademlia.Search | |||
42 | import qualified Network.Tox as Tox | 43 | import qualified Network.Tox as Tox |
43 | import Network.Tox.ContactInfo as Tox | 44 | import Network.Tox.ContactInfo as Tox |
44 | import qualified Network.Tox.Crypto.Handlers as Tox | 45 | import qualified Network.Tox.Crypto.Handlers as Tox |
46 | ;import Network.Tox.Crypto.Handlers (UponCookie (..)) | ||
45 | -- import qualified Network.Tox.DHT.Handlers as Tox | 47 | -- import qualified Network.Tox.DHT.Handlers as Tox |
46 | import ClientState | 48 | import ClientState |
47 | import Data.Bits | 49 | import Data.Bits |
@@ -69,6 +71,7 @@ import GHC.Conc (labelThread) | |||
69 | #endif | 71 | #endif |
70 | import DPut | 72 | import DPut |
71 | import Nesting | 73 | import Nesting |
74 | import qualified Network.Tox.DHT.Handlers | ||
72 | 75 | ||
73 | xmppToTox :: Conduit XML.Event IO Tox.CryptoMessage | 76 | xmppToTox :: Conduit XML.Event IO Tox.CryptoMessage |
74 | xmppToTox = doNestingXML $ do | 77 | xmppToTox = doNestingXML $ do |
@@ -159,22 +162,39 @@ gotDhtPubkey pubkey tx theirKey = do | |||
159 | now <- getPOSIXTime | 162 | now <- getPOSIXTime |
160 | when (now - tm > nodeinfoStaleTime) doSearch | 163 | when (now - tm > nodeinfoStaleTime) doSearch |
161 | where | 164 | where |
165 | tox :: Tox JabberClients | ||
166 | tox = txTox tx | ||
167 | |||
168 | myPublicKey = toPublic $ userSecret (txAccount tx) | ||
169 | me = key2id myPublicKey | ||
170 | |||
162 | doSearch = do | 171 | doSearch = do |
163 | let pub = toPublic $ userSecret (txAccount tx) | ||
164 | me = key2id pub | ||
165 | akey <- akeyConnect (txAnnouncer tx) me theirKey | 172 | akey <- akeyConnect (txAnnouncer tx) me theirKey |
166 | atomically $ registerNodeCallback (toxRouting tox) (nic akey) | 173 | atomically $ registerNodeCallback (toxRouting tox) (nic akey) |
167 | scheduleSearch (txAnnouncer tx) akey meth pubkey | 174 | scheduleSearch (txAnnouncer tx) akey meth pubkey |
168 | tox :: Tox JabberClients | 175 | |
169 | tox = txTox tx | ||
170 | byAddr :: TVar (Map.Map SockAddr Tox.NetCryptoSession) | 176 | byAddr :: TVar (Map.Map SockAddr Tox.NetCryptoSession) |
171 | byAddr = Tox.netCryptoSessions (toxCryptoSessions tox) | 177 | byAddr = Tox.netCryptoSessions (toxCryptoSessions tox) |
178 | |||
179 | crypto = Tox.transportCrypto $ toxCryptoSessions tox | ||
180 | |||
181 | readNcVar :: (Tox.NetCryptoSession -> TVar b) -> SockAddr -> STM (Maybe b) | ||
182 | readNcVar v addr = traverse readTVar =<< fmap v . Map.lookup addr <$> readTVar byAddr | ||
183 | |||
172 | chillSesh :: SockAddr -> STM (Maybe (Status Tox.ToxProgress)) | 184 | chillSesh :: SockAddr -> STM (Maybe (Status Tox.ToxProgress)) |
173 | chillSesh addr = traverse readTVar =<< fmap Tox.ncState . Map.lookup addr <$> readTVar byAddr | 185 | chillSesh = readNcVar Tox.ncState |
186 | |||
174 | activeSesh :: SockAddr -> STM Bool | 187 | activeSesh :: SockAddr -> STM Bool |
175 | activeSesh a = chillSesh a >>= return . \case | 188 | activeSesh a = chillSesh a >>= return . \case |
176 | Just Established -> True | 189 | Just Established -> True |
177 | _ -> False | 190 | _ -> False |
191 | |||
192 | readCookie :: SockAddr -> STM (Maybe (UponCookie (Tox.Cookie Encrypted))) | ||
193 | readCookie = readNcVar Tox.ncCookie | ||
194 | readCookie' :: SockAddr -> STM (Maybe (Tox.Cookie Encrypted)) | ||
195 | readCookie' = fmap join . (fmap.fmap) Tox.toMaybe . readCookie | ||
196 | |||
197 | target :: NodeId | ||
178 | target = key2id $ dhtpk pubkey | 198 | target = key2id $ dhtpk pubkey |
179 | meth :: SearchMethod Tox.DHTPublicKey | 199 | meth :: SearchMethod Tox.DHTPublicKey |
180 | meth = | 200 | meth = |
@@ -193,36 +213,84 @@ gotDhtPubkey pubkey tx theirKey = do | |||
193 | , rumoredAddress = assume akey | 213 | , rumoredAddress = assume akey |
194 | } | 214 | } |
195 | 215 | ||
216 | client :: Network.Tox.DHT.Handlers.Client | ||
217 | client = toxDHT tox | ||
218 | |||
196 | assume :: AnnounceKey -> POSIXTime -> SockAddr -> NodeInfo -> STM () | 219 | assume :: AnnounceKey -> POSIXTime -> SockAddr -> NodeInfo -> STM () |
197 | assume akey time addr ni = | 220 | assume akey time addr ni = |
198 | tput XNodeinfoSearch $ show ("rumor", akey, time, addr, ni) | 221 | tput XNodeinfoSearch $ show ("rumor", akey, time, addr, ni) |
199 | 222 | ||
200 | observe :: AnnounceKey -> POSIXTime -> NodeInfo -> STM () | 223 | observe :: AnnounceKey -> POSIXTime -> NodeInfo -> STM () |
201 | observe akey time (nodeAddr -> addr) = do | 224 | observe akey time ni@(nodeAddr -> addr) = do |
202 | tput XNodeinfoSearch $ show ("observation", akey, time, addr) | 225 | tput XNodeinfoSearch $ show ("observation", akey, time, addr) |
203 | scheduleImmediately (txAnnouncer tx) akey $ | 226 | scheduleImmediately (txAnnouncer tx) akey $ |
204 | ScheduledItem $ shakeHands (activeSesh addr) (getContact theirKey (txAccount tx)) | 227 | ScheduledItem $ getCookie ni (activeSesh addr) (getContact theirKey (txAccount tx)) |
205 | setContactAddr time theirKey addr (txAccount tx) | 228 | setContactAddr time theirKey addr (txAccount tx) |
206 | 229 | ||
207 | shakeHands :: STM Bool -> STM (Maybe Contact) -> Announcer -> AnnounceKey -> POSIXTime -> STM (IO ()) | 230 | getCookie |
208 | shakeHands isActive getC ann akey now = do | 231 | :: NodeInfo |
209 | mbContact <- getC | 232 | -> STM Bool |
210 | case mbContact of | 233 | -> STM (Maybe Contact) |
211 | Nothing -> return $ return () | 234 | -> Announcer |
212 | Just contact -> do | 235 | -> AnnounceKey |
213 | active <- isActive | 236 | -> POSIXTime |
214 | if (not active) then do | 237 | -> STM (IO ()) |
215 | scheduleRel ann akey (ScheduledItem $ shakeHands isActive getC) 5 | 238 | getCookie ni isActive getC ann akey now = fix $ \goBack -> do |
216 | return $ shakeHandsIO contact | 239 | mbContact <- getC |
217 | else | 240 | case mbContact of |
218 | return $ return () | 241 | Nothing -> return $ return () |
219 | 242 | Just contact -> do | |
220 | shakeHandsIO :: Contact -> IO () | 243 | active <- isActive |
221 | shakeHandsIO _ = return () | 244 | return $ when (not active) (getCookieIO goBack) |
245 | |||
246 | where | ||
247 | |||
248 | callRealShakeHands = realShakeHands (userSecret (txAccount tx)) theirKey (dhtpk pubkey) (toxCryptoSessions tox) (nodeAddr ni) | ||
249 | |||
250 | reschedule n f = scheduleRel ann akey f n | ||
251 | reschedule' n f = reschedule n (ScheduledItem $ \_ _ now -> f now) | ||
252 | |||
253 | cookieMaxAge = 60 * 5 | ||
254 | |||
255 | getCookieIO :: STM (IO ()) -> IO () | ||
256 | getCookieIO getCookieAgain = do | ||
257 | cookieRequest crypto client myPublicKey ni >>= \case | ||
258 | Nothing -> atomically $ reschedule' 5 (const getCookieAgain) | ||
259 | Just cookie -> do | ||
260 | void $ callRealShakeHands cookie | ||
261 | cookieCreationStamp <- getPOSIXTime | ||
262 | let shaker :: POSIXTime -> STM (IO ()) | ||
263 | shaker now = do | ||
264 | if (now > cookieCreationStamp + cookieMaxAge) | ||
265 | then return (getCookieIO getCookieAgain) | ||
266 | else do | ||
267 | reschedule' 5 shaker | ||
268 | return . void $ callRealShakeHands cookie | ||
269 | atomically $ reschedule' 5 shaker | ||
270 | |||
271 | realShakeHands :: SecretKey -> PublicKey -> PublicKey -> Tox.NetCryptoSessions -> SockAddr -> Tox.Cookie Encrypted -> IO Bool | ||
272 | realShakeHands myseckey theirpubkey theirDhtKey allsessions saddr cookie = do | ||
273 | let hp = | ||
274 | HParam | ||
275 | { hpOtherCookie = cookie | ||
276 | , hpMySecretKey = myseckey | ||
277 | , hpCookieRemotePubkey = theirpubkey | ||
278 | , hpCookieRemoteDhtkey = theirDhtKey | ||
279 | , hpTheirBaseNonce = Nothing | ||
280 | , hpTheirSessionKeyPublic = Nothing | ||
281 | } | ||
282 | newsession <- generateSecretKey | ||
283 | timestamp <- getPOSIXTime | ||
284 | (myhandshake, ioAction) <- | ||
285 | atomically $ | ||
286 | Tox.freshCryptoSession allsessions saddr newsession timestamp hp | ||
287 | ioAction | ||
288 | -- send handshake | ||
289 | isJust <$> forM myhandshake (Tox.sendHandshake allsessions saddr) | ||
222 | 290 | ||
223 | dispatch :: ToxToXMPP -> ContactEvent -> IO () | 291 | dispatch :: ToxToXMPP -> ContactEvent -> IO () |
224 | dispatch tx (SessionEstablished theirKey) = stopConnecting tx theirKey | 292 | dispatch tx (SessionEstablished theirKey) = stopConnecting tx theirKey |
225 | dispatch tx (SessionTerminated theirKey) = startConnecting tx theirKey | 293 | dispatch tx (SessionTerminated theirKey) = startConnecting tx theirKey |
226 | dispatch tx (AddrChange theirkey saddr) = return () -- todo | 294 | dispatch tx (AddrChange theirkey saddr) = return () -- todo |
227 | dispatch tx (PolicyChange theirkey TryingToConnect ) = startConnecting tx theirkey | 295 | dispatch tx (PolicyChange theirkey TryingToConnect ) = startConnecting tx theirkey |
228 | dispatch tx (PolicyChange theirkey policy ) = stopConnecting tx theirkey | 296 | dispatch tx (PolicyChange theirkey policy ) = stopConnecting tx theirkey |