Class: PAK::ValidatesHostname::HostnameValidator

Inherits:
ActiveModel::EachValidator
  • Object
show all
Defined in:
lib/validates_hostname.rb

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ HostnameValidator

Returns a new instance of HostnameValidator.



166
167
168
169
170
171
172
173
174
175
176
# File 'lib/validates_hostname.rb', line 166

def initialize(options)
  opts = {
    :allow_underscore        => false,
    :require_valid_tld       => false,
    :valid_tlds              => ALLOWED_TLDS,
    :allow_numeric_hostname  => false,
    :allow_wildcard_hostname => false,
    :allow_root_label        => false
  }.merge(options)
  super(opts)
end

Instance Method Details

#add_error(record, attr_name, message, *interpolators) ⇒ Object



236
237
238
239
240
241
242
# File 'lib/validates_hostname.rb', line 236

def add_error(record, attr_name, message, *interpolators)
  args = {
    :default => [DEFAULT_ERROR_MSG[message], options[:message]],
    :scope   => [:errors, :messages]
  }.merge(interpolators.last.is_a?(Hash) ? interpolators.pop : {})
  record.errors.add(attr_name, I18n.t( message, args ))
end

#validate_each(record, attribute, value) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/validates_hostname.rb', line 178

def validate_each(record, attribute, value)
  value ||= ''

  # maximum hostname length: 255 characters
  add_error(record, attribute, :invalid_hostname_length) unless value.length.between?(1, 255)

  # split each hostname into labels and do various checks
  if value.is_a?(String)
    labels = value.split '.'
    labels.each_with_index do |label, index|
      # CHECK 1: hostname label cannot be longer than 63 characters
      add_error(record, attribute, :invalid_label_length) unless label.length.between?(1, 63)

      # CHECK 2: hostname label cannot begin or end with hyphen
      add_error(record, attribute, :label_begins_or_ends_with_hyphen) if label =~ /^[-]/i or label =~ /[-]$/

      # Take care of wildcard first label
      next if options[:allow_wildcard_hostname] and label == '*' and index == 0

      # CHECK 3: hostname can only contain characters:
      #          a-z, 0-9, hyphen, optional underscore, optional asterisk
      valid_chars = 'a-z0-9\-'
      valid_chars << '_' if options[:allow_underscore] == true
      add_error(record, attribute, :label_contains_invalid_characters, :valid_chars => valid_chars) unless label =~ /^[#{valid_chars}]+$/i
    end

    # CHECK 4: the unqualified hostname portion cannot consist of
    #          numeric values only
    if options[:allow_numeric_hostname] == false and labels.length > 0
      is_numeric_only = labels[0] =~ /\A\d+\z/
      add_error(record, attribute, :hostname_label_is_numeric) if is_numeric_only
    end

    # CHECK 5: in order to be fully qualified, the full hostname's
    #          TLD must be valid
    if options[:require_valid_tld] == true
      my_tld = value == '.' ? value : labels.last
      my_tld ||= ''
      has_tld = options[:valid_tlds].select {
        |tld| tld =~ /^#{Regexp.escape(my_tld)}$/i
      }.empty? ? false : true
      add_error(record, attribute, :hostname_is_not_fqdn) unless has_tld
    end

    # CHECK 6: hostname may not contain consecutive dots
    if value =~ /\.\./
      add_error(record, attribute, :hostname_contains_consecutive_dots)
    end

    # CHECK 7: do not allow trailing dot unless option is set
    if options[:allow_root_label] == false
      if value =~ /\.$/
        add_error(record, attribute, :hostname_ends_with_dot)
      end
    end
  end
end