{-# LANGUAGE OverloadedStrings #-}
module Knives.ExtIP where
import CommandLine
import Network.HTTP.Simple
import Data.Aeson
import Data.Bool (bool)
import Control.Monad ((>=>))
data RExtIP = RExtIP
{ ip :: String } deriving Show
instance FromJSON RExtIP where
parseJSON = withObject "RExtIP" $ \v -> RExtIP
<$> v .: "ip"
data RLoc = RLoc
{status :: String
, country :: String
, countryCode:: String
, region :: String
, regionName :: String
, city :: String
, zip :: String
, lat :: Float
, lon :: Float
, timezone :: String
, isp :: String
, org :: String
, as :: String
, query :: String
} deriving Show
instance FromJSON RLoc where
parseJSON = withObject "RLoc" $ \v -> RLoc
<$> v .: "status"
<*> v .: "country"
<*> v .: "countryCode"
<*> v .: "region"
<*> v .: "regionName"
<*> v .: "city"
<*> v .: "zip"
<*> v .: "lat"
<*> v .: "lon"
<*> v .: "timezone"
<*> v .: "isp"
<*> v .: "org"
<*> v .: "as"
<*> v .: "query"
knifeExtIP :: ExtIPOptions -> IO ()
knifeExtIP optsE = do
res <- (parseRequest >=> httpLBS) $ bool url_ipv4 url_ipv6 $ ipv6 optsE
putStrLn $ ipaddr res
if (not $ nolocation optsE)
then do
loc <- location
putStrLn $ loc
else return ()
where
url_ipv4 = "https://ipv4.jsonip.com"
url_ipv6 = "https://ipv6.jsonip.com"
url_geo = "http://ip-api.com/json/"
ipaddr res = do
let ipresult = eitherDecode $ getResponseBody res :: Either String RExtIP
case ipresult of
Left err -> do
"Failed to obtain IP: " ++ err
Right extIP -> do
ip extIP
location :: IO String
location = do
request <- parseRequest url_geo
res <- httpLBS request
let locres = eitherDecode $ getResponseBody res :: Either String RLoc
case locres of
Left err -> do
return $ "Failed to obtain location: " ++ err
Right loc -> do
let str_result = "Location: "
++ city loc ++ ", "
++ country loc
++ " (" ++ countryCode loc ++ ")\n"
++ "Timezone: " ++ timezone loc ++ "\n"
return str_result