Add validator for qualidied domain array
- Validate that the entries contain no unicode, html tags and are not larger than 255 characters.
This commit is contained in:
parent
ab97168e4f
commit
42ecbcad10
3 changed files with 172 additions and 0 deletions
49
app/validators/qualified_domain_array_validator.rb
Normal file
49
app/validators/qualified_domain_array_validator.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# QualifiedDomainArrayValidator
|
||||
#
|
||||
# Custom validator for URL hosts/'qualified domains' (FQDNs, ex: gitlab.com, sub.example.com).
|
||||
# This does not check if the domain actually exists. It only checks if it is a
|
||||
# valid domain string.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# class ApplicationSetting < ApplicationRecord
|
||||
# validates :outbound_local_requests_whitelist, qualified_domain_array: true
|
||||
# end
|
||||
#
|
||||
class QualifiedDomainArrayValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
validate_value_present(record, attribute, value)
|
||||
validate_host_length(record, attribute, value)
|
||||
validate_idna_encoding(record, attribute, value)
|
||||
validate_sanitization(record, attribute, value)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_value_present(record, attribute, value)
|
||||
return unless value.blank?
|
||||
|
||||
record.errors.add(attribute, _('entries cannot be blank'))
|
||||
end
|
||||
|
||||
def validate_host_length(record, attribute, value)
|
||||
return unless value&.any? { |entry| entry.size > 255 }
|
||||
|
||||
record.errors.add(attribute, _('entries cannot be larger than 255 characters'))
|
||||
end
|
||||
|
||||
def validate_idna_encoding(record, attribute, value)
|
||||
return if value&.all?(&:ascii_only?)
|
||||
|
||||
record.errors.add(attribute, _('unicode domains should use IDNA encoding'))
|
||||
end
|
||||
|
||||
def validate_sanitization(record, attribute, value)
|
||||
sanitizer = Rails::Html::FullSanitizer.new
|
||||
return unless value&.any? { |str| sanitizer.sanitize(str) != str }
|
||||
|
||||
record.errors.add(attribute, _('entries cannot contain HTML tags'))
|
||||
end
|
||||
end
|
|
@ -12803,6 +12803,15 @@ msgstr ""
|
|||
msgid "encrypted: needs to be a :required, :optional or :migrating!"
|
||||
msgstr ""
|
||||
|
||||
msgid "entries cannot be blank"
|
||||
msgstr ""
|
||||
|
||||
msgid "entries cannot be larger than 255 characters"
|
||||
msgstr ""
|
||||
|
||||
msgid "entries cannot contain HTML tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "error"
|
||||
msgstr ""
|
||||
|
||||
|
@ -13308,6 +13317,9 @@ msgstr ""
|
|||
msgid "triggered"
|
||||
msgstr ""
|
||||
|
||||
msgid "unicode domains should use IDNA encoding"
|
||||
msgstr ""
|
||||
|
||||
msgid "updated"
|
||||
msgstr ""
|
||||
|
||||
|
|
111
spec/validators/qualified_domain_array_validator_spec.rb
Normal file
111
spec/validators/qualified_domain_array_validator_spec.rb
Normal file
|
@ -0,0 +1,111 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe QualifiedDomainArrayValidator do
|
||||
class TestClass
|
||||
include ActiveModel::Validations
|
||||
|
||||
attr_accessor :domain_array
|
||||
|
||||
def initialize(domain_array)
|
||||
self.domain_array = domain_array
|
||||
end
|
||||
end
|
||||
|
||||
let!(:record) do
|
||||
TestClass.new(['gitlab.com'])
|
||||
end
|
||||
|
||||
subject { validator.validate(record) }
|
||||
|
||||
shared_examples 'cannot be blank' do
|
||||
it 'returns error when attribute is blank' do
|
||||
record.domain_array = []
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_present
|
||||
expect(record.errors.first[1]).to eq 'entries cannot be blank'
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'can be nil' do
|
||||
it 'allows when attribute is nil' do
|
||||
record.domain_array = nil
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
let(:validator) { described_class.new(attributes: [:domain_array]) }
|
||||
|
||||
it_behaves_like 'cannot be blank'
|
||||
|
||||
it 'returns error when attribute is nil' do
|
||||
record.domain_array = nil
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_present
|
||||
end
|
||||
|
||||
it 'allows when domain is valid' do
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_empty
|
||||
end
|
||||
|
||||
it 'returns error when domain contains unicode' do
|
||||
record.domain_array = ['ğitlab.com']
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_present
|
||||
expect(record.errors.first[1]).to eq 'unicode domains should use IDNA encoding'
|
||||
end
|
||||
|
||||
it 'returns error when entry is larger than 255 chars' do
|
||||
record.domain_array = ['a' * 256]
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_present
|
||||
expect(record.errors.first[1]).to eq 'entries cannot be larger than 255 characters'
|
||||
end
|
||||
|
||||
it 'returns error when entry contains HTML tags' do
|
||||
record.domain_array = ['gitlab.com<h1>something</h1>']
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_present
|
||||
expect(record.errors.first[1]).to eq 'entries cannot contain HTML tags'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when allow_nil is set to true' do
|
||||
let(:validator) { described_class.new(attributes: [:domain_array], allow_nil: true) }
|
||||
|
||||
it_behaves_like 'can be nil'
|
||||
|
||||
it_behaves_like 'cannot be blank'
|
||||
end
|
||||
|
||||
context 'when allow_blank is set to true' do
|
||||
let(:validator) { described_class.new(attributes: [:domain_array], allow_blank: true) }
|
||||
|
||||
it_behaves_like 'can be nil'
|
||||
|
||||
it 'allows when attribute is blank' do
|
||||
record.domain_array = []
|
||||
|
||||
subject
|
||||
|
||||
expect(record.errors).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue