ip addresses: move more logic to Danbooru::IpAddress.
* Move `is_local?` from IpLookup to Danbooru::IpAddress. * Refactor more things to use Danbooru::IpAddress instead of using IPAddress directly.
This commit is contained in:
@@ -79,10 +79,10 @@ module Searchable
|
|||||||
|
|
||||||
def where_inet_matches(attr, value)
|
def where_inet_matches(attr, value)
|
||||||
if value.match?(/[, ]/)
|
if value.match?(/[, ]/)
|
||||||
ips = value.split(/[, ]+/).map { |ip| IPAddress.parse(ip).to_string }
|
ips = value.split(/[, ]+/).map { |ip| Danbooru::IpAddress.new(ip).to_string }
|
||||||
where("#{qualified_column_for(attr)} = ANY(ARRAY[?]::inet[])", ips)
|
where("#{qualified_column_for(attr)} = ANY(ARRAY[?]::inet[])", ips)
|
||||||
else
|
else
|
||||||
ip = IPAddress.parse(value)
|
ip = Danbooru::IpAddress.new(value)
|
||||||
where("#{qualified_column_for(attr)} <<= ?", ip.to_string)
|
where("#{qualified_column_for(attr)} <<= ?", ip.to_string)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,10 +5,23 @@
|
|||||||
module Danbooru
|
module Danbooru
|
||||||
class IpAddress
|
class IpAddress
|
||||||
attr_reader :ip_address
|
attr_reader :ip_address
|
||||||
delegate_missing_to :ip_address
|
delegate :ipv4?, :ipv6?, :loopback?, :link_local?, :unique_local?, :private?, :to_string, :prefix, :multicast?, :unspecified?, to: :ip_address
|
||||||
|
delegate :ip_info, :is_proxy?, to: :ip_lookup
|
||||||
|
|
||||||
def initialize(string)
|
def initialize(string)
|
||||||
@ip_address = ::IPAddress.parse(string)
|
@ip_address = ::IPAddress.parse(string.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def ip_lookup
|
||||||
|
@ip_lookup ||= IpLookup.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_local?
|
||||||
|
if ipv4?
|
||||||
|
loopback? || link_local? || multicast? || private?
|
||||||
|
elsif ipv6?
|
||||||
|
loopback? || link_local? || unique_local? || unspecified?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# "1.2.3.4/24" if the address is a subnet, "1.2.3.4" otherwise.
|
# "1.2.3.4/24" if the address is a subnet, "1.2.3.4" otherwise.
|
||||||
@@ -19,5 +32,17 @@ module Danbooru
|
|||||||
def inspect
|
def inspect
|
||||||
"#<Danbooru::IpAddress #{to_s}>"
|
"#<Danbooru::IpAddress #{to_s}>"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
self.class == other.class && to_s == other.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is needed to be able to correctly treat IpAddresses as hash keys,
|
||||||
|
# which Rails does internally when preloading associations.
|
||||||
|
def hash
|
||||||
|
to_s.hash
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :eql?, :==
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ class IpLookup
|
|||||||
end
|
end
|
||||||
|
|
||||||
def initialize(ip_addr, api_key: Danbooru.config.ip_registry_api_key, cache_duration: 3.days)
|
def initialize(ip_addr, api_key: Danbooru.config.ip_registry_api_key, cache_duration: 3.days)
|
||||||
@ip_addr = IPAddress.parse(ip_addr.to_s)
|
@ip_addr = Danbooru::IpAddress.new(ip_addr)
|
||||||
@api_key = api_key
|
@api_key = api_key
|
||||||
@cache_duration = cache_duration
|
@cache_duration = cache_duration
|
||||||
end
|
end
|
||||||
|
|
||||||
def ip_info
|
def ip_info
|
||||||
|
return {} if ip_addr.is_local?
|
||||||
return {} if response.blank?
|
return {} if response.blank?
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -43,14 +44,6 @@ class IpLookup
|
|||||||
json
|
json
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_local?
|
|
||||||
if ip_addr.ipv4?
|
|
||||||
ip_addr.loopback? || ip_addr.link_local? || ip_addr.private?
|
|
||||||
elsif ip_addr.ipv6?
|
|
||||||
ip_addr.loopback? || ip_addr.link_local? || ip_addr.unique_local?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def is_proxy?
|
def is_proxy?
|
||||||
response[:security].present? && response[:security].values.any?
|
response[:security].present? && response[:security].values.any?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class UserVerifier
|
|||||||
|
|
||||||
def requires_verification?
|
def requires_verification?
|
||||||
return false if !Danbooru.config.new_user_verification?
|
return false if !Danbooru.config.new_user_verification?
|
||||||
return false if is_local_ip?
|
return false if ip_address.is_local?
|
||||||
|
|
||||||
# we check for IP bans first to make sure we bump the IP ban hit count
|
# we check for IP bans first to make sure we bump the IP ban hit count
|
||||||
is_ip_banned? || is_logged_in? || is_recent_signup? || is_proxy?
|
is_ip_banned? || is_logged_in? || is_recent_signup? || is_proxy?
|
||||||
@@ -33,11 +33,7 @@ class UserVerifier
|
|||||||
private
|
private
|
||||||
|
|
||||||
def ip_address
|
def ip_address
|
||||||
@ip_address ||= IPAddress.parse(request.remote_ip)
|
@ip_address ||= Danbooru::IpAddress.new(request.remote_ip)
|
||||||
end
|
|
||||||
|
|
||||||
def is_local_ip?
|
|
||||||
IpLookup.new(ip_address).is_local?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_logged_in?
|
def is_logged_in?
|
||||||
@@ -56,7 +52,7 @@ class UserVerifier
|
|||||||
end
|
end
|
||||||
|
|
||||||
def is_proxy?
|
def is_proxy?
|
||||||
IpLookup.new(ip_address).is_proxy?
|
ip_address.is_proxy?
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
|
|||||||
@@ -12,16 +12,8 @@ class ValidatingSocket < TCPSocket
|
|||||||
end
|
end
|
||||||
|
|
||||||
def validate_hostname!(hostname)
|
def validate_hostname!(hostname)
|
||||||
ip = IPAddress.parse(::Resolv.getaddress(hostname))
|
ip = Danbooru::IpAddress.new(::Resolv.getaddress(hostname))
|
||||||
raise ProhibitedIpError, "Connection to #{hostname} failed; #{ip} is a prohibited IP" if prohibited_ip?(ip)
|
raise ProhibitedIpError, "Connection to #{hostname} failed; #{ip} is a prohibited IP" if ip.is_local?
|
||||||
ip.to_s
|
ip.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def prohibited_ip?(ip)
|
|
||||||
if ip.ipv4?
|
|
||||||
ip.loopback? || ip.link_local? || ip.multicast? || ip.private?
|
|
||||||
elsif ip.ipv6?
|
|
||||||
ip.loopback? || ip.link_local? || ip.unique_local? || ip.unspecified?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class IpAddress < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def lookup
|
def lookup
|
||||||
@lookup ||= IpLookup.new(ip_addr)
|
@lookup ||= ip_addr.ip_lookup
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
# An IpGeolocation contains metadata associated with an IP address, primarily geolocation data.
|
# An IpGeolocation contains metadata associated with an IP address, primarily geolocation data.
|
||||||
|
|
||||||
class IpGeolocation < ApplicationRecord
|
class IpGeolocation < ApplicationRecord
|
||||||
|
attribute :ip_addr, :ip_address
|
||||||
|
attribute :network, :ip_address
|
||||||
|
|
||||||
has_many :user_sessions, foreign_key: :ip_addr, primary_key: :ip_addr
|
has_many :user_sessions, foreign_key: :ip_addr, primary_key: :ip_addr
|
||||||
|
|
||||||
def self.visible(user)
|
def self.visible(user)
|
||||||
@@ -17,13 +20,12 @@ class IpGeolocation < ApplicationRecord
|
|||||||
q
|
q
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create_or_update!(ip_addr)
|
def self.create_or_update!(ip)
|
||||||
ip_lookup = IpLookup.new(ip_addr)
|
ip_address = Danbooru::IpAddress.new(ip)
|
||||||
return nil if ip_lookup.is_local?
|
return nil if ip_address.ip_info.blank?
|
||||||
return nil if ip_lookup.ip_info.blank?
|
|
||||||
|
|
||||||
ip_geolocation = IpGeolocation.create_with(**ip_lookup.ip_info).create_or_find_by!(ip_addr: ip_addr)
|
ip_geolocation = IpGeolocation.create_with(**ip_address.ip_info).create_or_find_by!(ip_addr: ip_address)
|
||||||
ip_geolocation.update!(**ip_lookup.ip_info)
|
ip_geolocation.update!(**ip_address.ip_info)
|
||||||
ip_geolocation
|
ip_geolocation
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
# and their browser user agent. This is used to track logins and other events.
|
# and their browser user agent. This is used to track logins and other events.
|
||||||
|
|
||||||
class UserSession < ApplicationRecord
|
class UserSession < ApplicationRecord
|
||||||
|
attribute :ip_addr, :ip_address
|
||||||
|
|
||||||
belongs_to :ip_geolocation, foreign_key: :ip_addr, primary_key: :ip_addr, optional: true
|
belongs_to :ip_geolocation, foreign_key: :ip_addr, primary_key: :ip_addr, optional: true
|
||||||
|
|
||||||
def self.visible(user)
|
def self.visible(user)
|
||||||
|
|||||||
Reference in New Issue
Block a user