aboutsummaryrefslogtreecommitdiff
path: root/Assistant/Threads
diff options
context:
space:
mode:
Diffstat (limited to 'Assistant/Threads')
-rw-r--r--Assistant/Threads/PairListener.hs154
-rw-r--r--Assistant/Threads/WebApp.hs137
2 files changed, 0 insertions, 291 deletions
diff --git a/Assistant/Threads/PairListener.hs b/Assistant/Threads/PairListener.hs
deleted file mode 100644
index 09eaf1fe8..000000000
--- a/Assistant/Threads/PairListener.hs
+++ /dev/null
@@ -1,154 +0,0 @@
-{- git-annex assistant thread to listen for incoming pairing traffic
- -
- - Copyright 2012 Joey Hess <id@joeyh.name>
- -
- - Licensed under the GNU GPL version 3 or higher.
- -}
-
-module Assistant.Threads.PairListener where
-
-import Assistant.Common
-import Assistant.Pairing
-import Assistant.Pairing.Network
-import Assistant.Pairing.MakeRemote
-import Assistant.WebApp (UrlRenderer)
-import Assistant.WebApp.Types
-import Assistant.Alert
-import Assistant.DaemonStatus
-import Utility.ThreadScheduler
-import Git
-
-import Network.Multicast
-import Network.Socket
-import qualified Data.ByteString as B
-import qualified Data.ByteString.UTF8 as BU8
-import qualified Network.Socket.ByteString as B
-import qualified Data.Text as T
-
-pairListenerThread :: UrlRenderer -> NamedThread
-pairListenerThread urlrenderer = namedThread "PairListener" $ do
- listener <- asIO1 $ go [] []
- liftIO $ withSocketsDo $
- runEvery (Seconds 60) $ void $ tryIO $
- listener =<< getsock
- where
- {- Note this can crash if there's no network interface,
- - or only one like lo that doesn't support multicast. -}
- getsock = multicastReceiver (multicastAddress IPv4AddrClass) pairingPort
-
- go reqs cache sock = liftIO (getmsg sock B.empty) >>= \msg -> case readish (BU8.toString msg) of
- Nothing -> go reqs cache sock
- Just m -> do
- debug ["received", show msg]
- (pip, verified) <- verificationCheck m
- =<< (pairingInProgress <$> getDaemonStatus)
- let wrongstage = maybe False (\p -> pairMsgStage m <= inProgressPairStage p) pip
- let fromus = maybe False (\p -> remoteSshPubKey (pairMsgData m) == remoteSshPubKey (inProgressPairData p)) pip
- case (wrongstage, fromus, checkSane (pairMsgData m), pairMsgStage m) of
- (_, True, _, _) -> do
- debug ["ignoring message that looped back"]
- go reqs cache sock
- (_, _, False, _) -> do
- liftAnnex $ warning $
- "illegal control characters in pairing message; ignoring (" ++ show (pairMsgData m) ++ ")"
- go reqs cache sock
- -- PairReq starts a pairing process, so a
- -- new one is always heeded, even if
- -- some other pairing is in process.
- (_, _, _, PairReq) -> if m `elem` reqs
- then go reqs (invalidateCache m cache) sock
- else do
- pairReqReceived verified urlrenderer m
- go (m:take 10 reqs) (invalidateCache m cache) sock
- (True, _, _, _) -> do
- debug
- ["ignoring out of order message"
- , show (pairMsgStage m)
- , "expected"
- , show (succ . inProgressPairStage <$> pip)
- ]
- go reqs cache sock
- (_, _, _, PairAck) -> do
- cache' <- pairAckReceived verified pip m cache
- go reqs cache' sock
- (_,_ , _, PairDone) -> do
- pairDoneReceived verified pip m
- go reqs cache sock
-
- {- As well as verifying the message using the shared secret,
- - check its UUID against the UUID we have stored. If
- - they're the same, someone is sending bogus messages,
- - which could be an attempt to brute force the shared secret. -}
- verificationCheck _ Nothing = return (Nothing, False)
- verificationCheck m (Just pip)
- | not verified && sameuuid = do
- liftAnnex $ warning
- "detected possible pairing brute force attempt; disabled pairing"
- stopSending pip
- return (Nothing, False)
- | otherwise = return (Just pip, verified && sameuuid)
- where
- verified = verifiedPairMsg m pip
- sameuuid = pairUUID (inProgressPairData pip) == pairUUID (pairMsgData m)
-
- {- PairReqs invalidate the cache of recently finished pairings.
- - This is so that, if a new pairing is started with the
- - same secret used before, a bogus PairDone is not sent. -}
- invalidateCache msg = filter (not . verifiedPairMsg msg)
-
- getmsg sock c = do
- (msg, _) <- B.recvFrom sock chunksz
- if B.length msg < chunksz
- then return $ c <> msg
- else getmsg sock $ c <> msg
- where
- chunksz = 1024
-
-{- Show an alert when a PairReq is seen. -}
-pairReqReceived :: Bool -> UrlRenderer -> PairMsg -> Assistant ()
-pairReqReceived True _ _ = noop -- ignore our own PairReq
-pairReqReceived False urlrenderer msg = do
- button <- mkAlertButton True (T.pack "Respond") urlrenderer (FinishLocalPairR msg)
- void $ addAlert $ pairRequestReceivedAlert repo button
- where
- repo = pairRepo msg
-
-{- When a verified PairAck is seen, a host is ready to pair with us, and has
- - already configured our ssh key. Stop sending PairReqs, finish the pairing,
- - and send a single PairDone. -}
-pairAckReceived :: Bool -> Maybe PairingInProgress -> PairMsg -> [PairingInProgress] -> Assistant [PairingInProgress]
-pairAckReceived True (Just pip) msg cache = do
- stopSending pip
- repodir <- repoPath <$> liftAnnex gitRepo
- liftIO $ setupAuthorizedKeys msg repodir
- finishedLocalPairing msg (inProgressSshKeyPair pip)
- startSending pip PairDone $ multicastPairMsg
- (Just 1) (inProgressSecret pip) (inProgressPairData pip)
- return $ pip : take 10 cache
-{- A stale PairAck might also be seen, after we've finished pairing.
- - Perhaps our PairDone was not received. To handle this, we keep
- - a cache of recently finished pairings, and re-send PairDone in
- - response to stale PairAcks for them. -}
-pairAckReceived _ _ msg cache = do
- let pips = filter (verifiedPairMsg msg) cache
- unless (null pips) $
- forM_ pips $ \pip ->
- startSending pip PairDone $ multicastPairMsg
- (Just 1) (inProgressSecret pip) (inProgressPairData pip)
- return cache
-
-{- If we get a verified PairDone, the host has accepted our PairAck, and
- - has paired with us. Stop sending PairAcks, and finish pairing with them.
- -
- - TODO: Should third-party hosts remove their pair request alert when they
- - see a PairDone?
- - Complication: The user could have already clicked on the alert and be
- - entering the secret. Would be better to start a fresh pair request in this
- - situation.
- -}
-pairDoneReceived :: Bool -> Maybe PairingInProgress -> PairMsg -> Assistant ()
-pairDoneReceived False _ _ = noop -- not verified
-pairDoneReceived True Nothing _ = noop -- not in progress
-pairDoneReceived True (Just pip) msg = do
- stopSending pip
- finishedLocalPairing msg (inProgressSshKeyPair pip)
diff --git a/Assistant/Threads/WebApp.hs b/Assistant/Threads/WebApp.hs
deleted file mode 100644
index dfb631bc6..000000000
--- a/Assistant/Threads/WebApp.hs
+++ /dev/null
@@ -1,137 +0,0 @@
-{- git-annex assistant webapp thread
- -
- - Copyright 2012-2014 Joey Hess <id@joeyh.name>
- -
- - Licensed under the GNU GPL version 3 or higher.
- -}
-
-{-# LANGUAGE TemplateHaskell, MultiParamTypeClasses #-}
-{-# LANGUAGE ViewPatterns, OverloadedStrings #-}
-{-# LANGUAGE CPP #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-
-module Assistant.Threads.WebApp where
-
-import Assistant.Common
-import Assistant.WebApp
-import Assistant.WebApp.Types
-import Assistant.WebApp.DashBoard
-import Assistant.WebApp.SideBar
-import Assistant.WebApp.Notifications
-import Assistant.WebApp.RepoList
-import Assistant.WebApp.Configurators
-import Assistant.WebApp.Configurators.Local
-import Assistant.WebApp.Configurators.Ssh
-import Assistant.WebApp.Configurators.Pairing
-import Assistant.WebApp.Configurators.AWS
-import Assistant.WebApp.Configurators.IA
-import Assistant.WebApp.Configurators.WebDAV
-import Assistant.WebApp.Configurators.Preferences
-import Assistant.WebApp.Configurators.Unused
-import Assistant.WebApp.Configurators.Edit
-import Assistant.WebApp.Configurators.Delete
-import Assistant.WebApp.Configurators.Fsck
-import Assistant.WebApp.Configurators.Upgrade
-import Assistant.WebApp.Documentation
-import Assistant.WebApp.Control
-import Assistant.WebApp.OtherRepos
-import Assistant.WebApp.Repair
-import Assistant.WebApp.Pairing
-import Assistant.Types.ThreadedMonad
-import Utility.WebApp
-import Utility.AuthToken
-import Utility.Tmp
-import Utility.FileMode
-import Git
-import qualified Annex
-
-import Yesod
-import Network.Socket (SockAddr, HostName)
-import Data.Text (pack, unpack)
-import qualified Network.Wai.Handler.WarpTLS as TLS
-import Network.Wai.Middleware.RequestLogger
-
-mkYesodDispatch "WebApp" $(parseRoutesFile "Assistant/WebApp/routes")
-
-type Url = String
-
-webAppThread
- :: AssistantData
- -> UrlRenderer
- -> Bool
- -> Maybe String
- -> Maybe (IO Url)
- -> Maybe HostName
- -> Maybe (Url -> FilePath -> IO ())
- -> NamedThread
-webAppThread assistantdata urlrenderer noannex cannotrun postfirstrun listenhost onstartup = thread $ liftIO $ do
- listenhost' <- if isJust listenhost
- then pure listenhost
- else getAnnex $ annexListen <$> Annex.getGitConfig
- tlssettings <- getAnnex getTlsSettings
-#ifdef __ANDROID__
- when (isJust listenhost') $
- -- See Utility.WebApp
- giveup "Sorry, --listen is not currently supported on Android"
-#endif
- webapp <- WebApp
- <$> pure assistantdata
- <*> genAuthToken 128
- <*> getreldir
- <*> pure staticRoutes
- <*> pure postfirstrun
- <*> pure cannotrun
- <*> pure noannex
- <*> pure listenhost'
- <*> newWormholePairingState
- setUrlRenderer urlrenderer $ yesodRender webapp (pack "")
- app <- toWaiAppPlain webapp
- app' <- ifM debugEnabled
- ( return $ logStdout app
- , return app
- )
- runWebApp tlssettings listenhost' app' $ \addr -> if noannex
- then withTmpFile "webapp.html" $ \tmpfile h -> do
- hClose h
- go tlssettings addr webapp tmpfile Nothing
- else do
- htmlshim <- getAnnex' $ fromRepo gitAnnexHtmlShim
- urlfile <- getAnnex' $ fromRepo gitAnnexUrlFile
- go tlssettings addr webapp htmlshim (Just urlfile)
- where
- -- The webapp thread does not wait for the startupSanityCheckThread
- -- to finish, so that the user interface remains responsive while
- -- that's going on.
- thread = namedThreadUnchecked "WebApp"
- getreldir
- | noannex = return Nothing
- | otherwise = Just <$>
- (relHome =<< absPath
- =<< getAnnex' (fromRepo repoPath))
- go tlssettings addr webapp htmlshim urlfile = do
- let url = myUrl tlssettings webapp addr
- maybe noop (`writeFileProtected` url) urlfile
- writeHtmlShim "Starting webapp..." url htmlshim
- maybe noop (\a -> a url htmlshim) onstartup
-
- getAnnex a
- | noannex = pure Nothing
- | otherwise = getAnnex' a
- getAnnex' = runThreadState (threadState assistantdata)
-
-myUrl :: Maybe TLS.TLSSettings -> WebApp -> SockAddr -> Url
-myUrl tlssettings webapp addr = unpack $ yesodRender webapp urlbase DashboardR []
- where
- urlbase = pack $ proto ++ "://" ++ show addr
- proto
- | isJust tlssettings = "https"
- | otherwise = "http"
-
-getTlsSettings :: Annex (Maybe TLS.TLSSettings)
-getTlsSettings = do
- cert <- fromRepo gitAnnexWebCertificate
- privkey <- fromRepo gitAnnexWebPrivKey
- ifM (liftIO $ allM doesFileExist [cert, privkey])
- ( return $ Just $ TLS.tlsSettings cert privkey
- , return Nothing
- )