bot-away 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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