loofah 2.7.0 → 2.19.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +107 -0
- data/README.md +13 -12
- data/lib/loofah/elements.rb +5 -2
- data/lib/loofah/html5/safelist.rb +262 -27
- data/lib/loofah/html5/scrub.rb +135 -40
- data/lib/loofah/instance_methods.rb +9 -5
- data/lib/loofah/scrubber.rb +4 -0
- data/lib/loofah/scrubbers.rb +9 -8
- data/lib/loofah/version.rb +5 -0
- data/lib/loofah.rb +13 -15
- metadata +40 -137
- data/Gemfile +0 -24
- data/Manifest.txt +0 -25
- data/Rakefile +0 -97
- data/benchmark/benchmark.rb +0 -154
- data/benchmark/fragment.html +0 -96
- data/benchmark/helper.rb +0 -73
- data/benchmark/www.slashdot.com.html +0 -2560
data/Gemfile
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# -*- ruby -*-
|
2
|
-
|
3
|
-
# DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`.
|
4
|
-
|
5
|
-
source "https://rubygems.org/"
|
6
|
-
|
7
|
-
gem "nokogiri", ">=1.5.9"
|
8
|
-
gem "crass", "~>1.0.2"
|
9
|
-
|
10
|
-
gem "rake", "~>12.3", :group => [:development, :test]
|
11
|
-
gem "minitest", "~>2.2", :group => [:development, :test]
|
12
|
-
gem "rr", "~>1.2.0", :group => [:development, :test]
|
13
|
-
gem "json", "~>2.3.0", :group => [:development, :test]
|
14
|
-
gem "hoe-gemspec", "~>1.0", :group => [:development, :test]
|
15
|
-
gem "hoe-debugging", "~>2.0", :group => [:development, :test]
|
16
|
-
gem "hoe-bundler", "~>1.5", :group => [:development, :test]
|
17
|
-
gem "hoe-git", "~>1.6", :group => [:development, :test]
|
18
|
-
gem "hoe-markdown", "~>1.2", :group => [:development, :test]
|
19
|
-
gem "concourse", ">=0.26.0", :group => [:development, :test]
|
20
|
-
gem "rubocop", ">=0.76.0", :group => [:development, :test]
|
21
|
-
gem "rdoc", ">=4.0", "<7", :group => [:development, :test]
|
22
|
-
gem "hoe", "~>3.22", :group => [:development, :test]
|
23
|
-
|
24
|
-
# vim: syntax=ruby
|
data/Manifest.txt
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
CHANGELOG.md
|
2
|
-
Gemfile
|
3
|
-
MIT-LICENSE.txt
|
4
|
-
Manifest.txt
|
5
|
-
README.md
|
6
|
-
Rakefile
|
7
|
-
SECURITY.md
|
8
|
-
benchmark/benchmark.rb
|
9
|
-
benchmark/fragment.html
|
10
|
-
benchmark/helper.rb
|
11
|
-
benchmark/www.slashdot.com.html
|
12
|
-
lib/loofah.rb
|
13
|
-
lib/loofah/elements.rb
|
14
|
-
lib/loofah/helpers.rb
|
15
|
-
lib/loofah/html/document.rb
|
16
|
-
lib/loofah/html/document_fragment.rb
|
17
|
-
lib/loofah/html5/libxml2_workarounds.rb
|
18
|
-
lib/loofah/html5/safelist.rb
|
19
|
-
lib/loofah/html5/scrub.rb
|
20
|
-
lib/loofah/instance_methods.rb
|
21
|
-
lib/loofah/metahelpers.rb
|
22
|
-
lib/loofah/scrubber.rb
|
23
|
-
lib/loofah/scrubbers.rb
|
24
|
-
lib/loofah/xml/document.rb
|
25
|
-
lib/loofah/xml/document_fragment.rb
|
data/Rakefile
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
require "rubygems"
|
2
|
-
require "hoe"
|
3
|
-
require "concourse"
|
4
|
-
|
5
|
-
Hoe.plugin :git
|
6
|
-
Hoe.plugin :gemspec
|
7
|
-
Hoe.plugin :bundler
|
8
|
-
Hoe.plugin :debugging
|
9
|
-
Hoe.plugin :markdown
|
10
|
-
|
11
|
-
Hoe.spec "loofah" do
|
12
|
-
developer "Mike Dalessio", "mike.dalessio@gmail.com"
|
13
|
-
developer "Bryan Helmkamp", "bryan@brynary.com"
|
14
|
-
|
15
|
-
self.license "MIT"
|
16
|
-
self.urls = {
|
17
|
-
"home" => "https://github.com/flavorjones/loofah",
|
18
|
-
"bugs" => "https://github.com/flavorjones/loofah/issues",
|
19
|
-
"doco" => "https://www.rubydoc.info/gems/loofah/",
|
20
|
-
"clog" => "https://github.com/flavorjones/loofah/blob/master/CHANGELOG.md",
|
21
|
-
"code" => "https://github.com/flavorjones/loofah",
|
22
|
-
}
|
23
|
-
|
24
|
-
extra_deps << ["nokogiri", ">=1.5.9"]
|
25
|
-
extra_deps << ["crass", "~> 1.0.2"]
|
26
|
-
|
27
|
-
extra_dev_deps << ["rake", "~> 12.3"]
|
28
|
-
extra_dev_deps << ["minitest", "~>2.2"]
|
29
|
-
extra_dev_deps << ["rr", "~>1.2.0"]
|
30
|
-
extra_dev_deps << ["json", "~> 2.3.0"]
|
31
|
-
extra_dev_deps << ["hoe-gemspec", "~> 1.0"]
|
32
|
-
extra_dev_deps << ["hoe-debugging", "~> 2.0"]
|
33
|
-
extra_dev_deps << ["hoe-bundler", "~> 1.5"]
|
34
|
-
extra_dev_deps << ["hoe-git", "~> 1.6"]
|
35
|
-
extra_dev_deps << ["hoe-markdown", "~> 1.2"]
|
36
|
-
extra_dev_deps << ["concourse", ">=0.26.0"]
|
37
|
-
extra_dev_deps << ["rubocop", ">=0.76.0"]
|
38
|
-
end
|
39
|
-
|
40
|
-
task :gemspec do
|
41
|
-
system %q(rake debug_gem | grep -v "^\(in " > loofah.gemspec)
|
42
|
-
end
|
43
|
-
|
44
|
-
task :redocs => :fix_css
|
45
|
-
task :docs => :fix_css
|
46
|
-
task :fix_css do
|
47
|
-
better_css = <<-EOT
|
48
|
-
.method-description pre {
|
49
|
-
margin : 1em 0 ;
|
50
|
-
}
|
51
|
-
|
52
|
-
.method-description ul {
|
53
|
-
padding : .5em 0 .5em 2em ;
|
54
|
-
}
|
55
|
-
|
56
|
-
.method-description p {
|
57
|
-
margin-top : .5em ;
|
58
|
-
}
|
59
|
-
|
60
|
-
#main ul, div#documentation ul {
|
61
|
-
list-style-type : disc ! IMPORTANT ;
|
62
|
-
list-style-position : inside ! IMPORTANT ;
|
63
|
-
}
|
64
|
-
|
65
|
-
h2 + ul {
|
66
|
-
margin-top : 1em;
|
67
|
-
}
|
68
|
-
EOT
|
69
|
-
puts "* fixing css"
|
70
|
-
File.open("doc/rdoc.css", "a") { |f| f.write better_css }
|
71
|
-
end
|
72
|
-
|
73
|
-
desc "generate and upload docs to rubyforge"
|
74
|
-
task :doc_upload_to_rubyforge => :docs do
|
75
|
-
Dir.chdir "doc" do
|
76
|
-
system "rsync -avz --delete * rubyforge.org:/var/www/gforge-projects/loofah/loofah"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
desc "generate safelists from W3C specifications"
|
81
|
-
task :generate_safelists do
|
82
|
-
load "tasks/generate-safelists"
|
83
|
-
end
|
84
|
-
|
85
|
-
task :rubocop => [:rubocop_security, :rubocop_frozen_string_literals]
|
86
|
-
task :rubocop_security do
|
87
|
-
sh "rubocop lib --only Security"
|
88
|
-
end
|
89
|
-
task :rubocop_frozen_string_literals do
|
90
|
-
sh "rubocop lib --auto-correct --only Style/FrozenStringLiteralComment"
|
91
|
-
end
|
92
|
-
Rake::Task[:test].prerequisites << :rubocop
|
93
|
-
|
94
|
-
Concourse.new("loofah", fly_target: "ci") do |c|
|
95
|
-
c.add_pipeline "loofah", "loofah.yml"
|
96
|
-
c.add_pipeline "loofah-pr", "loofah-pr.yml"
|
97
|
-
end
|
data/benchmark/benchmark.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require "#{File.dirname(__FILE__)}/helper.rb"
|
3
|
-
|
4
|
-
def compare_scrub_methods
|
5
|
-
snip = "<div>foo</div><foo>fuxx <b>quux</b></foo><script>i have a chair</script>"
|
6
|
-
puts "starting with:\n#{snip}"
|
7
|
-
puts
|
8
|
-
puts RailsSanitize.new.sanitize(snip) # => Rails.sanitize / scrub!(:prune).to_s
|
9
|
-
puts Loofah::Helpers.sanitize(snip)
|
10
|
-
puts "--"
|
11
|
-
puts RailsSanitize.new.strip_tags(snip) # => Rails.strip_tags / parse().text
|
12
|
-
puts Loofah::Helpers.strip_tags(snip)
|
13
|
-
puts "--"
|
14
|
-
puts Sanitize.clean(snip, Sanitize::Config::RELAXED) # => scrub!(:strip).to_s
|
15
|
-
puts Loofah.scrub_fragment(snip, :strip).to_s
|
16
|
-
puts "--"
|
17
|
-
puts HTML5libSanitize.new.sanitize(snip) # => scrub!(:escape).to_s
|
18
|
-
puts Loofah.scrub_fragment(snip, :escape).to_s
|
19
|
-
puts "--"
|
20
|
-
puts HTMLFilter.new.filter(snip)
|
21
|
-
puts Loofah.scrub_fragment(snip, :strip).to_s
|
22
|
-
puts
|
23
|
-
end
|
24
|
-
|
25
|
-
module TestSet
|
26
|
-
def test_set(options = {})
|
27
|
-
scale = options[:rehearse] ? 10 : 1
|
28
|
-
puts self.class.name
|
29
|
-
|
30
|
-
n = 100 / scale
|
31
|
-
puts " Large document, #{BIG_FILE.length} bytes (x#{n})"
|
32
|
-
bench BIG_FILE, n, false
|
33
|
-
puts
|
34
|
-
|
35
|
-
n = 1000 / scale
|
36
|
-
puts " Small fragment, #{FRAGMENT.length} bytes (x#{n})"
|
37
|
-
bench FRAGMENT, n, true
|
38
|
-
puts
|
39
|
-
|
40
|
-
n = 10_000 / scale
|
41
|
-
puts " Text snippet, #{SNIPPET.length} bytes (x#{n})"
|
42
|
-
bench SNIPPET, n, true
|
43
|
-
puts
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class HeadToHead < Measure
|
48
|
-
end
|
49
|
-
|
50
|
-
class HeadToHeadRailsSanitize < Measure
|
51
|
-
include TestSet
|
52
|
-
|
53
|
-
def bench(content, ntimes, fragment_p)
|
54
|
-
clear_measure
|
55
|
-
|
56
|
-
measure "Loofah::Helpers.sanitize", ntimes do
|
57
|
-
Loofah::Helpers.sanitize content
|
58
|
-
end
|
59
|
-
|
60
|
-
sanitizer = RailsSanitize.new
|
61
|
-
measure "ActionView sanitize", ntimes do
|
62
|
-
sanitizer.sanitize(content)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
class HeadToHeadRailsStripTags < Measure
|
68
|
-
include TestSet
|
69
|
-
|
70
|
-
def bench(content, ntimes, fragment_p)
|
71
|
-
clear_measure
|
72
|
-
|
73
|
-
measure "Loofah::Helpers.strip_tags", ntimes do
|
74
|
-
Loofah::Helpers.strip_tags content
|
75
|
-
end
|
76
|
-
|
77
|
-
sanitizer = RailsSanitize.new
|
78
|
-
measure "ActionView strip_tags", ntimes do
|
79
|
-
sanitizer.strip_tags(content)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class HeadToHeadSanitizerSanitize < Measure
|
85
|
-
include TestSet
|
86
|
-
|
87
|
-
def bench(content, ntimes, fragment_p)
|
88
|
-
clear_measure
|
89
|
-
|
90
|
-
measure "Loofah :strip", ntimes do
|
91
|
-
if fragment_p
|
92
|
-
Loofah.scrub_fragment(content, :strip).to_s
|
93
|
-
else
|
94
|
-
Loofah.scrub_document(content, :strip).to_s
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
measure "Sanitize.clean", ntimes do
|
99
|
-
Sanitize.clean(content, Sanitize::Config::RELAXED)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class HeadToHeadHtml5LibSanitize < Measure
|
105
|
-
include TestSet
|
106
|
-
|
107
|
-
def bench(content, ntimes, fragment_p)
|
108
|
-
clear_measure
|
109
|
-
|
110
|
-
measure "Loofah :escape", ntimes do
|
111
|
-
if fragment_p
|
112
|
-
Loofah.scrub_fragment(content, :escape).to_s
|
113
|
-
else
|
114
|
-
Loofah.scrub_document(content, :escape).to_s
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
html5_sanitizer = HTML5libSanitize.new
|
119
|
-
measure "HTML5lib.sanitize", ntimes do
|
120
|
-
html5_sanitizer.sanitize(content)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class HeadToHeadHTMLFilter < Measure
|
126
|
-
include TestSet
|
127
|
-
|
128
|
-
def bench(content, ntimes, fragment_p)
|
129
|
-
clear_measure
|
130
|
-
|
131
|
-
measure "Loofah::Helpers.sanitize", ntimes do
|
132
|
-
Loofah::Helpers.sanitize content
|
133
|
-
end
|
134
|
-
|
135
|
-
sanitizer = HTMLFilter.new
|
136
|
-
measure "HTMLFilter.filter", ntimes do
|
137
|
-
sanitizer.filter(content)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
puts "Nokogiri version: #{Nokogiri::VERSION_INFO.inspect}"
|
143
|
-
puts "Loofah version: #{Loofah::VERSION.inspect}"
|
144
|
-
|
145
|
-
benches = []
|
146
|
-
benches << HeadToHeadRailsSanitize.new
|
147
|
-
benches << HeadToHeadRailsStripTags.new
|
148
|
-
benches << HeadToHeadSanitizerSanitize.new
|
149
|
-
benches << HeadToHeadHtml5LibSanitize.new
|
150
|
-
benches << HeadToHeadHTMLFilter.new
|
151
|
-
puts "---------- rehearsal ----------"
|
152
|
-
benches.each { |bench| bench.test_set :rehearse => true }
|
153
|
-
puts "---------- realsies ----------"
|
154
|
-
benches.each { |bench| bench.test_set }
|
data/benchmark/fragment.html
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
<div id="top_parent"></div>
|
2
|
-
|
3
|
-
<div id="jump">
|
4
|
-
<a href="#main-articles">Stories</a>
|
5
|
-
<br>
|
6
|
-
<a href="#blocks">Slash Boxes</a>
|
7
|
-
<br>
|
8
|
-
<a href="#comments">Comments</a>
|
9
|
-
</div>
|
10
|
-
<a name="topothepage"></a>
|
11
|
-
<div id="doc3" class="yui-t6 index2 mainpage ac ">
|
12
|
-
<div id="hd" >
|
13
|
-
<div id="logo" >
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
<h1><a href="//slashdot.org"><span>Slashdot</span></a></h1>
|
18
|
-
<div id="slogan"><h2>News for nerds, stuff that matters</h2></div>
|
19
|
-
</div>
|
20
|
-
<a href="#articles" class="hidden">Jump to articles</a>
|
21
|
-
<div class="nav">
|
22
|
-
<ul>
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
<li><a href="//slashdot.org/submit.pl" title="Submit a story to Slashdot">Submit Story</a></li>
|
27
|
-
<li><a href="//slashdot.org/help" title="Frequently asked questions on Slashdot">Help</a></li>
|
28
|
-
<li><a href="//slashdot.org/login.pl" onclick="show_login_box(); return false;">Log In</a></li>
|
29
|
-
|
30
|
-
</ul>
|
31
|
-
</div>
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
<div id="fh_picker_search" style="display: block;">
|
38
|
-
<form method="get" action="//slashdot.org/index2.pl">
|
39
|
-
<fieldset class="mode-filter mode-anon">
|
40
|
-
<legend>Search</legend>
|
41
|
-
|
42
|
-
|
43
|
-
<input class="query" type="text" name="fhfilter" value="" id="searchquery"> <input type="button" class="setfhfilter" value="Filter" id="viewsearch" style="display:none"> <input type="submit" class="setsearchfilter" value="Search" id="fhsearch" style="display:none">
|
44
|
-
<noscript><input type="submit" class="setsearchfilter" value="Search"></noscript>
|
45
|
-
|
46
|
-
<script type="text/javascript">
|
47
|
-
var slash_search;
|
48
|
-
$(function(){
|
49
|
-
if (has_hose()) {
|
50
|
-
var $search_text = $any('searchquery'),
|
51
|
-
$panel = $search_text.closest('fieldset');
|
52
|
-
$search_buttons = $('#viewsearch,#fhsearch'),
|
53
|
-
ws = /\s+/;
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
// The search buttons set the firehose option named by their class.
|
58
|
-
$search_buttons.
|
59
|
-
click(function(){
|
60
|
-
var which=this.className;
|
61
|
-
$search_text.each(function(){
|
62
|
-
firehose_set_options(which, this.value);
|
63
|
-
});
|
64
|
-
return false;
|
65
|
-
});
|
66
|
-
|
67
|
-
// Provide a globally available function that does whatever clicking the search button would do.
|
68
|
-
slash_search = function( query ){
|
69
|
-
query!==undefined && $search_text.val(query);
|
70
|
-
$search_buttons.filter(':visible:first').click();
|
71
|
-
};
|
72
|
-
|
73
|
-
$search_text.
|
74
|
-
keydown(function( e ){ // ESCAPE restores the filter in-effect.
|
75
|
-
if ( e.which == $.ui.keyCode.ESCAPE ) {
|
76
|
-
$search_text.val(firehose_settings.fhfilter||'');
|
77
|
-
return true;
|
78
|
-
}
|
79
|
-
if ( e.which == $.ui.keyCode.ENTER ) {
|
80
|
-
slash_search();
|
81
|
-
return false;
|
82
|
-
}
|
83
|
-
});
|
84
|
-
|
85
|
-
$(document).
|
86
|
-
bind('firehose-setting-setfhfilter firehose-setting-setsearchfilter', function( e, new_query ){
|
87
|
-
$('fieldset input[type=text]').each(function(){
|
88
|
-
$(this).blur().val(new_query);
|
89
|
-
});
|
90
|
-
}).
|
91
|
-
bind('set-options.firehose', function( e, data ){
|
92
|
-
data.select_section && $panel.toggleClass('mode-filter', data.id!=='unsaved');
|
93
|
-
});
|
94
|
-
}
|
95
|
-
});
|
96
|
-
</script>
|
data/benchmark/helper.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
require "rubygems"
|
2
|
-
require "open-uri"
|
3
|
-
require "hpricot"
|
4
|
-
require File.expand_path(File.dirname(__FILE__) + "/../lib/loofah")
|
5
|
-
require "benchmark"
|
6
|
-
require "action_view"
|
7
|
-
require "action_controller/vendor/html-scanner"
|
8
|
-
require "sanitize"
|
9
|
-
require "hitimes"
|
10
|
-
require "htmlfilter"
|
11
|
-
|
12
|
-
unless defined?(HTMLFilter)
|
13
|
-
HTMLFilter = HtmlFilter
|
14
|
-
end
|
15
|
-
|
16
|
-
class RailsSanitize
|
17
|
-
include ActionView::Helpers::SanitizeHelper
|
18
|
-
extend ActionView::Helpers::SanitizeHelper::ClassMethods
|
19
|
-
end
|
20
|
-
|
21
|
-
class HTML5libSanitize
|
22
|
-
require "html5/html5parser"
|
23
|
-
require "html5/liberalxmlparser"
|
24
|
-
require "html5/treewalkers"
|
25
|
-
require "html5/treebuilders"
|
26
|
-
require "html5/serializer"
|
27
|
-
require "html5/sanitizer"
|
28
|
-
|
29
|
-
include HTML5
|
30
|
-
|
31
|
-
def sanitize(html)
|
32
|
-
HTMLParser.parse_fragment(html, {
|
33
|
-
:tokenizer => HTMLSanitizer,
|
34
|
-
:encoding => "utf-8",
|
35
|
-
:tree => TreeBuilders::REXML::TreeBuilder,
|
36
|
-
}).to_s
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
BIG_FILE = File.read(File.join(File.dirname(__FILE__), "www.slashdot.com.html"))
|
41
|
-
FRAGMENT = File.read(File.join(File.dirname(__FILE__), "fragment.html"))
|
42
|
-
SNIPPET = "This is typical form field input in <b>length and content."
|
43
|
-
|
44
|
-
class Measure
|
45
|
-
def initialize
|
46
|
-
clear_measure
|
47
|
-
end
|
48
|
-
|
49
|
-
def clear_measure
|
50
|
-
@first_time = true
|
51
|
-
@baseline = nil
|
52
|
-
end
|
53
|
-
|
54
|
-
def measure(name, ntimes)
|
55
|
-
if @first_time
|
56
|
-
printf " %-30s %7s %8s %5s\n", "", "total", "single", "rel"
|
57
|
-
@first_time = false
|
58
|
-
end
|
59
|
-
timer = Hitimes::TimedMetric.new(name)
|
60
|
-
timer.start
|
61
|
-
ntimes.times do |j|
|
62
|
-
yield
|
63
|
-
end
|
64
|
-
timer.stop
|
65
|
-
if @baseline
|
66
|
-
printf " %30s %7.3f (%8.6f) %5.2fx\n", timer.name, timer.sum, timer.sum / ntimes, timer.sum / @baseline
|
67
|
-
else
|
68
|
-
@baseline = timer.sum
|
69
|
-
printf " %30s %7.3f (%8.6f) %5s\n", timer.name, timer.sum, timer.sum / ntimes, "-"
|
70
|
-
end
|
71
|
-
timer.sum
|
72
|
-
end
|
73
|
-
end
|