sinatra/rack-protection/lib/rack/protection/escaped_params.rb

90 lines
2.3 KiB
Ruby

require 'rack/protection'
require 'rack/utils'
require 'tempfile'
begin
require 'escape_utils'
rescue LoadError
end
module Rack
module Protection
##
# Prevented attack:: XSS
# Supported browsers:: all
# More infos:: http://en.wikipedia.org/wiki/Cross-site_scripting
#
# Automatically escapes Rack::Request#params so they can be embedded in HTML
# or JavaScript without any further issues. Calls +html_safe+ on the escaped
# strings if defined, to avoid double-escaping in Rails.
#
# Options:
# escape:: What escaping modes to use, should be Symbol or Array of Symbols.
# Available: :html (default), :javascript, :url
class EscapedParams < Base
extend Rack::Utils
class << self
alias escape_url escape
public :escape_html
end
default_options :escape => :html,
:escaper => defined?(EscapeUtils) ? EscapeUtils : self
def initialize(*)
super
modes = Array options[:escape]
@escaper = options[:escaper]
@html = modes.include? :html
@javascript = modes.include? :javascript
@url = modes.include? :url
if @javascript and not @escaper.respond_to? :escape_javascript
fail("Use EscapeUtils for JavaScript escaping.")
end
end
def call(env)
request = Request.new(env)
get_was = handle(request.GET)
post_was = handle(request.POST) rescue nil
app.call env
ensure
request.GET.replace get_was if get_was
request.POST.replace post_was if post_was
end
def handle(hash)
was = hash.dup
hash.replace escape(hash)
was
end
def escape(object)
case object
when Hash then escape_hash(object)
when Array then object.map { |o| escape(o) }
when String then escape_string(object)
when Tempfile then object
else nil
end
end
def escape_hash(hash)
hash = hash.dup
hash.each { |k,v| hash[k] = escape(v) }
hash
end
def escape_string(str)
str = @escaper.escape_url(str) if @url
str = @escaper.escape_html(str) if @html
str = @escaper.escape_javascript(str) if @javascript
str
end
end
end
end