bot-away 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.travis.yml +14 -0
  2. data/History.txt +20 -0
  3. data/README.md +198 -0
  4. data/Rakefile +14 -94
  5. data/bot-away.gemspec +20 -87
  6. data/gemfiles/Gemfile.rails-3.0.x +8 -0
  7. data/gemfiles/Gemfile.rails-3.0.x.lock +121 -0
  8. data/gemfiles/Gemfile.rails-3.1.x +8 -0
  9. data/gemfiles/Gemfile.rails-3.1.x.lock +133 -0
  10. data/lib/bot-away.rb +15 -13
  11. data/lib/bot-away/action_dispatch/params_parser.rb +22 -0
  12. data/lib/bot-away/action_view/helpers/instance_tag.rb +36 -12
  13. data/lib/bot-away/param_parser.rb +2 -2
  14. data/lib/bot-away/railtie.rb +10 -0
  15. data/lib/bot-away/test_case.rb +58 -0
  16. data/lib/bot-away/test_case/controller_test_case.rb +11 -0
  17. data/lib/bot-away/test_case/instance_tag_test_case.rb +15 -0
  18. data/lib/bot-away/test_case/matchers.rb +20 -0
  19. data/lib/bot-away/test_case/matchers/honeypot_matcher.rb +30 -0
  20. data/lib/bot-away/test_case/matchers/obfuscation_matcher.rb +30 -0
  21. data/lib/bot-away/test_case/mock_object.rb +16 -0
  22. data/lib/bot-away/version.rb +12 -0
  23. data/lib/locale/honeypots.yml +6 -0
  24. data/spec/controllers/basic_form_view_spec.rb +112 -0
  25. data/spec/controllers/{test_controller_spec.rb → tests_controller_spec.rb} +29 -80
  26. data/spec/integration/params_post_spec.rb +42 -0
  27. data/spec/lib/action_view/helpers/instance_tag_spec.rb +94 -0
  28. data/spec/{views/lib → lib/action_view}/param_parser_spec.rb +10 -10
  29. data/spec/spec_helper.rb +37 -105
  30. data/spec/test_rails_app/app/controllers/tests_controller.rb +11 -0
  31. data/spec/test_rails_app/app/models/post.rb +13 -0
  32. data/spec/test_rails_app/app/views/tests/basic_form.html.erb +5 -0
  33. data/spec/test_rails_app/app/views/tests/model_form.html.erb +12 -0
  34. data/spec/test_rails_app/config/locales/bot-away-overrides.yml +6 -0
  35. data/spec/views/form_builder_spec.rb +118 -0
  36. metadata +94 -137
  37. data/Manifest.txt +0 -23
  38. data/README.rdoc +0 -179
  39. data/VERSION +0 -1
  40. data/lib/bot-away/action_dispatch/request.rb +0 -20
  41. data/spec/rspec_version.rb +0 -19
  42. data/spec/support/honeypot_matcher.rb +0 -30
  43. data/spec/support/obfuscation_helper.rb +0 -123
  44. data/spec/support/obfuscation_matcher.rb +0 -28
  45. data/spec/support/rails/mock_logger.rb +0 -21
  46. data/spec/support/test_controller.rb +0 -28
  47. data/spec/support/views/test/index.html.erb +0 -4
  48. data/spec/support/views/test/model_form.html.erb +0 -6
  49. data/spec/views/lib/action_view/helpers/instance_tag_spec.rb +0 -75
  50. data/spec/views/lib/disabled_for_spec.rb +0 -101
  51. data/spec/views/lib/form_builder_spec.rb +0 -56
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bot-away.gemspec
4
+ gemspec :path => ".."
5
+
6
+ gem 'rails', '~> 3.0.10'
7
+ gem 'rspec', '~> 2.6.0'
8
+ gem 'rspec-rails', '~> 2.6.1'
@@ -0,0 +1,121 @@
1
+ PATH
2
+ remote: /Users/colin/projects/gems/bot-away
3
+ specs:
4
+ bot-away (2.0.0)
5
+ actionpack (>= 2.3.5)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ abstract (1.0.0)
11
+ actionmailer (3.0.11)
12
+ actionpack (= 3.0.11)
13
+ mail (~> 2.2.19)
14
+ actionpack (3.0.11)
15
+ activemodel (= 3.0.11)
16
+ activesupport (= 3.0.11)
17
+ builder (~> 2.1.2)
18
+ erubis (~> 2.6.6)
19
+ i18n (~> 0.5.0)
20
+ rack (~> 1.2.1)
21
+ rack-mount (~> 0.6.14)
22
+ rack-test (~> 0.5.7)
23
+ tzinfo (~> 0.3.23)
24
+ activemodel (3.0.11)
25
+ activesupport (= 3.0.11)
26
+ builder (~> 2.1.2)
27
+ i18n (~> 0.5.0)
28
+ activerecord (3.0.11)
29
+ activemodel (= 3.0.11)
30
+ activesupport (= 3.0.11)
31
+ arel (~> 2.0.10)
32
+ tzinfo (~> 0.3.23)
33
+ activeresource (3.0.11)
34
+ activemodel (= 3.0.11)
35
+ activesupport (= 3.0.11)
36
+ activesupport (3.0.11)
37
+ arel (2.0.10)
38
+ builder (2.1.2)
39
+ capybara (1.1.2)
40
+ mime-types (>= 1.16)
41
+ nokogiri (>= 1.3.3)
42
+ rack (>= 1.0.0)
43
+ rack-test (>= 0.5.4)
44
+ selenium-webdriver (~> 2.0)
45
+ xpath (~> 0.1.4)
46
+ childprocess (0.2.9)
47
+ ffi (~> 1.0.6)
48
+ diff-lcs (1.1.3)
49
+ erubis (2.6.6)
50
+ abstract (>= 1.0.0)
51
+ ffi (1.0.11)
52
+ i18n (0.5.0)
53
+ json (1.6.4)
54
+ mail (2.2.19)
55
+ activesupport (>= 2.3.6)
56
+ i18n (>= 0.4.0)
57
+ mime-types (~> 1.16)
58
+ treetop (~> 1.4.8)
59
+ mime-types (1.17.2)
60
+ multi_json (1.0.4)
61
+ nokogiri (1.5.0)
62
+ polyglot (0.3.3)
63
+ rack (1.2.5)
64
+ rack-mount (0.6.14)
65
+ rack (>= 1.0.0)
66
+ rack-test (0.5.7)
67
+ rack (>= 1.0)
68
+ rails (3.0.11)
69
+ actionmailer (= 3.0.11)
70
+ actionpack (= 3.0.11)
71
+ activerecord (= 3.0.11)
72
+ activeresource (= 3.0.11)
73
+ activesupport (= 3.0.11)
74
+ bundler (~> 1.0)
75
+ railties (= 3.0.11)
76
+ railties (3.0.11)
77
+ actionpack (= 3.0.11)
78
+ activesupport (= 3.0.11)
79
+ rake (>= 0.8.7)
80
+ rdoc (~> 3.4)
81
+ thor (~> 0.14.4)
82
+ rake (0.9.2.2)
83
+ rdoc (3.12)
84
+ json (~> 1.4)
85
+ rspec (2.6.0)
86
+ rspec-core (~> 2.6.0)
87
+ rspec-expectations (~> 2.6.0)
88
+ rspec-mocks (~> 2.6.0)
89
+ rspec-core (2.6.4)
90
+ rspec-expectations (2.6.0)
91
+ diff-lcs (~> 1.1.2)
92
+ rspec-mocks (2.6.0)
93
+ rspec-rails (2.6.1)
94
+ actionpack (~> 3.0)
95
+ activesupport (~> 3.0)
96
+ railties (~> 3.0)
97
+ rspec (~> 2.6.0)
98
+ rubyzip (0.9.5)
99
+ selenium-webdriver (2.16.0)
100
+ childprocess (>= 0.2.5)
101
+ ffi (~> 1.0.9)
102
+ multi_json (~> 1.0.4)
103
+ rubyzip
104
+ thor (0.14.6)
105
+ treetop (1.4.10)
106
+ polyglot
107
+ polyglot (>= 0.3.1)
108
+ tzinfo (0.3.31)
109
+ xpath (0.1.4)
110
+ nokogiri (~> 1.3)
111
+
112
+ PLATFORMS
113
+ ruby
114
+
115
+ DEPENDENCIES
116
+ bot-away!
117
+ capybara (~> 1.1.2)
118
+ rails (~> 3.0.10)
119
+ rake (~> 0.9.2)
120
+ rspec (~> 2.6.0)
121
+ rspec-rails (~> 2.6.1)
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in bot-away.gemspec
4
+ gemspec :path => ".."
5
+
6
+ gem 'rails', '~> 3.1.0'
7
+ gem 'rspec', '~> 2.6.0'
8
+ gem 'rspec-rails', '~> 2.6.1'
@@ -0,0 +1,133 @@
1
+ PATH
2
+ remote: /Users/colin/projects/gems/bot-away
3
+ specs:
4
+ bot-away (2.0.0)
5
+ actionpack (>= 2.3.5)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ actionmailer (3.1.0)
11
+ actionpack (= 3.1.0)
12
+ mail (~> 2.3.0)
13
+ actionpack (3.1.0)
14
+ activemodel (= 3.1.0)
15
+ activesupport (= 3.1.0)
16
+ builder (~> 3.0.0)
17
+ erubis (~> 2.7.0)
18
+ i18n (~> 0.6)
19
+ rack (~> 1.3.2)
20
+ rack-cache (~> 1.0.3)
21
+ rack-mount (~> 0.8.2)
22
+ rack-test (~> 0.6.1)
23
+ sprockets (~> 2.0.0)
24
+ activemodel (3.1.0)
25
+ activesupport (= 3.1.0)
26
+ bcrypt-ruby (~> 3.0.0)
27
+ builder (~> 3.0.0)
28
+ i18n (~> 0.6)
29
+ activerecord (3.1.0)
30
+ activemodel (= 3.1.0)
31
+ activesupport (= 3.1.0)
32
+ arel (~> 2.2.1)
33
+ tzinfo (~> 0.3.29)
34
+ activeresource (3.1.0)
35
+ activemodel (= 3.1.0)
36
+ activesupport (= 3.1.0)
37
+ activesupport (3.1.0)
38
+ multi_json (~> 1.0)
39
+ arel (2.2.1)
40
+ bcrypt-ruby (3.0.0)
41
+ builder (3.0.0)
42
+ capybara (1.1.2)
43
+ mime-types (>= 1.16)
44
+ nokogiri (>= 1.3.3)
45
+ rack (>= 1.0.0)
46
+ rack-test (>= 0.5.4)
47
+ selenium-webdriver (~> 2.0)
48
+ xpath (~> 0.1.4)
49
+ childprocess (0.2.9)
50
+ ffi (~> 1.0.6)
51
+ diff-lcs (1.1.3)
52
+ erubis (2.7.0)
53
+ ffi (1.0.11)
54
+ hike (1.2.1)
55
+ i18n (0.6.0)
56
+ json (1.6.4)
57
+ mail (2.3.0)
58
+ i18n (>= 0.4.0)
59
+ mime-types (~> 1.16)
60
+ treetop (~> 1.4.8)
61
+ mime-types (1.17.2)
62
+ multi_json (1.0.4)
63
+ nokogiri (1.5.0)
64
+ polyglot (0.3.3)
65
+ rack (1.3.2)
66
+ rack-cache (1.0.3)
67
+ rack (>= 0.4)
68
+ rack-mount (0.8.3)
69
+ rack (>= 1.0.0)
70
+ rack-ssl (1.3.2)
71
+ rack
72
+ rack-test (0.6.1)
73
+ rack (>= 1.0)
74
+ rails (3.1.0)
75
+ actionmailer (= 3.1.0)
76
+ actionpack (= 3.1.0)
77
+ activerecord (= 3.1.0)
78
+ activeresource (= 3.1.0)
79
+ activesupport (= 3.1.0)
80
+ bundler (~> 1.0)
81
+ railties (= 3.1.0)
82
+ railties (3.1.0)
83
+ actionpack (= 3.1.0)
84
+ activesupport (= 3.1.0)
85
+ rack-ssl (~> 1.3.2)
86
+ rake (>= 0.8.7)
87
+ rdoc (~> 3.4)
88
+ thor (~> 0.14.6)
89
+ rake (0.9.2.2)
90
+ rdoc (3.12)
91
+ json (~> 1.4)
92
+ rspec (2.6.0)
93
+ rspec-core (~> 2.6.0)
94
+ rspec-expectations (~> 2.6.0)
95
+ rspec-mocks (~> 2.6.0)
96
+ rspec-core (2.6.4)
97
+ rspec-expectations (2.6.0)
98
+ diff-lcs (~> 1.1.2)
99
+ rspec-mocks (2.6.0)
100
+ rspec-rails (2.6.1)
101
+ actionpack (~> 3.0)
102
+ activesupport (~> 3.0)
103
+ railties (~> 3.0)
104
+ rspec (~> 2.6.0)
105
+ rubyzip (0.9.5)
106
+ selenium-webdriver (2.16.0)
107
+ childprocess (>= 0.2.5)
108
+ ffi (~> 1.0.9)
109
+ multi_json (~> 1.0.4)
110
+ rubyzip
111
+ sprockets (2.0.0)
112
+ hike (~> 1.2)
113
+ rack (~> 1.0)
114
+ tilt (~> 1.1, != 1.3.0)
115
+ thor (0.14.6)
116
+ tilt (1.3.3)
117
+ treetop (1.4.10)
118
+ polyglot
119
+ polyglot (>= 0.3.1)
120
+ tzinfo (0.3.31)
121
+ xpath (0.1.4)
122
+ nokogiri (~> 1.3)
123
+
124
+ PLATFORMS
125
+ ruby
126
+
127
+ DEPENDENCIES
128
+ bot-away!
129
+ capybara (~> 1.1.2)
130
+ rails (~> 3.1.0)
131
+ rake (~> 0.9.2)
132
+ rspec (~> 2.6.0)
133
+ rspec-rails (~> 2.6.1)
@@ -1,20 +1,23 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
1
  require 'action_controller'
5
2
  require 'action_view'
6
- require 'sc-core-ext'
7
3
 
8
4
  require 'bot-away/param_parser'
9
- require 'bot-away/action_dispatch/request'
5
+ require 'bot-away/action_dispatch/params_parser'
10
6
  require 'bot-away/action_view/helpers/instance_tag'
11
7
  require 'bot-away/spinner'
8
+ require 'bot-away/version'
9
+ require 'bot-away/railtie'
12
10
 
13
11
  module BotAway
14
- VERSION = File.read(File.join(File.dirname(__FILE__), "../VERSION")) unless defined?(VERSION)
12
+ autoload :TestCase, 'bot-away/test_case'
15
13
 
16
14
  class << self
17
15
  attr_accessor :show_honeypots, :dump_params
16
+ attr_writer :obfuscate_honeypot_warning_messages
17
+
18
+ def obfuscate_honeypot_warning_messages?
19
+ !!@obfuscate_honeypot_warning_messages
20
+ end
18
21
 
19
22
  def unfiltered_params(*keys)
20
23
  unfiltered_params = instance_variable_get("@unfiltered_params") || instance_variable_set("@unfiltered_params", [])
@@ -33,7 +36,9 @@ module BotAway
33
36
  # excluded? will also check the current Rails run mode against disabled_for[:mode]
34
37
  def excluded?(options)
35
38
  options = options.stringify_keys
36
- nonparams = options.stringify_keys.without('object_name', 'method_name')
39
+ nonparams = options.stringify_keys
40
+ nonparams.delete 'object_name'
41
+ nonparams.delete 'method_name'
37
42
  (options['object_name'] && options['method_name'] &&
38
43
  unfiltered_params_include?(options['object_name'], options['method_name'])) || disabled_for?(nonparams)
39
44
  end
@@ -55,8 +60,6 @@ module BotAway
55
60
  def disabled_for?(options)
56
61
  return false if @disabled_for.nil? || options.empty?
57
62
  options = options.stringify_keys
58
- # p options
59
- # p "===="
60
63
  @disabled_for.each do |set|
61
64
  if set.key?('mode')
62
65
  next unless ENV['RAILS_ENV'] == set['mode'].to_s
@@ -66,7 +69,6 @@ module BotAway
66
69
  # and that means we need to check the next few conditions.
67
70
  end
68
71
 
69
- # p set
70
72
  if set.key?('controller') && set.key?('action')
71
73
  return true if set['controller'] == options['controller'] && set['action'] == options['action']
72
74
  elsif set.key?('controller') && !set.key?('action')
@@ -89,13 +91,13 @@ module BotAway
89
91
  def reset!
90
92
  self.show_honeypots = false
91
93
  self.dump_params = false
94
+ self.obfuscate_honeypot_warning_messages = true
92
95
  self.unfiltered_params.clear
93
96
  self.disabled_for.clear
94
97
  end
95
98
  end
96
99
 
97
100
  delegate :accepts_unfiltered_params, :unfiltered_params, :to => :"self.class"
98
- end
99
101
 
100
- # WHY do I have to do this???
101
- ActionView::Base.send :include, ActionView::Helpers
102
+ reset! # set defaults
103
+ end
@@ -0,0 +1,22 @@
1
+ require 'action_dispatch/middleware/params_parser'
2
+
3
+ # We're overriding ActionDispatch::ParamsParser
4
+ # instead of just attaching a custom param parser so that others' custom param parsers can do
5
+ # their jobs without conflict. Also, overriding the parser allows us to deobfuscate all params,
6
+ # not just the ones I'm smart enough to predict will be used.
7
+ class ActionDispatch::ParamsParser
8
+ def parse_formatted_parameters_with_deobfuscation(env)
9
+ request = ActionDispatch::Request.new(env)
10
+ params = parse_formatted_parameters_without_deobfuscation(env)
11
+ if params
12
+ BotAway::ParamParser.new(request.ip, params).params
13
+ else
14
+ request_parameters = request.parameters.dup
15
+ request.parameters.clear
16
+ request.parameters.merge! BotAway::ParamParser.new(request.ip, request_parameters).params
17
+ params
18
+ end
19
+ end
20
+
21
+ alias_method_chain :parse_formatted_parameters, :deobfuscation
22
+ end
@@ -1,5 +1,6 @@
1
1
  class ActionView::Helpers::InstanceTag
2
2
  attr_reader :spinner
3
+ attr_writer :honeypot_index
3
4
 
4
5
  def initialize_with_spinner(object_name, method_name, template_object, object = nil)
5
6
  initialize_without_spinner(object_name, method_name, template_object, object)
@@ -35,16 +36,16 @@ class ActionView::Helpers::InstanceTag
35
36
  end
36
37
 
37
38
  def honeypot_tag(name, options = nil, *args)
38
- tag_without_honeypot(name, honeypot_options(options.dup? || {}), *args)
39
+ disguise tag_without_honeypot(name, honeypot_options(options ? options.dup : {}), *args)
39
40
  end
40
41
 
41
42
  def obfuscated_tag(name, options = nil, *args)
42
- tag_without_honeypot(name, obfuscate_options(options.dup? || {}), *args)
43
+ tag_without_honeypot(name, obfuscate_options(options ? options.dup : {}), *args)
43
44
  end
44
45
 
45
46
  def tag_with_honeypot(name, options = nil, *args)
46
47
  if spinner
47
- obfuscated_tag(name, options, *args) + disguise(honeypot_tag(name, options, *args))
48
+ obfuscated_tag(name, options, *args) + honeypot_tag(name, options, *args)
48
49
  else
49
50
  tag_without_honeypot(name, options, *args)
50
51
  end
@@ -66,6 +67,9 @@ class ActionView::Helpers::InstanceTag
66
67
  add_default_name_and_id_for_value(tag_value, name_and_id)
67
68
  options["for"] ||= name_and_id["id"]
68
69
  options["for"] = spinner.encode(options["for"]) if spinner && options["for"]
70
+ # TODO ideas for future implementation, but they may break nested tags
71
+ # escaped_reversed_text = text.to_s.reverse.chars.collect { |b| "&#x#{b.ord.to_s(16)};" }.join
72
+ # text = '<bdo dir="rtl">'.html_safe + escaped_reversed_text + '</bdo>'.html_safe
69
73
  to_label_tag_without_obfuscation(text, options)
70
74
  end
71
75
 
@@ -76,7 +80,7 @@ class ActionView::Helpers::InstanceTag
76
80
  # this should cover all Rails selects.
77
81
  if spinner && options && (options.keys.include?('id') || options.keys.include?('name'))
78
82
  if name == 'select' && !content_or_options_with_block.empty?
79
- content = '<option selected value=""></option>'
83
+ content = '<option selected value=""></option>'.html_safe
80
84
  else
81
85
  content = ""
82
86
  end
@@ -92,18 +96,38 @@ class ActionView::Helpers::InstanceTag
92
96
  alias_method_chain :tag, :honeypot
93
97
  alias_method_chain :to_label_tag, :obfuscation
94
98
  alias_method_chain :content_tag, :obfuscation
95
-
99
+
96
100
  def disguise(element)
97
101
  return element.replace("Honeypot(#{element})") if BotAway.show_honeypots
98
- case rand(3)
102
+ # TODO a way to customize the hidden tags too
103
+ case honeypot_index % 3
99
104
  when 0 # Hidden
100
- element.replace "<div style='display:none;'>Leave this empty: #{element}</div>"
105
+ element.replace "<div style='display:none;'>#{honeypot_warning_tag}#{element}</div>"
101
106
  when 1 # Off-screen
102
- element.replace "<div style='position:absolute;left:-1000px;top:-1000px;'>Don't fill this in: #{element}</div>"
103
- when 2 # Negligible size
104
- element.replace "<div style='position:absolute;width:0px;height:1px;z-index:-1;color:transparent;overflow:hidden;'>Keep this blank: #{element}</div>"
105
- else # this should never happen?
106
- disguise(element)
107
+ element.replace "<div style='position:absolute;left:-1000px;top:-1000px;'>#{honeypot_warning_tag}#{element}</div>"
108
+ else # Negligible size
109
+ element.replace "<div style='position:absolute;width:0px;height:1px;z-index:-1;color:transparent;overflow:hidden;'>#{honeypot_warning_tag}#{element}</div>"
110
+ end
111
+ end
112
+
113
+ def honeypot_index
114
+ @honeypot_index || rand(I18n.t("bot_away.number_of_honeypot_warning_messages").to_i) + 1
115
+ end
116
+
117
+ def honeypot_warning_message
118
+ warning = I18n.t "bot_away.honeypot_warning_#{honeypot_index}"
119
+ if BotAway.obfuscate_honeypot_warning_messages?
120
+ warning.reverse.chars.collect { |b| "&#x#{b.ord.to_s(16)};" }.join
121
+ else
122
+ warning.html_safe
123
+ end
124
+ end
125
+
126
+ def honeypot_warning_tag
127
+ if BotAway.obfuscate_honeypot_warning_messages?
128
+ "<bdo dir=\"rtl\">#{honeypot_warning_message}</bdo>".html_safe
129
+ else
130
+ honeypot_warning_message
107
131
  end
108
132
  end
109
133
  end