cartodb-4.42/app/models/carto/dbdirect_ip.rb
2024-04-06 05:25:13 +00:00

87 lines
2.1 KiB
Ruby

require 'ip_checker'
require 'carto/dbdirect/metadata_manager'
module Carto
class DbdirectIp < ActiveRecord::Base
belongs_to :user, inverse_of: :dbdirect_ip, foreign_key: :user_id
# Note about the `ips` attribute:
# The corresponding column is of type json, so there's no need for an explicit serializer
# But there's a subtle difference here from having a text field and defining `serialize :ips JSON`
# If a string is assigned to `ips` it is interpreted and parsed and JSON, and the result is nil
# if not valid JSON. With the serializer version, the string would be preserved as string.
validate :validate_ips
after_save do
persist_ips(user.username, ips)
end
after_destroy do
persist_ips(user.username, ips)
end
def self.metadata_manager
metadata_manager_class.new(config, $users_metadata)
end
def self.metadata_manager_class
Carto::Dbdirect::MetadataManager
end
def self.config
Cartodb.get_config(:dbdirect, 'metadata_persist') || {}
end
def self.metadata_persist_enabled?
!!config['enabled']
end
private
MAX_IP_MASK_HOST_BITS = 8
def validate_ips
# Check type
unless ips.kind_of?(Array) && ips.all? { |ip| ip.kind_of?(String) }
errors.add(:ips, "IPs must be an array of strings ")
return false
end
ok = true
if ips.present?
# Validate each IP
ips.each do |ip|
error = validate_ip(ip)
if error.present?
ok = false
errors.add(:ips, error)
end
end
end
ok
end
def validate_ip(ip)
IpChecker.validate(
ip,
max_host_bits: MAX_IP_MASK_HOST_BITS,
exclude_0: false,
exclude_private: true,
exclude_local: true,
exclude_loopback: true
)
end
def normalize_ip(ip)
IpChecker.normalize(ip)
end
def persist_ips(username, ips)
return unless self.class.metadata_persist_enabled?
ips = ips.map { |ip| normalize_ip(ip) }
self.class.metadata_manager.save(username, ips)
end
end
end