|
| 1 | +{-# LANGUAGE OverloadedStrings,TemplateHaskell #-} |
| 2 | +{-| |
| 3 | +Module : IP2ProxyWebService |
| 4 | +Description : IP2Proxy Haskell package |
| 5 | +Copyright : (c) IP2Location, 2021 |
| 6 | +License : MIT |
| 7 | +Maintainer : sales@ip2location.com |
| 8 | +Stability : experimental |
| 9 | +
|
| 10 | +This Haskell package allows users to query an IP address to determine if it was being used as open proxy, web proxy, VPN anonymizer and TOR exits. |
| 11 | +
|
| 12 | +IP2Proxy Web Service API subscription at https://www.ip2location.com/web-service/ip2proxy |
| 13 | +-} |
| 14 | +module IP2ProxyWebService (WSResult(..), WSConfig, openWS, lookUp, getCredit) where |
| 15 | + |
| 16 | +import Control.Exception |
| 17 | +import System.Exit |
| 18 | +import Data.Aeson as DA |
| 19 | +import Data.Aeson.TH |
| 20 | +import Network.HTTP.Client |
| 21 | +import Network.HTTP.Client.TLS (tlsManagerSettings) |
| 22 | +import Network.HTTP.Types.Status (statusCode) |
| 23 | +import Data.Maybe |
| 24 | +import Network.URI.Encode as URIE |
| 25 | +-- import Text.Regex.Base |
| 26 | +-- import Text.Regex.TDFA |
| 27 | + |
| 28 | +-- | Contains the web service configuration. |
| 29 | +data WSConfig = WSConfig { |
| 30 | + -- | Web service API key |
| 31 | + apiKey :: String, |
| 32 | + -- | API package |
| 33 | + apiPackage :: String, |
| 34 | + -- | Use SSL |
| 35 | + useSSL :: Bool |
| 36 | +} deriving (Show) |
| 37 | + |
| 38 | +-- | Contains the web service results. |
| 39 | +data WSResult = WSResult { |
| 40 | + -- | Response status or error |
| 41 | + response :: String, |
| 42 | + -- | Country code |
| 43 | + countryCode :: Maybe String, |
| 44 | + -- | Country name |
| 45 | + countryName :: Maybe String, |
| 46 | + -- | Region name |
| 47 | + regionName :: Maybe String, |
| 48 | + -- | City name |
| 49 | + cityName :: Maybe String, |
| 50 | + -- | ISP name |
| 51 | + isp :: Maybe String, |
| 52 | + -- | Domain |
| 53 | + domain :: Maybe String, |
| 54 | + -- | Usage type |
| 55 | + usageType :: Maybe String, |
| 56 | + -- | Autonomous System Number |
| 57 | + asn :: Maybe String, |
| 58 | + -- | Autonomous System |
| 59 | + as :: Maybe String, |
| 60 | + -- | Proxy last seen in days |
| 61 | + lastSeen :: Maybe String, |
| 62 | + -- | Proxy type |
| 63 | + proxyType :: Maybe String, |
| 64 | + -- | Threat type |
| 65 | + threat :: Maybe String, |
| 66 | + -- | Whether is a proxy |
| 67 | + isProxy :: Maybe String, |
| 68 | + -- | VPN provider name |
| 69 | + provider :: Maybe String |
| 70 | +} deriving (Show, Eq) |
| 71 | + |
| 72 | +$(deriveJSON defaultOptions ''WSResult) |
| 73 | + |
| 74 | +checkparams :: String -> String -> IO String |
| 75 | +checkparams apikey apipackage = do |
| 76 | + return "OK" |
| 77 | + --- regex part commented out due to cabal dependency issues |
| 78 | + -- let apikeyok = apikey =~ ("^[0-9A-Z]{10}$" :: String) :: Bool |
| 79 | + -- if apikeyok == False |
| 80 | + -- then die(show "Invalid API key.") |
| 81 | + -- else do |
| 82 | + -- let apipackageok = apipackage =~ ("^PX[0-9]+$" :: String) :: Bool |
| 83 | + -- if apipackageok == False |
| 84 | + -- then die(show "Invalid package name.") |
| 85 | + -- else return "OK" |
| 86 | + |
| 87 | +{-| |
| 88 | + The 'openWS' function initializes the web service configuration. |
| 89 | + It takes 3 arguments; the web service API key, the API package to call & whether to use SSL. |
| 90 | +-} |
| 91 | +openWS :: String -> String -> Bool -> IO WSConfig |
| 92 | +openWS apikey apipackage usessl = do |
| 93 | + paramok <- checkparams apikey apipackage |
| 94 | + return (WSConfig apikey apipackage usessl) |
| 95 | + |
| 96 | +{-| |
| 97 | + The 'lookUp' function returns an WSResult containing proxy data for an IP address. |
| 98 | + It takes 2 arguments; the web service configuration from 'openWS' function (WSConfig record) & either IPv4 or IPv6 address (String). |
| 99 | +-} |
| 100 | +lookUp :: WSConfig -> String -> IO WSResult |
| 101 | +lookUp myconfig ip = do |
| 102 | + let key = apiKey myconfig |
| 103 | + let package = apiPackage myconfig |
| 104 | + let usessl = useSSL myconfig |
| 105 | + |
| 106 | + paramok <- checkparams key package |
| 107 | + let protocol = if usessl == True |
| 108 | + then "https" |
| 109 | + else "http" |
| 110 | + manager <- newManager tlsManagerSettings |
| 111 | + httprequest <- parseRequest $ protocol ++ "://api.ip2proxy.com/?key=" ++ key ++ "&package=" ++ package ++ "&ip=" ++ (URIE.encode ip) |
| 112 | + httpresponse <- httpLbs httprequest manager |
| 113 | + let json = responseBody httpresponse |
| 114 | + let Just result = DA.decode json :: Maybe WSResult |
| 115 | + return result |
| 116 | + |
| 117 | +{-| |
| 118 | + The 'getCredit' function returns an WSResult containing web service credit balance for the API key. |
| 119 | + It takes 1 argument; the web service configuration from 'openWS' function (WSConfig record). |
| 120 | +-} |
| 121 | +getCredit :: WSConfig -> IO WSResult |
| 122 | +getCredit myconfig = do |
| 123 | + let key = apiKey myconfig |
| 124 | + let package = apiPackage myconfig |
| 125 | + let usessl = useSSL myconfig |
| 126 | + |
| 127 | + paramok <- checkparams key package |
| 128 | + let protocol = if usessl == True |
| 129 | + then "https" |
| 130 | + else "http" |
| 131 | + manager <- newManager tlsManagerSettings |
| 132 | + httprequest <- parseRequest $ protocol ++ "://api.ip2proxy.com/?key=" ++ key ++ "&check=true" |
| 133 | + httpresponse <- httpLbs httprequest manager |
| 134 | + let json = responseBody httpresponse |
| 135 | + let Just result = DA.decode json :: Maybe WSResult |
| 136 | + return result |
0 commit comments