From fd489f1be5eff3d11c978165017c0984493794fe Mon Sep 17 00:00:00 2001 From: Sam Truzjan Date: Mon, 30 Dec 2013 17:41:30 +0400 Subject: Add documentation to Token module --- src/Network/BitTorrent/DHT/Token.hs | 55 +++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/Network/BitTorrent/DHT/Token.hs b/src/Network/BitTorrent/DHT/Token.hs index 51ee40d5..a38456fd 100644 --- a/src/Network/BitTorrent/DHT/Token.hs +++ b/src/Network/BitTorrent/DHT/Token.hs @@ -1,9 +1,16 @@ --- | The return value for a query for peers includes an opaque value --- known as the \"token.\" For a node to announce that its controlling +-- | +-- Copyright : (c) Sam Truzjan 2013 +-- License : BSD3 +-- Maintainer : pxqr.sta@gmail.com +-- Stability : experimental +-- Portability : portable +-- +-- The return value for a query for peers includes an opaque value +-- known as the 'Token'. For a node to announce that its controlling -- peer is downloading a torrent, it must present the token received -- from the same queried node in a recent query for peers. When a node --- attempts to "announce" a torrent, the queried node checks the token --- against the querying node's IP address. This is to prevent +-- attempts to \"announce\" a torrent, the queried node checks the +-- token against the querying node's 'IP' address. This is to prevent -- malicious hosts from signing up other hosts for torrents. Since the -- token is merely returned by the querying node to the same node it -- received the token from, the implementation is not defined. Tokens @@ -12,11 +19,20 @@ -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Network.BitTorrent.DHT.Token - ( Token + ( -- * Token + Token + + -- * Session tokens , TokenMap + + -- ** Construction , Network.BitTorrent.DHT.Token.tokens + + -- ** Query , Network.BitTorrent.DHT.Token.lookup , Network.BitTorrent.DHT.Token.member + + -- ** Modification , Network.BitTorrent.DHT.Token.defaultUpdateInterval , Network.BitTorrent.DHT.Token.update ) where @@ -36,10 +52,9 @@ import System.Random import Network.BitTorrent.Core - -type Secret = Int - -- TODO use ShortByteString + +-- | An opaque value. newtype Token = Token BS.ByteString deriving (Show, Eq, BEncode, IsString) @@ -47,6 +62,9 @@ newtype Token = Token BS.ByteString instance Default Token where def = Token "0xdeadbeef" +-- | The secret value used as salt. +type Secret = Int + -- The BitTorrent implementation uses the SHA1 hash of the IP address -- concatenated onto a secret, we use hashable instead. makeToken :: Hashable a => NodeAddr a -> Secret -> Token @@ -54,33 +72,46 @@ makeToken n s = Token $ toBS $ hashWithSalt s n where toBS = toStrict . toLazyByteString . int64BE . fromIntegral --- | Constant space token map based on secret. +-- | Constant space 'Node' to 'Token' map based on the secret value. data TokenMap = TokenMap { prevSecret :: {-# UNPACK #-} !Secret , curSecret :: {-# UNPACK #-} !Secret , generator :: {-# UNPACK #-} !StdGen } deriving Show +-- | A new token map based on the specified seed value. Returned token +-- map should be periodicatically 'update'd. +-- +-- Normally, the seed value should vary between invocations of the +-- client software. tokens :: Int -> TokenMap tokens seed = (`evalState` mkStdGen seed) $ TokenMap <$> state next <*> state next <*> get +-- | Get token for the given node. A token becomes invalid after 2 +-- 'update's. +-- +-- Typically used to handle find_peers query. lookup :: Hashable a => NodeAddr a -> TokenMap -> Token lookup addr TokenMap {..} = makeToken addr curSecret --- | If token is not set 'Network.KRPC.ProtocolError' should be sent --- back. +-- | Check if token is valid. +-- +-- Typically used to handle 'Network.BitTorrent.DHT.Message.Announce' +-- query. If token is invalid the 'Network.KRPC.ProtocolError' should +-- be sent back to the malicious node. member :: Hashable a => NodeAddr a -> Token -> TokenMap -> Bool member addr token TokenMap {..} = token `L.elem` valid where valid = makeToken addr <$> [curSecret, prevSecret] --- Secret changes every five minutes and tokens up to ten minutes old +-- | Secret changes every five minutes and tokens up to ten minutes old -- are accepted. defaultUpdateInterval :: NominalDiffTime defaultUpdateInterval = 5 * 60 +-- | Update current tokens. update :: TokenMap -> TokenMap update TokenMap {..} = TokenMap { prevSecret = curSecret -- cgit v1.2.3