git-annex/P2P/Address.hs
Joey Hess 40ecf58d4b
update licenses from GPL to AGPL
This does not change the overall license of the git-annex program, which
was already AGPL due to a number of sources files being AGPL already.

Legally speaking, I'm adding a new license under which these files are
now available; I already released their current contents under the GPL
license. Now they're dual licensed GPL and AGPL. However, I intend
for all my future changes to these files to only be released under the
AGPL license, and I won't be tracking the dual licensing status, so I'm
simply changing the license statement to say it's AGPL.

(In some cases, others wrote parts of the code of a file and released it
under the GPL; but in all cases I have contributed a significant portion
of the code in each file and it's that code that is getting the AGPL
license; the GPL license of other contributors allows combining with
AGPL code.)
2019-03-13 15:48:14 -04:00

95 lines
2.9 KiB
Haskell

{- P2P protocol addresses
-
- Copyright 2016 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
module P2P.Address where
import qualified Annex
import Annex.Common
import Git
import Git.Types
import Creds
import Utility.AuthToken
import Utility.Tor
import qualified Data.Text as T
-- | A P2P address, without an AuthToken.
--
-- This is enough information to connect to the peer,
-- but not enough to authenticate with it.
data P2PAddress = TorAnnex OnionAddress OnionPort
deriving (Eq, Show)
-- | A P2P address, with an AuthToken.
--
-- This is enough information to connect to the peer, and authenticate with
-- it.
data P2PAddressAuth = P2PAddressAuth P2PAddress AuthToken
deriving (Eq, Show)
class FormatP2PAddress a where
formatP2PAddress :: a -> String
unformatP2PAddress :: String -> Maybe a
instance FormatP2PAddress P2PAddress where
formatP2PAddress (TorAnnex (OnionAddress onionaddr) onionport) =
torAnnexScheme ++ ":" ++ onionaddr ++ ":" ++ show onionport
unformatP2PAddress s
| (torAnnexScheme ++ ":") `isPrefixOf` s = do
let s' = dropWhile (== ':') $ dropWhile (/= ':') s
let (onionaddr, ps) = separate (== ':') s'
onionport <- readish ps
return (TorAnnex (OnionAddress onionaddr) onionport)
| otherwise = Nothing
torAnnexScheme :: String
torAnnexScheme = "tor-annex:"
instance FormatP2PAddress P2PAddressAuth where
formatP2PAddress (P2PAddressAuth addr authtoken) =
formatP2PAddress addr ++ ":" ++ T.unpack (fromAuthToken authtoken)
unformatP2PAddress s = do
let (ra, rs) = separate (== ':') (reverse s)
addr <- unformatP2PAddress (reverse rs)
authtoken <- toAuthToken (T.pack $ reverse ra)
return (P2PAddressAuth addr authtoken)
repoP2PAddress :: Repo -> Maybe P2PAddress
repoP2PAddress (Repo { location = Url url }) = unformatP2PAddress (show url)
repoP2PAddress _ = Nothing
-- | Load known P2P addresses for this repository.
loadP2PAddresses :: Annex [P2PAddress]
loadP2PAddresses = mapMaybe unformatP2PAddress . maybe [] lines
<$> readCreds p2pAddressCredsFile
-- | Store a new P2P address for this repository.
storeP2PAddress :: P2PAddress -> Annex ()
storeP2PAddress addr = do
addrs <- loadP2PAddresses
unless (addr `elem` addrs) $ do
let s = unlines $ map formatP2PAddress (addr:addrs)
let tmpnam = p2pAddressCredsFile ++ ".new"
writeCreds s tmpnam
tmpf <- credsFile tmpnam
destf <- credsFile p2pAddressCredsFile
-- This may be run by root, so make the creds file
-- and directory have the same owner and group as
-- the git repository directory has.
st <- liftIO . getFileStatus =<< Annex.fromRepo repoLocation
let fixowner f = setOwnerAndGroup f (fileOwner st) (fileGroup st)
liftIO $ do
fixowner tmpf
fixowner (takeDirectory tmpf)
fixowner (takeDirectory (takeDirectory tmpf))
renameFile tmpf destf
p2pAddressCredsFile :: FilePath
p2pAddressCredsFile = "p2paddrs"
torAppName :: AppName
torAppName = "tor-annex"