diff --git a/app/logical/ip_lookup.rb b/app/logical/ip_lookup.rb new file mode 100644 index 000000000..bc78e83b4 --- /dev/null +++ b/app/logical/ip_lookup.rb @@ -0,0 +1,27 @@ +# API client for https://ipregistry.co/ + +class IpLookup + extend Memoist + + attr_reader :ip_addr, :api_key, :cache_duration + + def initialize(ip_addr, api_key: Danbooru.config.ip_registry_api_key, cache_duration: 1.day) + @ip_addr = ip_addr + @api_key = api_key + @cache_duration = cache_duration + end + + def info + return {} unless api_key.present? + response = Danbooru::Http.cache(cache_duration).get("https://api.ipregistry.co/#{ip_addr}?key=#{api_key}") + return {} if response.status != 200 + json = response.parse.deep_symbolize_keys.with_indifferent_access + json + end + + def is_proxy? + info[:security].present? && info[:security].values.any? + end + + memoize :info, :is_proxy? +end diff --git a/app/models/ip_address.rb b/app/models/ip_address.rb index 6d7c351ad..0fcf5a8fb 100644 --- a/app/models/ip_address.rb +++ b/app/models/ip_address.rb @@ -37,6 +37,10 @@ class IpAddress < ApplicationRecord group(:user_id).select("user_id, COUNT(*) AS count_all").reorder("count_all DESC, user_id") end + def lookup + @lookup ||= IpLookup.new(ip_addr) + end + def to_s # include the subnet mask only when the IP denotes a subnet. (ip_addr.size > 1) ? ip_addr.to_string : ip_addr.to_s diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb index 6a15f1c60..16f3a441d 100644 --- a/config/danbooru_default_config.rb +++ b/config/danbooru_default_config.rb @@ -513,6 +513,12 @@ module Danbooru "https://#{hostname}" end + # API key for https://ipregistry.co. Used for looking up IP address + # information and for detecting proxies during signup. + def ip_registry_api_key + nil + end + # Cloudflare API token. Used to purge URLs from Cloudflare's cache when a # post is replaced. The token must have 'zone.cache_purge' permissions. # https://support.cloudflare.com/hc/en-us/articles/200167836-Managing-API-Tokens-and-Keys