tamed_beast 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/Gemfile +4 -0
  2. data/README +12 -0
  3. data/Rakefile +2 -0
  4. data/app/controllers/forums_controller.rb +60 -0
  5. data/app/controllers/posts_controller.rb +98 -0
  6. data/app/controllers/topics_controller.rb +94 -0
  7. data/app/models/forum.rb +23 -0
  8. data/app/models/post.rb +26 -0
  9. data/app/models/topic.rb +97 -0
  10. data/app/views/forums/_form.html.erb +21 -0
  11. data/app/views/forums/edit.html.erb +12 -0
  12. data/app/views/forums/index.html.erb +63 -0
  13. data/app/views/forums/new.html.erb +10 -0
  14. data/app/views/forums/show.html.erb +81 -0
  15. data/app/views/posts/_edit.html.erb +38 -0
  16. data/app/views/posts/edit.html.erb +14 -0
  17. data/app/views/posts/index.html.erb +1 -0
  18. data/app/views/topics/_form.html.erb +17 -0
  19. data/app/views/topics/edit.html.erb +10 -0
  20. data/app/views/topics/index.html.erb +2 -0
  21. data/app/views/topics/new.html.erb +18 -0
  22. data/app/views/topics/show.html.erb +175 -0
  23. data/config/conf.rb +0 -0
  24. data/lib/generators/tamed_beast/install_generator.rb +56 -0
  25. data/lib/generators/tamed_beast/migration_generator.rb +26 -0
  26. data/lib/generators/tamed_beast/templates/migration.rb +57 -0
  27. data/lib/generators/tamed_beast/templates/routes.rb +9 -0
  28. data/lib/tamed_beast.rb +7 -0
  29. data/lib/tamed_beast/application_helper.rb +18 -0
  30. data/lib/tamed_beast/auth.rb +24 -0
  31. data/lib/tamed_beast/engine.rb +7 -0
  32. data/lib/tamed_beast/version.rb +3 -0
  33. data/tamed_beast.gemspec +23 -0
  34. data/test/fixtures/forums.yml +19 -0
  35. data/test/fixtures/posts.yml +34 -0
  36. data/test/fixtures/topics.yml +29 -0
  37. data/test/fixtures/users.yml +9 -0
  38. data/test/functional/forums_controller_test.rb +51 -0
  39. data/test/functional/posts_controller_test.rb +54 -0
  40. data/test/functional/topics_controller_test.rb +55 -0
  41. data/test/unit/forum_test.rb +10 -0
  42. data/test/unit/post_test.rb +32 -0
  43. data/test/unit/topic_test.rb +33 -0
  44. data/vendor/plugins/white_list/README +29 -0
  45. data/vendor/plugins/white_list/Rakefile +22 -0
  46. data/vendor/plugins/white_list/init.rb +2 -0
  47. data/vendor/plugins/white_list/lib/white_list_helper.rb +97 -0
  48. data/vendor/plugins/white_list/test/white_list_test.rb +132 -0
  49. data/vendor/plugins/white_list_formatted_content/init.rb +27 -0
  50. metadata +161 -0
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ class TopicsControllerTest < ActionController::TestCase
4
+ fixtures :posts
5
+ fixtures :topics
6
+ fixtures :forums
7
+ fixtures :users
8
+
9
+ test "show action lists posts in a topic" do
10
+ f = forums(:one)
11
+ t = topics(:one)
12
+ get :show, :id => t.id, :forum_id => f.id
13
+ assert_response :success
14
+ assert_equal Post.where(:topic_id => t.id).count, assigns(:posts).size
15
+
16
+ end
17
+
18
+ test "create action" do
19
+ f = forums(:one)
20
+ u = users(:one)
21
+ sign_in(u)
22
+
23
+ assert_difference "Topic.where(:forum_id => #{f.id}).count" do
24
+ post :create, :forum_id => f.id, :topic => {:title => 'test test', :body => 'test test body body'}
25
+ t = Topic.where(:forum_id => f.id).last
26
+
27
+ assert_redirected_to forum_topic_path(f,t)
28
+ end
29
+ end
30
+
31
+ test "update action" do
32
+ f = forums(:one)
33
+ t = topics(:one)
34
+ u = users(:one)
35
+ sign_in(u)
36
+
37
+ put :update, :id => t.id, :forum_id => f.id, :topic => {:title => 'test test'}
38
+ assert_redirected_to forum_topic_path(f,t)
39
+ end
40
+
41
+ test "destroy action" do
42
+ f = forums(:one)
43
+ t = topics(:one)
44
+ u = users(:one)
45
+ sign_in(u)
46
+
47
+ delete :destroy, :id => t.id, :forum_id => f.id
48
+ assert_redirected_to forum_path(f)
49
+ end
50
+
51
+ private
52
+ def sign_in(u)
53
+ session[:user_id] = u.id
54
+ end
55
+ end
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+
3
+ class ForumTest < ActiveSupport::TestCase
4
+ test "validates presence of name" do
5
+ f = Forum.new
6
+ assert !f.valid?
7
+ f.name = "a new forum"
8
+ assert f.valid?
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class PostTest < ActiveSupport::TestCase
4
+ test "validates presence of user" do
5
+ p = Post.new
6
+ p.body = "lorem ipsum dolor sit amet..."
7
+ p.topic_id = 1
8
+ assert !p.valid?
9
+ p.user_id = 1
10
+ assert p.valid?
11
+ end
12
+
13
+ test "validates presence of body" do
14
+ p = Post.new
15
+ p.topic_id = 1
16
+ p.user_id = 1
17
+ assert !p.valid?
18
+
19
+ p.body = "lorem ipsum dolor sit amet..."
20
+ assert p.valid?
21
+ end
22
+
23
+ test "validates presence of topic" do
24
+ p = Post.new
25
+ p.user_id = 1
26
+ p.body = "lorem ipsum dolor sit amet..."
27
+ assert !p.valid?
28
+
29
+ p.topic_id = 1
30
+ assert p.valid?
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class TopicTest < ActiveSupport::TestCase
4
+ test "validates presence of user" do
5
+ t = Topic.new
6
+ t.title = "A new topic"
7
+ t.forum_id = 1
8
+ assert !t.valid?
9
+
10
+ t.user_id = 1
11
+ assert t.valid?
12
+ end
13
+
14
+ test "validates presence of forum" do
15
+ t = Topic.new
16
+ t.title = "A new topic"
17
+ t.user_id = 1
18
+ assert !t.valid?
19
+
20
+ t.forum_id = 1
21
+ assert t.valid?
22
+ end
23
+
24
+ test "validates presence of title" do
25
+ t = Topic.new
26
+ t.user_id = 1
27
+ t.forum_id = 1
28
+ assert !t.valid?
29
+
30
+ t.title = "A new topic"
31
+ assert t.valid?
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ WhiteList
2
+ =========
3
+
4
+ This White Listing helper will html encode all tags and strip all attributes that aren't specifically allowed.
5
+ It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
6
+ tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
7
+ the extensive test suite.
8
+
9
+ <%= white_list @article.body %>
10
+
11
+ You can add or remove tags/attributes if you want to customize it a bit.
12
+
13
+ Add table tags
14
+
15
+ WhiteListHelper.tags.merge %w(table td th)
16
+
17
+ Remove tags
18
+
19
+ WhiteListHelper.tags.delete 'div'
20
+
21
+ Change allowed attributes
22
+
23
+ WhiteListHelper.attributes.merge %w(id class style)
24
+
25
+ white_list accepts a block for custom tag escaping. Shown below is the default block that white_list uses if none is given.
26
+ The block is called for all bad tags, and every text node. node is an instance of HTML::Node (either HTML::Tag or HTML::Text).
27
+ bad is nil for text nodes inside good tags, or is the tag name of the bad tag.
28
+
29
+ <%= white_list(@article.body) { |node, bad| white_listed_bad_tags.include?(bad) ? nil : node.to_s.gsub(/</, '&lt;') } %>
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the white_list plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the white_list plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'WhiteList'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
@@ -0,0 +1,2 @@
1
+ require 'white_list_helper'
2
+ ActionView::Base.send :include, WhiteListHelper
@@ -0,0 +1,97 @@
1
+ module WhiteListHelper
2
+ @@protocol_attributes = Set.new %w(src href)
3
+ @@protocol_separator = /:|(&#0*58)|(&#x70)|(%|&#37;)3A/
4
+ mattr_reader :protocol_attributes, :protocol_separator
5
+
6
+ def self.contains_bad_protocols?(white_listed_protocols, value)
7
+ value =~ protocol_separator && !white_listed_protocols.include?(value.split(protocol_separator).first)
8
+ end
9
+
10
+ klass = class << self; self; end
11
+ klass_methods = []
12
+ inst_methods = []
13
+ [:bad_tags, :tags, :attributes, :protocols].each do |attr|
14
+ # Add class methods to the module itself
15
+ klass_methods << <<-EOS
16
+ def #{attr}=(value) @@#{attr} = Set.new(value) end
17
+ def #{attr}() @@#{attr} end
18
+ EOS
19
+
20
+ # prefix the instance methods with white_listed_*
21
+ inst_methods << "def white_listed_#{attr}() ::WhiteListHelper.#{attr} end"
22
+ end
23
+
24
+ klass.class_eval klass_methods.join("\n"), __FILE__, __LINE__
25
+ class_eval inst_methods.join("\n"), __FILE__, __LINE__
26
+
27
+ # This White Listing helper will html encode all tags and strip all attributes that aren't specifically allowed.
28
+ # It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
29
+ # tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
30
+ # the extensive test suite.
31
+ #
32
+ # <%= white_list @article.body %>
33
+ #
34
+ # You can add or remove tags/attributes if you want to customize it a bit.
35
+ #
36
+ # Add table tags
37
+ #
38
+ # WhiteListHelper.tags.merge %w(table td th)
39
+ #
40
+ # Remove tags
41
+ #
42
+ # WhiteListHelper.tags.delete 'div'
43
+ #
44
+ # Change allowed attributes
45
+ #
46
+ # WhiteListHelper.attributes.merge %w(id class style)
47
+ #
48
+ # white_list accepts a block for custom tag escaping. Shown below is the default block that white_list uses if none is given.
49
+ # The block is called for all bad tags, and every text node. node is an instance of HTML::Node (either HTML::Tag or HTML::Text).
50
+ # bad is nil for text nodes inside good tags, or is the tag name of the bad tag.
51
+ #
52
+ # <%= white_list(@article.body) { |node, bad| white_listed_bad_tags.include?(bad) ? nil : node.to_s.gsub(/</, '&lt;') } %>
53
+ #
54
+ def white_list(html, options = {}, &block)
55
+ return html if html.blank? || !html.include?('<')
56
+ attrs = Set.new(options[:attributes]).merge(white_listed_attributes)
57
+ tags = Set.new(options[:tags] ).merge(white_listed_tags)
58
+ block ||= lambda { |node, bad| white_listed_bad_tags.include?(bad) ? nil : node.to_s.gsub(/</, '&lt;') }
59
+ [].tap do |new_text|
60
+ tokenizer = HTML::Tokenizer.new(html)
61
+ bad = nil
62
+ while token = tokenizer.next
63
+ node = HTML::Node.parse(nil, 0, 0, token, false)
64
+ new_text << case node
65
+ when HTML::Tag
66
+ node.attributes.keys.each do |attr_name|
67
+ value = node.attributes[attr_name].to_s
68
+ if !attrs.include?(attr_name) || (protocol_attributes.include?(attr_name) && contains_bad_protocols?(value))
69
+ node.attributes.delete(attr_name)
70
+ else
71
+ node.attributes[attr_name] = CGI::escapeHTML(value)
72
+ end
73
+ end if node.attributes
74
+ if tags.include?(node.name)
75
+ bad = nil
76
+ node
77
+ else
78
+ bad = node.name
79
+ block.call node, bad
80
+ end
81
+ else
82
+ block.call node, bad
83
+ end
84
+ end
85
+ end.join
86
+ end
87
+
88
+ protected
89
+ def contains_bad_protocols?(value)
90
+ WhiteListHelper.contains_bad_protocols?(white_listed_protocols, value)
91
+ end
92
+ end
93
+
94
+ WhiteListHelper.bad_tags = %w(script)
95
+ WhiteListHelper.tags = %w(strong em b i p code pre tt output samp kbd var sub sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr acronym a img blockquote del ins fieldset legend)
96
+ WhiteListHelper.attributes = %w(href src width height alt cite datetime title class)
97
+ WhiteListHelper.protocols = %w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto feed)
@@ -0,0 +1,132 @@
1
+ require 'test/unit'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
3
+
4
+ class WhiteListTest < Test::Unit::TestCase
5
+ include WhiteListHelper
6
+ public :contains_bad_protocols?
7
+
8
+ WhiteListHelper.tags.each do |tag_name|
9
+ define_method "test_should_allow_#{tag_name}_tag" do
10
+ assert_white_listed "start <#{tag_name} title=\"1\" name=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo &lt;bad>bar&lt;/bad> baz</#{tag_name}> end)
11
+ end
12
+ end
13
+
14
+ def test_should_allow_anchors
15
+ assert_white_listed %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>)
16
+ end
17
+
18
+ %w(src width height alt).each do |img_attr|
19
+ define_method "test_should_allow_image_#{img_attr}_attribute" do
20
+ assert_white_listed %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />)
21
+ end
22
+ end
23
+
24
+ def test_should_handle_non_html
25
+ assert_white_listed 'abc'
26
+ end
27
+
28
+ def test_should_handle_blank_text
29
+ assert_white_listed nil
30
+ assert_white_listed ''
31
+ end
32
+
33
+ def test_should_allow_custom_tags
34
+ text = "<u>foo</u>"
35
+ assert_equal(text, white_list(text, :tags => %w(u)))
36
+ end
37
+
38
+ def test_should_allow_custom_tags_with_attributes
39
+ text = %(<fieldset foo="bar">foo</fieldset>)
40
+ assert_equal(text, white_list(text, :attributes => ['foo']))
41
+ end
42
+
43
+ [%w(img src), %w(a href)].each do |(tag, attr)|
44
+ define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do
45
+ assert_white_listed %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>)
46
+ end
47
+ end
48
+
49
+ def test_should_flag_bad_protocols
50
+ %w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto|
51
+ assert contains_bad_protocols?("#{proto}://bad")
52
+ end
53
+ end
54
+
55
+ def test_should_accept_good_protocols
56
+ WhiteListHelper.protocols.each do |proto|
57
+ assert !contains_bad_protocols?("#{proto}://good")
58
+ end
59
+ end
60
+
61
+ def test_should_reject_hex_codes_in_protocol
62
+ assert contains_bad_protocols?("%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29")
63
+ assert_white_listed %(<a href="&#37;6A&#37;61&#37;76&#37;61&#37;73&#37;63&#37;72&#37;69&#37;70&#37;74&#37;3A&#37;61&#37;6C&#37;65&#37;72&#37;74&#37;28&#37;22&#37;58&#37;53&#37;53&#37;22&#37;29">1</a>), "<a>1</a>"
64
+ end
65
+
66
+ def test_should_block_script_tag
67
+ assert_white_listed %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), ""
68
+ end
69
+
70
+ [%(<IMG SRC="javascript:alert('XSS');">),
71
+ %(<IMG SRC=javascript:alert('XSS')>),
72
+ %(<IMG SRC=JaVaScRiPt:alert('XSS')>),
73
+ %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">),
74
+ %(<IMG SRC=javascript:alert(&quot;XSS&quot;)>),
75
+ %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>),
76
+ %(<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>),
77
+ %(<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>),
78
+ %(<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>),
79
+ %(<IMG SRC="jav\tascript:alert('XSS');">),
80
+ %(<IMG SRC="jav&#x09;ascript:alert('XSS');">),
81
+ %(<IMG SRC="jav&#x0A;ascript:alert('XSS');">),
82
+ %(<IMG SRC="jav&#x0D;ascript:alert('XSS');">),
83
+ %(<IMG SRC=" &#14; javascript:alert('XSS');">),
84
+ %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i|
85
+ define_method "test_should_not_fall_for_xss_image_hack_#{i}" do
86
+ assert_white_listed img_hack, "<img>"
87
+ end
88
+ end
89
+
90
+ def test_should_sanitize_tag_broken_up_by_null
91
+ assert_white_listed %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "&lt;scr>alert(\"XSS\")&lt;/scr>"
92
+ end
93
+
94
+ def test_should_sanitize_invalid_script_tag
95
+ assert_white_listed %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), ""
96
+ end
97
+
98
+ def test_should_sanitize_script_tag_with_multiple_open_brackets
99
+ assert_white_listed %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "&lt;"
100
+ assert_white_listed %(<iframe src=http://ha.ckers.org/scriptlet.html\n<), %(&lt;iframe src="http:" />&lt;)
101
+ end
102
+
103
+ def test_should_sanitize_unclosed_script
104
+ assert_white_listed %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>"
105
+ end
106
+
107
+ def test_should_sanitize_half_open_scripts
108
+ assert_white_listed %(<IMG SRC="javascript:alert('XSS')"), "<img>"
109
+ end
110
+
111
+ def test_should_not_fall_for_ridiculous_hack
112
+ img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>)
113
+ assert_white_listed img_hack, "<img>"
114
+ end
115
+
116
+ def test_should_allow_custom_block
117
+ html = %(<SCRIPT type="javascript">foo</SCRIPT><img>blah</img><blink>blah</blink>)
118
+ safe = white_list html do |node, bad|
119
+ bad == 'script' ? nil : node
120
+ end
121
+ assert_equal "<img>blah</img><blink>blah</blink>", safe
122
+ end
123
+
124
+ def test_should_sanitize_attributes
125
+ assert_white_listed %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'&gt;&lt;script&gt;alert()&lt;/script&gt;">blah</span>)
126
+ end
127
+
128
+ protected
129
+ def assert_white_listed(text, expected = nil)
130
+ assert_equal((expected || text), white_list(text))
131
+ end
132
+ end
@@ -0,0 +1,27 @@
1
+ ActiveRecord::Base.class_eval do
2
+ include ActionView::Helpers::TagHelper, ActionView::Helpers::TextHelper, WhiteListHelper
3
+ def self.format_attribute(attr_name)
4
+ class << self; include ActionView::Helpers::TagHelper, ActionView::Helpers::TextHelper, WhiteListHelper; end
5
+ define_method(:body) { read_attribute attr_name }
6
+ define_method(:body_html) { read_attribute "#{attr_name}_html" }
7
+ define_method(:body_html=) { |value| write_attribute "#{attr_name}_html", value }
8
+ before_save :format_content
9
+ end
10
+
11
+ def dom_id
12
+ [self.class.name.downcase.pluralize.dasherize, id] * '-'
13
+ end
14
+
15
+ protected
16
+ def format_content
17
+ body.strip! if body.respond_to?(:strip!)
18
+ self.body_html = body.blank? ? '' : body_html_with_formatting
19
+ end
20
+
21
+ def body_html_with_formatting
22
+ body_html = auto_link(body) { |text| truncate(text, 50) }
23
+ textilized = RedCloth.new(body_html, [ :hard_breaks ])
24
+ textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
25
+ white_list(textilized.to_html)
26
+ end
27
+ end