10-patches.rb 7.49 KB
Newer Older
1
#-- encoding: UTF-8
2 3
#-- copyright
# ChiliProject is a project management system.
4
#
Holger Just's avatar
Holger Just committed
5
# Copyright (C) 2010-2013 the ChiliProject Team
6
#
7 8 9 10
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
11
#
12 13 14
# See doc/COPYRIGHT.rdoc for more details.
#++

15 16
# Patches active_support/core_ext/load_error.rb to support 1.9.3 LoadError message
if RUBY_VERSION >= '1.9.3'
Holger Just's avatar
Holger Just committed
17
  MissingSourceFile::REGEXPS << [/^cannot load such file -- (.+)$/i, 1]
18
end
19

20
require 'active_record'
21 22 23 24

module ActiveRecord
  class Base
    include Redmine::I18n
25

26 27 28 29 30 31 32
    # Translate attribute names for validation errors display
    def self.human_attribute_name(attr)
      l("field_#{attr.to_s.gsub(/_id$/, '')}")
    end
  end
end

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
module ActiveRecord
  class Errors
    def full_messages(options = {})
      full_messages = []

      @errors.each_key do |attr|
        @errors[attr].each do |message|
          next unless message

          if attr == "base"
            full_messages << message
          elsif attr == "custom_values"
            # Replace the generic "custom values is invalid"
            # with the errors on custom values
            @base.custom_values.each do |value|
              value.errors.each do |attr, msg|
                full_messages << value.custom_field.name + ' ' + msg
              end
            end
          else
            attr_name = @base.class.human_attribute_name(attr)
54
            full_messages << attr_name + ' ' + message.to_s
55 56 57 58 59 60 61 62
          end
        end
      end
      full_messages
    end
  end
end

63 64 65 66 67 68 69 70 71 72 73
module ActionView
  module Helpers
    module DateHelper
      # distance_of_time_in_words breaks when difference is greater than 30 years
      def distance_of_date_in_words(from_date, to_date = 0, options = {})
        from_date = from_date.to_date if from_date.respond_to?(:to_date)
        to_date = to_date.to_date if to_date.respond_to?(:to_date)
        distance_in_days = (to_date - from_date).abs

        I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
          case distance_in_days
74
            when 0..60     then locale.t :x_days,             :count => distance_in_days.round
75
            when 61..720   then locale.t :about_x_months,     :count => (distance_in_days / 30).round
76
            else                locale.t :over_x_years,       :count => (distance_in_days / 365).floor
77 78 79 80 81 82
          end
        end
      end
    end
  end
end
83 84

ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" }
85 86 87 88 89 90 91 92

# Adds :async_smtp and :async_sendmail delivery methods
# to perform email deliveries asynchronously
module AsynchronousMailer
  %w(smtp sendmail).each do |type|
    define_method("perform_delivery_async_#{type}") do |mail|
      Thread.start do
        send "perform_delivery_#{type}", mail
93
      end
94 95 96 97 98
    end
  end
end

ActionMailer::Base.send :include, AsynchronousMailer
99

100 101 102 103 104 105
# TMail::Unquoter.convert_to_with_fallback_on_iso_8859_1 introduced in TMail 1.2.7
# triggers a test failure in test_add_issue_with_japanese_keywords(MailHandlerTest)
module TMail
  class Unquoter
    class << self
      alias_method :convert_to, :convert_to_without_fallback_on_iso_8859_1
106 107 108
    end
  end
end
109 110 111 112 113 114 115 116 117

module ActionController
  module MimeResponds
    class Responder
      def api(&block)
        any(:xml, :json, &block)
      end
    end
  end
118

119 120
  # Backported fix for
  # CVE-2012-2660
121
  # https://groups.google.com/group/rubyonrails-security/browse_thread/thread/f1203e3376acec0f
122 123 124 125 126
  #
  # CVE-2012-2694
  # https://groups.google.com/group/rubyonrails-security/browse_thread/thread/8c82d9df8b401c5e
  #
  # TODO: Remove this once we are on Rails >= 3.2.6
127 128 129 130 131 132
  require 'action_controller/request'
  class Request
    protected

    # Remove nils from the params hash
    def deep_munge(hash)
133 134 135
      keys = hash.keys.find_all { |k| hash[k] == [nil] }
      keys.each { |k| hash[k] = nil }

136 137 138 139
      hash.each_value do |v|
        case v
        when Array
          v.grep(Hash) { |x| deep_munge(x) }
140
          v.compact!
141 142 143 144 145 146 147 148 149 150 151 152
        when Hash
          deep_munge(v)
        end
      end

      hash
    end

    def parse_query(qs)
      deep_munge(super)
    end
  end
153
end
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
# Fix for CVE-2013-0155
# https://groups.google.com/d/msg/rubyonrails-security/kKGNeMrnmiY/r2yM7xy-G48J
# TODO: Remove this once we are on Rails >= 3.2.11
module ActiveRecord
  class Base
    class << self
    protected
      def self.sanitize_sql_hash_for_conditions(attrs, default_table_name = quoted_table_name, top_level = true)
        attrs = expand_hash_conditions_for_aggregates(attrs)

        return '1 = 2' if !top_level && attrs.is_a?(Hash) && attrs.empty?

        conditions = attrs.map do |attr, value|
          table_name = default_table_name

          if not value.is_a?(Hash)
            attr = attr.to_s

            # Extract table name from qualified attribute names.
            if attr.include?('.') and top_level
              attr_table_name, attr = attr.split('.', 2)
              attr_table_name = connection.quote_table_name(attr_table_name)
            else
              attr_table_name = table_name
            end

            attribute_condition("#{attr_table_name}.#{connection.quote_column_name(attr)}", value)
          elsif top_level
            sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s), false)
          else
            raise ActiveRecord::StatementInvalid
          end
        end.join(' AND ')

        replace_bind_variables(conditions, expand_range_bind_variables(attrs.values))
      end
      alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
    end
  end
end

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 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
# Backported fix for CVE-2012-3465
# https://groups.google.com/d/msg/rubyonrails-security/FgVEtBajcTY/tYLS1JJTu38J
# TODO: Remove this once we are on Rails >= 3.2.8
require 'action_view/helpers/sanitize_helper'
module ActionView::Helpers::SanitizeHelper
  def strip_tags(html)
    self.class.full_sanitizer.sanitize(html)
  end
end

# Backported fix for CVE-2012-3464
# https://groups.google.com/d/msg/rubyonrails-security/kKGNeMrnmiY/r2yM7xy-G48J
# TODO: Remove this once we are on Rails >= 3.2.8
require 'active_support/core_ext/string/output_safety'
class ERB
  module Util
    HTML_ESCAPE["'"] = '&#39;'

    if RUBY_VERSION >= '1.9'
      # A utility method for escaping HTML tag characters.
      # This method is also aliased as <tt>h</tt>.
      #
      # In your ERB templates, use this method to escape any unsafe content. For example:
      # <%=h @person.name %>
      #
      # ==== Example:
      # puts html_escape("is a > 0 & a < 10?")
      # # => is a &gt; 0 &amp; a &lt; 10?
      def html_escape(s)
        s = s.to_s
        if s.html_safe?
          s
        else
          s.gsub(/[&"'><]/, HTML_ESCAPE).html_safe
        end
      end
    else
      def html_escape(s) #:nodoc:
        s = s.to_s
        if s.html_safe?
          s
        else
          s.gsub(/[&"'><]/n) { |special| HTML_ESCAPE[special] }.html_safe
        end
      end
    end

    # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
    remove_method(:h)
    alias h html_escape

    module_function :h

    singleton_class.send(:remove_method, :html_escape)
    module_function :html_escape
  end
end
require 'action_view/helpers/tag_helper'
module ActionView::Helpers::TagHelper
  def escape_once(html)
    ActiveSupport::Multibyte.clean(html.to_s).gsub(/[\"\'><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
  end
end