Module: Air18n::XssDetector

Defined in:
lib/air18n/xss_detector.rb

Class Method Summary collapse

Class Method Details

.extract_tags(text) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/air18n/xss_detector.rb', line 27

def extract_tags(text)
  i = 0
  tags = []
  opened = 0
  next_bracket = 0
  while open_index = text.index('<', i)
    opened += 1
    next_bracket = open_index
    while opened > 0 && next_bracket && next_bracket = text.index(/>|</, next_bracket + 1)
      opened += text[next_bracket] == '<' ? 1 : -1
    end
    if next_bracket.nil?
      # There is an open bracket with no close bracket.
      tags << text[open_index..-1]
      break
    end
    if next_bracket > 0
      tags << text[open_index..next_bracket]
      i = next_bracket
    end
  end
  tags
end

.has_dubious_escape_characters?(text) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/air18n/xss_detector.rb', line 23

def has_dubious_escape_characters?(text)
  text.include?('\\')
end

.normalize_tags(tags) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/air18n/xss_detector.rb', line 51

def normalize_tags(tags)
  tags.map do |tag|
    # Normalize double-quotes to single-quotes to allow differences in type
    # of quotation mark.
    tag.gsub('"', "'")
  end
end

.safe?(text_a, text_b, locale_a, locale_b) ⇒ Boolean

Returns:

  • (Boolean)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/air18n/xss_detector.rb', line 5

def safe?(text_a, text_b, locale_a, locale_b)
  text_a = text_a.to_s
  text_b = text_b.to_s
  tags_a = normalize_tags(extract_tags(text_a))
  tags_b = normalize_tags(extract_tags(text_b))
  if SmartCount::applies?(text_a) || SmartCount::applies?(text_b)
    tags_a = SmartCount::dedupe_things_like_tags_or_variables(locale_a, tags_a)
    tags_b = SmartCount::dedupe_things_like_tags_or_variables(locale_b, tags_b)
  end
  if has_dubious_escape_characters?(text_a) || has_dubious_escape_characters?(text_b)
    { :safe => false, :reason => 'Backslashes are not allowed' }
  elsif tags_a.group_by{|t| t} != tags_b.group_by{|t| t}
    { :safe => false, :reason => "HTML tags don't match: #{tags_a.inspect} vs. #{tags_b.inspect}" }
  else
    { :safe => true }
  end
end