-- |Structures and rules for describing routers.
module Tor.RouterDesc(
         RouterDesc(..)
       , blankRouterDesc
       , NodeFamily(..)
       , ExitRule(..)
       , AddrSpec(..)
       , PortSpec(..)
       )
 where

import Crypto.PubKey.Curve25519 as Curve
import Crypto.PubKey.RSA as RSA
import Data.ByteString(ByteString, empty)
import Data.Hourglass
import Data.Word

-- |The complete description of a router within the Tor network.
data RouterDesc = RouterDesc {
       routerNickname                :: String
     , routerIPv4Address             :: String
     , routerORPort                  :: Word16
     , routerDirPort                 :: Maybe Word16
     , routerParseLog                :: [String]
     , routerAvgBandwidth            :: Int
     , routerBurstBandwidth          :: Int
     , routerObservedBandwidth       :: Int
     , routerPlatformName            :: String
     , routerEntryPublished          :: DateTime
     , routerFingerprint             :: ByteString
     , routerHibernating             :: Bool
     , routerUptime                  :: Maybe Integer
     , routerOnionKey                :: RSA.PublicKey
     , routerNTorOnionKey            :: Maybe Curve.PublicKey
     , routerSigningKey              :: RSA.PublicKey
     , routerExitRules               :: [ExitRule]
     , routerIPv6Policy              :: Either [PortSpec] [PortSpec]
     , routerSignature               :: ByteString
     , routerContact                 :: Maybe String
     , routerFamily                  :: [NodeFamily]
     , routerReadHistory             :: Maybe (DateTime, Int, [Int])
     , routerWriteHistory            :: Maybe (DateTime, Int, [Int])
     , routerCachesExtraInfo         :: Bool
     , routerExtraInfoDigest         :: Maybe ByteString
     , routerHiddenServiceDir        :: Maybe Int
     , routerLinkProtocolVersions    :: [Int]
     , routerCircuitProtocolVersions :: [Int]
     , routerAllowSingleHopExits     :: Bool
     , routerAlternateORAddresses    :: [(String, Word16)]
     , routerStatus                  :: [String]
     }
 deriving (Show)

instance Eq RouterDesc where
  a == b = routerSigningKey a == routerSigningKey b

-- |A blank router description, with most of the options initialized with
-- standard "blank" values.
blankRouterDesc :: RouterDesc
blankRouterDesc =
  RouterDesc {
    routerNickname                = ""
  , routerIPv4Address             = "0.0.0.0"
  , routerORPort                  = 0
  , routerDirPort                 = Nothing
  , routerParseLog                = []
  , routerAvgBandwidth            = 0
  , routerBurstBandwidth          = 0
  , routerObservedBandwidth       = 0
  , routerPlatformName            = "Haskell"
  , routerEntryPublished          = timeFromElapsed (Elapsed (Seconds 0))
  , routerFingerprint             = empty
  , routerHibernating             = False
  , routerUptime                  = Nothing
  , routerOnionKey                = error "No public onion key"
  , routerNTorOnionKey            = Nothing
  , routerSigningKey              = error "No signing key"
  , routerExitRules               = []
  , routerIPv6Policy              = Left []
  , routerSignature               = empty
  , routerContact                 = Nothing
  , routerFamily                  = []
  , routerReadHistory             = Nothing
  , routerWriteHistory            = Nothing
  , routerCachesExtraInfo         = False
  , routerExtraInfoDigest         = Nothing
  , routerHiddenServiceDir        = Nothing
  , routerLinkProtocolVersions    = []
  , routerCircuitProtocolVersions = []
  , routerAllowSingleHopExits     = False
  , routerAlternateORAddresses    = []
  , routerStatus                  = []
  }

-- |A family descriptor for a node. Either a nickname, or a digest referencing
-- the family, or both.
data NodeFamily = NodeFamilyNickname String
                | NodeFamilyDigest ByteString
                | NodeFamilyBoth String ByteString
 deriving (Show)

-- |A rule for accepting or rejecting traffic, usually specified by exit nodes.
data ExitRule = ExitRuleAccept AddrSpec PortSpec -- ^Accept matching traffic.
              | ExitRuleReject AddrSpec PortSpec -- ^Reject matching traffic.
 deriving (Show)

-- |A port specifier
data PortSpec = PortSpecAll -- ^Accept any port
              | PortSpecRange  Word16 Word16 -- ^Accept ports between the two
                                             -- values, inclusive.
              | PortSpecSingle Word16 -- ^Accept only the given port.
 deriving (Eq, Show)

-- |An address or subnet specifier.
data AddrSpec = AddrSpecAll -- ^Accept any address
              | AddrSpecIP4     String -- ^Accept this specific address.
              | AddrSpecIP4Mask String String -- ^Accept this IP address and
                -- subnet mask (255.255.255.0,etc.)
              | AddrSpecIP4Bits String Int -- ^Accept this IP address and CIDR
                -- mask (/24,etc.)
              | AddrSpecIP6     String -- ^Accept this specific IP6 address.
              | AddrSpecIP6Bits String Int -- ^Accept this subnet and CIDR
                -- mask.
 deriving (Eq, Show)