diff options
Diffstat (limited to 'app/validators/url_validator.rb')
-rw-r--r-- | app/validators/url_validator.rb | 104 |
1 files changed, 0 insertions, 104 deletions
diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb deleted file mode 100644 index 3fd015c3cf5..00000000000 --- a/app/validators/url_validator.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true - -# UrlValidator -# -# Custom validator for URLs. -# -# By default, only URLs for the HTTP(S) protocols will be considered valid. -# Provide a `:protocols` option to configure accepted protocols. -# -# Example: -# -# class User < ActiveRecord::Base -# validates :personal_url, url: true -# -# validates :ftp_url, url: { protocols: %w(ftp) } -# -# validates :git_url, url: { protocols: %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. -# -# The available options are: -# - protocols: Allowed protocols. Default: http and https -# - allow_localhost: Allow urls pointing to localhost. Default: true -# - allow_local_network: Allow urls pointing to private network addresses. Default: true -# - ports: Allowed ports. Default: all. -# - 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, url: { allow_localhost: false, allow_local_network: false} -# -# validates :web_url, url: { ports: [80, 443] } -# end -class UrlValidator < ActiveModel::EachValidator - DEFAULT_PROTOCOLS = %w(http https).freeze - - attr_reader :record - - def validate_each(record, attribute, value) - @record = record - - unless value.present? - record.errors.add(attribute, 'must be a valid URL') - return - end - - value = strip_value!(record, attribute, value) - - Gitlab::UrlBlocker.validate!(value, blocker_args) - rescue Gitlab::UrlBlocker::BlockedUrlError => e - record.errors.add(attribute, "is blocked: #{e.message}") - end - - private - - def strip_value!(record, attribute, value) - new_value = value.strip - return value if new_value == value - - record.public_send("#{attribute}=", new_value) # rubocop:disable GitlabSecurity/PublicSend - end - - def default_options - # By default the validator doesn't block any url based on the ip address - { - protocols: DEFAULT_PROTOCOLS, - ports: [], - allow_localhost: true, - allow_local_network: true, - ascii_only: false, - enforce_user: false, - enforce_sanitization: false - } - end - - def current_options - options = self.options.map do |option, value| - [option, value.is_a?(Proc) ? value.call(record) : value] - end.to_h - - default_options.merge(options) - end - - def blocker_args - current_options.slice(*default_options.keys).tap do |args| - if allow_setting_local_requests? - args[:allow_localhost] = args[:allow_local_network] = true - end - end - end - - def 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-ee/issues/9833 - ApplicationSetting.current&.allow_local_requests_from_hooks_and_services? - end -end |