git-annex/RemoteDaemon/Transport/Tor.hs
Joey Hess f1781d01d8
remotedaemon support for generic P2P transports
RemoteDaemon.Transport.Tor was refactored into this, and most of the
code is reused between them.

getSocketFile does not yet deal with repositories on crippled
filesystems that don't support sockets. Annex.Ssh detects that and
allows the user to set an environment variable, and something similar
could be done here.

And it does not deal with a situation where there is no path to the
socket file that is not too long. In that situation it would crash out
I suppose. Probably though, remotedaemon is ran from the top of the
repo, and in that case the path is just ".git/annex/p2p/<md5>" so nice
and short.

This seems to mostly work. But I don't yet have a working git-annex-p2p-
command to test it with.

And with my not quite working git-annex-p2p-foo test script, running
remotedaemon results in an ever-growing number of zombie processes
that it's not waiting on.
2025-07-31 14:45:32 -04:00

77 lines
2 KiB
Haskell

{- git-remote-daemon, tor hidden service server and transport
-
- Copyright 2016-2025 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
{-# LANGUAGE CPP #-}
module RemoteDaemon.Transport.Tor (server, transport, torSocketFile) where
import Annex.Common
import RemoteDaemon.Types
import RemoteDaemon.Common
import Utility.Tor
import P2P.IO
import P2P.Auth
import P2P.Address
import Annex.UUID
import qualified RemoteDaemon.Transport.P2PGeneric as P2PGeneric
import Control.Concurrent.STM
import Control.Concurrent.Async
#ifndef mingw32_HOST_OS
import System.Posix.User
#endif
-- Run tor hidden service.
server :: Server
server ichan th@(TransportHandle (LocalRepo r) _ _) = go
where
go = checkstartservice >>= handlecontrol
checkstartservice = do
u <- liftAnnex th getUUID
msock <- liftAnnex th torSocketFile
case msock of
Nothing ->
return False
Just socketfile -> do
void $ async $ startservice socketfile u
return True
startservice socketfile u = do
sock <- listenUnixSocket socketfile
P2PGeneric.serveConnections
loadP2PAuthTokensTor
(P2PNetName "tor")
th u r sock
handlecontrol servicerunning = do
msg <- atomically $ readTChan ichan
case msg of
-- On reload, the configuration may have changed to
-- enable the tor hidden service. If it was not
-- enabled before, start it,
RELOAD | not servicerunning -> go
-- We can ignore all other messages; no need
-- to restart the hidden service when the network
-- changes as tor takes care of all that.
_ -> handlecontrol servicerunning
-- Connect to peer's tor hidden service. P2PGeneric can do this,
-- since it uses connectPeer which also supports tor.
transport :: Transport
transport = P2PGeneric.transport
torSocketFile :: Annex (Maybe OsPath)
torSocketFile = do
u <- getUUID
let ident = fromUUID u
#ifndef mingw32_HOST_OS
uid <- liftIO getRealUserID
#else
let uid = 0
#endif
liftIO $ getHiddenServiceSocketFile torAppName uid ident