Module: Hanami::Utils::Escape

Defined in:
gems/gems/hanami-utils-1.3.0/lib/hanami/utils/escape.rb

Overview

HTML escape utilities

Based on OWASP research and OWASP ESAPI code

Class Method Summary collapse

Class Method Details

.html(input) ⇒ String

Escape HTML contents

This MUST be used only for tag contents. Please use html_attribute for escaping HTML attributes.

Examples:

Good practice

<div><%= Hanami::Utils::Escape.html('<script>alert(1);</script>') %></div>
<div>&lt;script&gt;alert(1);&lt;&#x2F;script&gt;</div>

Bad practice

# WRONG Use Escape.html_attribute instead
<a title="<%= Hanami::Utils::Escape.html('...') %>">link</a>

Parameters:

  • input (String)

    the input

Returns:

  • (String)

    the escaped string

See Also:

Since:

  • 0.4.0

def self.html(input)
  input = encode(input)
  return input if input.is_a?(SafeString)

  result = SafeString.new

  input.each_char do |chr|
    result << HTML_CHARS.fetch(chr, chr)
  end

  result
end

.html_attribute(input) ⇒ String

Escape HTML attributes

This can be used both for HTML attributes and contents. Please note that this is more computational expensive. If you need to escape only HTML contents, please use .html.

Examples:

Good practice

<a title="<%= Hanami::Utils::Escape.html_attribute('...') %>">link</a>

Good but expensive practice

# Alternatively you can use Escape.html
<p><%= Hanami::Utils::Escape.html_attribute('...') %></p>

Parameters:

  • input (String)

    the input

Returns:

  • (String)

    the escaped string

See Also:

Since:

  • 0.4.0

def self.html_attribute(input)
  input = encode(input)
  return input if input.is_a?(SafeString)

  result = SafeString.new

  input.each_char do |chr|
    result << encode_char(chr, HTML_ATTRIBUTE_SAFE_CHARS)
  end

  result
end

.url(input, schemes = DEFAULT_URL_SCHEMES) ⇒ String

Escape URL for HTML attributes (href, src, etc..).

It extracts from the given input the first valid URL that matches the whitelisted schemes (default: http, https and mailto).

It's possible to pass a second optional argument to specify different schemes.

Examples:

Basic usage

<%
  good_input = "http://hanamirb.org"
  evil_input = "javascript:alert('xss')"

  escaped_good_input = Hanami::Utils::Escape.url(good_input) # => "http://hanamirb.org"
  escaped_evil_input = Hanami::Utils::Escape.url(evil_input) # => ""
%>

<a href="<%= escaped_good_input %>">personal website</a>
<a href="<%= escaped_evil_input %>">personal website</a>

Custom scheme

<%
  schemes  = ['ftp', 'ftps']

  accepted = "ftps://ftp.example.org"
  rejected = "http://www.example.org"

  escaped_accepted = Hanami::Utils::Escape.url(accepted) # => "ftps://ftp.example.org"
  escaped_rejected = Hanami::Utils::Escape.url(rejected) # => ""
%>

<a href="<%= escaped_accepted %>">FTP</a>
<a href="<%= escaped_rejected %>">FTP</a>

Parameters:

  • input (String)

    the input

  • schemes (Array<String>) (defaults to: DEFAULT_URL_SCHEMES)

    an array of whitelisted schemes

Returns:

  • (String)

    the escaped string

See Also:

Since:

  • 0.4.0

def self.url(input, schemes = DEFAULT_URL_SCHEMES)
  input = encode(input)
  return input if input.is_a?(SafeString)

  SafeString.new(
    URI::DEFAULT_PARSER.extract(
      URI.decode_www_form_component(input),
      schemes
    ).first.to_s
  )
end