mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 09:26:54 -06:00
Apply security fixes as a monkey^M^M^M^M^M^Mfreedom patch
This commit is contained in:
parent
c518ad0cc1
commit
1f0b28b069
124
lib/freedom_patches/rails_security_fixes.rb
Normal file
124
lib/freedom_patches/rails_security_fixes.rb
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
module HTML
|
||||||
|
class WhiteListSanitizer
|
||||||
|
# Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute
|
||||||
|
def sanitize_css(style)
|
||||||
|
# disallow urls
|
||||||
|
style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ')
|
||||||
|
|
||||||
|
# gauntlet
|
||||||
|
if style !~ /\A([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*\z/ ||
|
||||||
|
style !~ /\A(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*\z/
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
|
||||||
|
clean = []
|
||||||
|
style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop,val|
|
||||||
|
if allowed_css_properties.include?(prop.downcase)
|
||||||
|
clean << prop + ': ' + val + ';'
|
||||||
|
elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
|
||||||
|
unless val.split().any? do |keyword|
|
||||||
|
!allowed_css_keywords.include?(keyword) &&
|
||||||
|
keyword !~ /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/
|
||||||
|
end
|
||||||
|
clean << prop + ': ' + val + ';'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
clean.join(' ')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module HTML
|
||||||
|
class WhiteListSanitizer
|
||||||
|
self.protocol_separator = /:|(�*58)|(p)|(�*3a)|(%|%)3A/i
|
||||||
|
|
||||||
|
def contains_bad_protocols?(attr_name, value)
|
||||||
|
uri_attributes.include?(attr_name) &&
|
||||||
|
(value =~ /(^[^\/:]*):|(�*58)|(p)|(�*3a)|(%|%)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ActiveRecord
|
||||||
|
class Relation
|
||||||
|
|
||||||
|
def where_values_hash
|
||||||
|
equalities = with_default_scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|
|
||||||
|
node.left.relation.name == table_name
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash[equalities.map { |where| [where.left.name, where.right] }].with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ActiveRecord
|
||||||
|
class PredicateBuilder # :nodoc:
|
||||||
|
def self.build_from_hash(engine, attributes, default_table, allow_table_name = true)
|
||||||
|
predicates = attributes.map do |column, value|
|
||||||
|
table = default_table
|
||||||
|
|
||||||
|
if allow_table_name && value.is_a?(Hash)
|
||||||
|
table = Arel::Table.new(column, engine)
|
||||||
|
|
||||||
|
if value.empty?
|
||||||
|
'1 = 2'
|
||||||
|
else
|
||||||
|
build_from_hash(engine, value, table, false)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
column = column.to_s
|
||||||
|
|
||||||
|
if allow_table_name && column.include?('.')
|
||||||
|
table_name, column = column.split('.', 2)
|
||||||
|
table = Arel::Table.new(table_name, engine)
|
||||||
|
end
|
||||||
|
|
||||||
|
attribute = table[column]
|
||||||
|
|
||||||
|
case value
|
||||||
|
when ActiveRecord::Relation
|
||||||
|
value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
|
||||||
|
attribute.in(value.arel.ast)
|
||||||
|
when Array, ActiveRecord::Associations::CollectionProxy
|
||||||
|
values = value.to_a.map {|x| x.is_a?(ActiveRecord::Base) ? x.id : x}
|
||||||
|
ranges, values = values.partition {|v| v.is_a?(Range) || v.is_a?(Arel::Relation)}
|
||||||
|
|
||||||
|
array_predicates = ranges.map {|range| attribute.in(range)}
|
||||||
|
|
||||||
|
if values.include?(nil)
|
||||||
|
values = values.compact
|
||||||
|
if values.empty?
|
||||||
|
array_predicates << attribute.eq(nil)
|
||||||
|
else
|
||||||
|
array_predicates << attribute.in(values.compact).or(attribute.eq(nil))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
array_predicates << attribute.in(values)
|
||||||
|
end
|
||||||
|
|
||||||
|
array_predicates.inject {|composite, predicate| composite.or(predicate)}
|
||||||
|
when Range, Arel::Relation
|
||||||
|
attribute.in(value)
|
||||||
|
when ActiveRecord::Base
|
||||||
|
attribute.eq(value.id)
|
||||||
|
when Class
|
||||||
|
# FIXME: I think we need to deprecate this behavior
|
||||||
|
attribute.eq(value.name)
|
||||||
|
when Integer, ActiveSupport::Duration
|
||||||
|
# Arel treats integers as literals, but they should be quoted when compared with strings
|
||||||
|
column = engine.connection.schema_cache.columns_hash[table.name][attribute.name.to_s]
|
||||||
|
attribute.eq(Arel::Nodes::SqlLiteral.new(engine.connection.quote(value, column)))
|
||||||
|
else
|
||||||
|
attribute.eq(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
predicates.flatten
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user