diff --git a/app/models/white_ip.rb b/app/models/white_ip.rb index bc7aee337..b69bcee96 100644 --- a/app/models/white_ip.rb +++ b/app/models/white_ip.rb @@ -6,6 +6,7 @@ class WhiteIp < ApplicationRecord validate :valid_ipv6? validate :validate_ipv4_and_ipv6 validate :validate_only_one_ip + validate :validate_max_ip_count before_save :normalize_blank_values def normalize_blank_values @@ -40,6 +41,29 @@ class WhiteIp < ApplicationRecord errors.add(:ipv6, :invalid) end + def validate_max_ip_count + ip_addresses = registrar.white_ips + total = ip_addresses.size + count_network_addresses(ipv4.presence || ipv6) + limit = Setting.ip_whitelist_max_count + return unless total >= limit + + errors.add(:base, I18n.t(:ip_limit_exceeded, total: total, limit: limit)) + end + + def count_network_addresses(ip) + address = IPAddr.new(ip) + + if address.ipv4? + subnet_mask = address.prefix + 2**(32 - subnet_mask) - 2 + elsif address.ipv6? + subnet_mask = address.prefix + 2**(128 - subnet_mask) - 2 + else + 0 + end + end + API = 'api'.freeze REGISTRAR = 'registrar'.freeze INTERFACES = [API, REGISTRAR].freeze diff --git a/config/locales/en.yml b/config/locales/en.yml index cf1e64bec..4a37c35f8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -546,6 +546,7 @@ en: crt_or_csr_must_be_present: 'CRT or CSR must be present' ipv4_or_ipv6_must_be_present: 'IPv4 or IPv6 must be present' ip_must_be_one: 'Please enter only one IP address' + ip_limit_exceeded: 'IP address limit exceeded. Total addresses: %{total}. Limit: %{limit}.' white_ip: 'White IP' edit_white_ip: 'Edit white IP' confirm_domain_delete: 'Confirm domain delete' diff --git a/db/migrate/20230531111154_add_ip_whitelist_max_count_setting.rb b/db/migrate/20230531111154_add_ip_whitelist_max_count_setting.rb new file mode 100644 index 000000000..1693fdf1f --- /dev/null +++ b/db/migrate/20230531111154_add_ip_whitelist_max_count_setting.rb @@ -0,0 +1,11 @@ +class AddIpWhitelistMaxCountSetting < ActiveRecord::Migration[6.1] + def up + Setting.create(code: 'ip_whitelist_max_count', + value: 256, format: 'integer', + group: 'other') + end + + def down + Setting.find_by(code: 'ip_whitelist_max_count').destroy + end +end diff --git a/db/seeds.rb b/db/seeds.rb index 691c18b0f..4cb36e738 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -61,6 +61,7 @@ ActiveRecord::Base.transaction do SettingEntry.create(code: 'dispute_period_in_months', value: '36', format: 'integer', group: 'other') SettingEntry.create(code: 'registry_whois_disclaimer', value: 'Search results may not be used for commercial, advertising, recompilation, repackaging, redistribution, reuse, obscuring or other similar activities.', format: 'string', group: 'contacts') SettingEntry.create(code: 'legal_document_is_mandatory', value: 'true', format: 'boolean', group: 'domain_validation') + SettingEntry.create(code: 'ip_whitelist_max_count', value: '256', format: 'integer', group: 'other') AdminUser.where(username: 'admin').first_or_create!( username: 'admin', diff --git a/db/structure.sql b/db/structure.sql index 6286053ce..44ffd7162 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -5467,6 +5467,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20221206091556'), ('20221207102831'), ('20221214073933'), -('20221214074252'); +('20221214074252'), +('20230531111154');