Class: AddressableUrlValidator
- Inherits:
-
ActiveModel::EachValidator
- Object
- ActiveModel::EachValidator
- AddressableUrlValidator
- Defined in:
- app/validators/addressable_url_validator.rb
Overview
AddressableUrlValidator
Custom validator for URLs. This is a stricter version of UrlValidator - it also checks
for using the right protocol, but it actually parses the URL checking for any syntax errors.
The regex is also different from URI as we use Addressable::URI here.
By default, only URLs for the HTTP(S) schemes will be considered valid.
Provide a :schemes option to configure accepted schemes.
Example:
class User < ActiveRecord::Base
validates :personal_url, addressable_url: true
validates :ftp_url, addressable_url: { schemes: %w(ftp) }
validates :git_url, addressable_url: { schemes: %w(http https ssh git) }
end
This validator can also block urls pointing to localhost or the local network to protect against Server-side Request Forgery (SSRF), or check for the right port.
Configuration options:
- message - A custom error message, used when the URL is blank. (default is: "must be a valid URL").
- blocked_message - A custom error message, used when the URL is blocked. Default:
'is blocked: %{exception_message}'. - schemes - Array of URI schemes. Default:
['http', 'https'] - allow_localhost - Allow urls pointing to
localhost. Default:true - allow_local_network - Allow urls pointing to private network addresses. Default:
true - allow_blank - Allow urls to be
blank. Default:false - allow_nil - Allow urls to be
nil. Default:false - ports - Allowed ports. Default:
all. - deny_all_requests_except_allowed - Deny all requests. Default: Respects the instance app setting. Note: Regardless of whether enforced during validation, an HTTP request that uses the URI may still be blocked.
- enforce_user - Validate user format. Default:
false - enforce_sanitization - Validate that there are no html/css/js tags. Default:
false
Example:
class User < ActiveRecord::Base
validates :personal_url, addressable_url: { allow_localhost: false, allow_local_network: false}
validates :web_url, addressable_url: { ports: [80, 443] }
end
Direct Known Subclasses
Constant Summary collapse
- DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT =
proc { deny_all_requests_except_allowed? }.freeze
- BLOCKER_VALIDATE_OPTIONS =
By default, we avoid checking the dns rebinding protection when saving/updating a record. Sometimes, the url is not resolvable at that point, and some automated tasks that uses that url won't work. See https://gitlab.com/gitlab-org/gitlab-foss/issues/66723
{ schemes: %w[http https], ports: [], allow_localhost: true, allow_local_network: true, ascii_only: false, deny_all_requests_except_allowed: DENY_ALL_REQUESTS_EXCEPT_ALLOWED_DEFAULT, enforce_user: false, enforce_sanitization: false, dns_rebind_protection: false, outbound_local_requests_allowlist: [] }.freeze
- DEFAULT_OPTIONS =
BLOCKER_VALIDATE_OPTIONS.merge({ message: 'must be a valid URL', blocked_message: 'is blocked: %{exception_message}' }).freeze
Instance Attribute Summary collapse
-
#record ⇒ Object
readonly
Returns the value of attribute record.
Class Method Summary collapse
- .allow_setting_local_requests? ⇒ Boolean
- .deny_all_requests_except_allowed? ⇒ Boolean
- .outbound_local_requests_allowlist ⇒ Object
Instance Method Summary collapse
-
#initialize(options) ⇒ AddressableUrlValidator
constructor
A new instance of AddressableUrlValidator.
- #validate_each(record, attribute, value) ⇒ Object
Constructor Details
#initialize(options) ⇒ AddressableUrlValidator
Returns a new instance of AddressableUrlValidator.
73 74 75 76 77 |
# File 'app/validators/addressable_url_validator.rb', line 73 def initialize() .reverse_merge!(DEFAULT_OPTIONS) super() end |
Instance Attribute Details
#record ⇒ Object (readonly)
Returns the value of attribute record.
46 47 48 |
# File 'app/validators/addressable_url_validator.rb', line 46 def record @record end |
Class Method Details
.allow_setting_local_requests? ⇒ Boolean
119 120 121 122 123 124 125 126 127 |
# File 'app/validators/addressable_url_validator.rb', line 119 def self.allow_setting_local_requests? # We cannot use Gitlab::CurrentSettings as ApplicationSetting itself # uses UrlValidator to validate urls. This ends up in a cycle # when Gitlab::CurrentSettings creates an ApplicationSetting which then # calls this validator. # # See https://gitlab.com/gitlab-org/gitlab/issues/9833 ApplicationSetting.current&.allow_local_requests_from_web_hooks_and_services? end |
.deny_all_requests_except_allowed? ⇒ Boolean
129 130 131 |
# File 'app/validators/addressable_url_validator.rb', line 129 def self.deny_all_requests_except_allowed? ApplicationSetting.current&.deny_all_requests_except_allowed? end |
.outbound_local_requests_allowlist ⇒ Object
133 134 135 |
# File 'app/validators/addressable_url_validator.rb', line 133 def self.outbound_local_requests_allowlist ApplicationSetting.current&.outbound_local_requests_whitelist || [] # rubocop:disable Naming/InclusiveLanguage -- existing setting end |
Instance Method Details
#validate_each(record, attribute, value) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'app/validators/addressable_url_validator.rb', line 79 def validate_each(record, attribute, value) @record = record unless value.present? record.errors.add(attribute, .fetch(:message)) return end value = strip_value!(record, attribute, value) Gitlab::HTTP_V2::UrlBlocker.validate!(value, **blocker_args) rescue Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError => e record.errors.add(attribute, .fetch(:blocked_message) % { exception_message: e. }) end |