Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/validators/ip_cidr_validator.rb')
-rw-r--r--app/validators/ip_cidr_validator.rb45
1 files changed, 45 insertions, 0 deletions
diff --git a/app/validators/ip_cidr_validator.rb b/app/validators/ip_cidr_validator.rb
new file mode 100644
index 00000000000..b1760a99d6d
--- /dev/null
+++ b/app/validators/ip_cidr_validator.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+# IpCidrValidator
+#
+# Validates that an IP is a valid IPv4 or IPv6 CIDR address.
+#
+# Example:
+#
+# class Group < ActiveRecord::Base
+# validates :ip, presence: true, ip_cidr: true
+# end
+
+class IpCidrValidator < ActiveModel::EachValidator # rubocop:disable Gitlab/NamespacedClass -- This is a globally shareable validator, but it's unclear what namespace it should belong in
+ def validate_each(record, attribute, value)
+ # NOTE: We want this to be usable for nullable fields, so we don't validate presence.
+ # Use a separate `presence` validation for the field if needed.
+ return true if value.blank?
+
+ # rubocop:disable Layout/LineLength -- The error message is bigger than the line limit
+ unless valid_cidr_format?(value)
+ record.errors.add(
+ attribute,
+ format(_(
+ "IP '%{value}' is not a valid CIDR: IP should be followed by a slash followed by an integer subnet mask (for example: '192.168.1.0/24')"),
+ value: value
+ )
+ )
+ return
+ end
+ # rubocop:enable Layout/LineLength
+
+ IPAddress.parse(value)
+ rescue ArgumentError => e
+ record.errors.add(
+ attribute,
+ format(_("IP '%{value}' is not a valid CIDR: %{message}"), value: value, message: e.message)
+ )
+ end
+
+ private
+
+ def valid_cidr_format?(cidr)
+ cidr.count('/') == 1 && cidr.split('/').last =~ /^\d+$/
+ end
+end