diff options
Diffstat (limited to 'activemodel/lib/active_model/validations')
-rw-r--r-- | activemodel/lib/active_model/validations/format.rb | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index dd87e312f9..ffdf842d94 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -32,11 +32,21 @@ module ActiveModel def record_error(record, attribute, name, value) record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value)) end - + + def regexp_using_multiline_anchors?(regexp) + regexp.source.start_with?("^") || + (regexp.source.end_with?("$") && !regexp.source.end_with?("\\$")) + end + def check_options_validity(options, name) option = options[name] if option && !option.is_a?(Regexp) && !option.respond_to?(:call) raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}" + elsif option && option.is_a?(Regexp) && + regexp_using_multiline_anchors?(option) && options[:multiline] != true + raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \ + "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \ + ":multiline => true option?" end end end @@ -47,7 +57,7 @@ module ActiveModel # attribute matches the regular expression: # # class Person < ActiveRecord::Base - # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create + # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :on => :create # end # # Alternatively, you can require that the specified attribute does _not_ @@ -63,12 +73,16 @@ module ActiveModel # class Person < ActiveRecord::Base # # Admin can have number as a first letter in their screen name # validates_format_of :screen_name, - # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i } + # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i } # end # # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line. # + # Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass the + # :multiline => true option in case you use any of these two anchors in the provided + # regular expression. In most cases, you should be using <tt>\A</tt> and <tt>\z</tt>. + # # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. # In addition, both must be a regular expression or a proc or lambda, or # else an exception will be raised. @@ -98,6 +112,9 @@ module ActiveModel # method, proc or string should return or evaluate to a true or false value. # * <tt>:strict</tt> - Specifies whether validation should be strict. # See <tt>ActiveModel::Validation#validates!</tt> for more information. + # * <tt>:multiline</tt> - Set to true if your regular expression contains + # anchors that match the beginning or end of lines as opposed to the + # beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>. def validates_format_of(*attr_names) validates_with FormatValidator, _merge_attributes(attr_names) end |