X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=data%2Frbot%2Fplugins%2Fgeoip.rb;h=48391a10729721b4803563c6d916699cd06d2013;hb=fda847bf583b9cc02eda341730d53887302ffe57;hp=96dcf9d23ce2edca1ef62317ad511a1939686d92;hpb=235634f64decfd4c1c20574474faf0267c8772c5;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/data/rbot/plugins/geoip.rb b/data/rbot/plugins/geoip.rb old mode 100755 new mode 100644 index 96dcf9d2..48391a10 --- a/data/rbot/plugins/geoip.rb +++ b/data/rbot/plugins/geoip.rb @@ -9,40 +9,80 @@ # # Resolves the geographic locations of users (network-wide) and IP addresses -module GeoIP +module ::GeoIP class InvalidHostError < RuntimeError; end + class BadAPIError < RuntimeError; end - GEO_IP_PRIMARY = "http://lakka.kapsi.fi:40086/lookup.yaml?host=" - GEO_IP_SECONDARY = "http://www.geoiptool.com/en/?IP=" HOST_NAME_REGEX = /^[a-z0-9\-]+(?:\.[a-z0-9\-]+)*\.[a-z]{2,4}/i - REGEX = { - :country => %r{Country:.*? (.*?)}m, - :region => %r{Region:.*?(.*?)}m, - :city => %r{City:.*?(.*?)}m - } - def self.valid_host?(hostname) hostname =~ HOST_NAME_REGEX || hostname =~ Resolv::IPv4::Regex && (hostname.split(".").map { |e| e.to_i }.max <= 255) end - def self.resolve(hostname) - raise InvalidHostError unless valid_host?(hostname) + def self.geoiptool(bot, ip) + url = "http://www.geoiptool.com/en/?IP=" + regexes = { + :country => %r{Country:.*? (.*?)}m, + :region => %r{Region:.*?(.*?)}m, + :city => %r{City:.*?(.*?)}m, + :lat => %r{Latitude:.*?(.*?)}m, + :lon => %r{Longitude:.*?(.*?)}m + } + res = {} + raw = bot.httputil.get_response(url+ip) + raw = raw.decompress_body(raw.raw_body) + + regexes.each { |key, regex| res[key] = raw.scan(regex).join('') } + + return res + end - yaml = Irc::Utils.bot.httputil.get(GEO_IP_PRIMARY+hostname) + IPINFODB_URL = "http://api.ipinfodb.com/v2/ip_query.php?key=%{key}&ip=%{ip}" - if yaml - return YAML::load(yaml) + def self.ipinfodb(bot, ip) + key = bot.config['geoip.ipinfodb_key'] + return if not key or key.empty? + url = IPINFODB_URL % { + :ip => ip, + :key => key + } + debug "Requesting #{url}" + + xml = bot.httputil.get(url) + + if xml + obj = REXML::Document.new(xml) + debug "Found #{obj}" + newobj = { + :country => obj.elements["Response"].elements["CountryName"].text, + :city => obj.elements["Response"].elements["City"].text, + :region => obj.elements["Response"].elements["RegionName"].text, + } + debug "Returning #{newobj}" + return newobj else - res = {} - raw = Irc::Utils.bot.httputil.get_response(GEO_IP_SECONDARY+hostname) - raw = raw.decompress_body(raw.raw_body) + raise InvalidHostError + end + end - REGEX.each { |key, regex| res[key] = Iconv.conv('utf-8', 'ISO-8859-1', raw.scan(regex).to_s) } + JUMP_TABLE = { + "ipinfodb" => Proc.new { |bot, ip| ipinfodb(bot, ip) }, + "geoiptool" => Proc.new { |bot, ip| geoiptool(bot, ip) }, + } + + def self.resolve(bot, hostname, api) + raise InvalidHostError unless valid_host?(hostname) - return res + begin + ip = Resolv.getaddress(hostname) + rescue Resolv::ResolvError + raise InvalidHostError end + + raise BadAPIError unless JUMP_TABLE.key?(api) + + return JUMP_TABLE[api].call(bot, ip) end end @@ -66,6 +106,13 @@ class Stack end class GeoIpPlugin < Plugin + Config.register Config::ArrayValue.new('geoip.sources', + :default => [ "ipinfodb", "geoiptool" ], + :desc => "Which API to use for lookups. Supported values: ipinfodb, geoiptool") + Config.register Config::StringValue.new('geoip.ipinfodb_key', + :default => "", + :desc => "API key for the IPinfoDB geolocation service") + def help(plugin, topic="") "geoip [] => returns the geographic location of whichever has been given -- note: user can be anyone on the network" end @@ -101,7 +148,7 @@ class GeoIpPlugin < Plugin if m.replyto.class == Channel # check if there is an user on the channel with nick same as input given - user = m.replyto.users.find { |user| user.nick == params[:input] } + user = m.replyto.users.find { |usr| usr.nick == params[:input] } if user m.reply host2output(user.host, user.nick) @@ -128,32 +175,41 @@ class GeoIpPlugin < Plugin def host2output(host, nick=nil) return "127.0.0.1 could not be res.. wait, what?" if host == "127.0.0.1" + geo = {:country => ""} begin - geo = GeoIP::resolve(host) - - raise if geo[:country].empty? + apis = @bot.config['geoip.sources'] + apis.compact.each { |api| + geo = GeoIP::resolve(@bot, host, api) + if geo and geo[:country] != "" + break + end + } rescue GeoIP::InvalidHostError, RuntimeError - return _("#{nick ? "#{nick}'s location" : host} could not be resolved") + if nick + return _("%{nick}'s location could not be resolved") % { :nick => nick } + else + return _("%{host} could not be resolved") % { :host => host } + end + rescue GeoIP::BadAPIError + return _("The owner configured me to use an API that doesn't exist, bug them!") end - res = _("%{thing} is #{nick ? "from" : "located in"}") % { - :thing => (nick ? nick : Resolv::getaddress(host)), - :country => geo[:country] - } + location = [] + location << geo[:city] unless geo[:city].nil_or_empty? + location << geo[:region] unless geo[:region].nil_or_empty? or geo[:region] == geo[:city] + location << geo[:country] unless geo[:country].nil_or_empty? - res << " %{city}," % { - :city => geo[:city] - } unless geo[:city].to_s.empty? + if nick + res = _("%{nick} is from %{location}") + else + res = _("%{host} is located in %{location}") + end - res << " %{country}" % { - :country => geo[:country] + return res % { + :nick => nick, + :host => host, + :location => location.join(', ') } - - res << " (%{region})" % { - :region => geo[:region] - } unless geo[:region].to_s.empty? || geo[:region] == geo[:city] - - return res end end