bot-away 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ .idea
2
+ *.swp
3
+ *.log
4
+ pkg
5
+ dry-run
6
+ coverage
7
+ doc
@@ -1,11 +1,21 @@
1
+ === 1.2.0 2010-10-14
2
+ * Enhancements:
3
+ * Rails 3 / RSpec 2 support! Yay!
4
+ * ActionController::Request#accepts_unfiltered_params has been removed. Use BotAway#accepts_unfiltered_params instead.
5
+ * Exclusion of bot-filtering on a per-controller, per-action and/or per-runmode basis is now possible via
6
+ BotAway#disabled_for
7
+
1
8
  === 1.1.0 2010-06-21
2
- * Minor enhancements:
9
+ * Enhancements:
3
10
  * ActionController::Request.accepts_unfiltered_params is now accessible as BotAway.accepts_unfiltered_params
4
11
  * BotAway.show_honeypots = true will show honeypots as visible elements within the form, for debugging.
5
12
  * BotAway.dump_params = true will dump the params hash as it was before BotAway modified it, for debugging.
6
13
  * BotAway will no longer generate hashes for, or disguise, elements whose names have been added to
7
14
  BotAway.unfiltered_params. This should resolve issues where JavaScript is involved (case in point:
8
- CalendarDateSelect).
15
+ Calendar Date Select).
16
+ * Bugfix:
17
+ * Resolved: Unfiltered params were not matched if they were of differing types (ie Symbol vs String). This caused
18
+ problems in particular with Calendar Date Select.
9
19
 
10
20
  === 1.0.3 2010-06-13
11
21
  * Bugfixes:
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Colin MacKenzie IV
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -2,13 +2,11 @@
2
2
 
3
3
  * http://github.com/sinisterchipmunk/bot-away
4
4
 
5
- == DESCRIPTION:
6
-
7
5
  Unobtrusively detects form submissions made by spambots, and silently drops those submissions. The key word here is
8
6
  "unobtrusive" -- this is NOT a CAPTCHA. This is a transparent, modular implementation of the bot-catching techniques
9
7
  discussed by Ned Batchelder at http://nedbatchelder.com/text/stopbots.html.
10
8
 
11
- == WHAT'S GOING ON:
9
+ == How It Works
12
10
 
13
11
  If a bot submission is detected, the params hash is cleared, so the data can't be used. Since this includes the
14
12
  authenticity token, Rails should complain about an invalid or missing authenticity token. Congrats, spam blocked.
@@ -16,24 +14,139 @@ authenticity token, Rails should complain about an invalid or missing authentici
16
14
  The specifics of the techniques employed for filtering spambots are discussed Ned's site in the description; however,
17
15
  here's a brief run-down of what's going on:
18
16
 
19
- * Your code stays the same. After the bot-away gem has been activated, all Rails-generated forms on your site
17
+ * Your code stays the same. After the Bot-Away gem has been activated, all Rails-generated forms on your site
20
18
  will automatically be transformed into bot-resistent forms.
21
19
  * All of the form elements that you create (for instance, a "comment" model with a "body" field) are turned into
22
20
  dummy elements, or honeypots, and are made invisible to the end user. This is done using div elements and inline CSS
23
- stylesheets. There are several ways an element can be hidden, and these approaches are chosen at random to help
24
- minimize predictability. In the rare event that a real user actually can see the element, it has a label next to it
21
+ stylesheets (I decided against a JavaScript option because it's the most likely to be disabled on a legitimate
22
+ client). There are several ways an element can be hidden, and these approaches are chosen at random to help
23
+ minimize predictability.
24
+
25
+ In the rare event that a real user actually can see the element, it has a label next to it
25
26
  along the lines of "Leave this blank" -- though the exact message is randomized to help prevent detection.
26
27
  * All of the form elements are mirrored by hashes. The hashes are generated using the session's authenticity token,
27
28
  so they can't be predicted.
28
- * When data is submitted, bot-away steps in and 1.) validates that no honeypots have been filled in; and 2)
29
- converts the hashed elements back into the field names that you are expecting (replacing the honeypot fields).
29
+ * When data is submitted, Bot-Away steps in and
30
+ 1. validates that no honeypots have been filled in; and
31
+ 2. converts the hashed elements back into the field names that you are expecting (replacing the honeypot fields). Your
32
+ code is never aware of the difference; it's just business as usual as long as the user is legitimate.
30
33
  * If a honeypot has been filled in, or a hashed element is missing where it was expected, then the request is
31
34
  considered to be either spam, or tampered with; and the entire params hash is emptied. Since this happens at the
32
35
  lowest level, the most likely result is that Rails will complain that the user's authenticity token is invalid. If
33
36
  that does not happen, then your code will be passed a params hash containing only a "suspected_bot" key, and an error
34
37
  will result. Either way, the spambot has been foiled!
35
38
 
36
- == FEATURES/PROBLEMS:
39
+ == Installation:
40
+
41
+ * gem install bot-away
42
+
43
+ == Usage:
44
+
45
+ Whether you're on Rails 2 or Rails 3, adding Bot-Away to your project is as easy as telling Rails where to find it.
46
+
47
+ === Rails 2.x
48
+
49
+ In your Rails config/environment.rb:
50
+
51
+ config.gem 'bot-away'
52
+
53
+ === Rails 3
54
+
55
+ In your Gemfile:
56
+
57
+ gem 'bot-away'
58
+
59
+ That's it.
60
+
61
+ == Whitelists
62
+
63
+ Sometimes you don't care about whether or not a bot is filling out a particular form. Even more, sometimes it's
64
+ preferable to make a form bot-friendly. I'm talking specifically about login forms, where all sorts of people
65
+ use bots (their Web browsers, usually) in order to prefill the form with their login information. This is perfectly
66
+ harmless, and even a malicious bot is not going to be able to cause any trouble on a form like this because it'll only
67
+ be denied access to the site.
68
+
69
+ In cases like this, you'll want to go ahead and disable Bot-Away. Since Bot-Away is only disabled on a per-controller
70
+ or per-action basis, it stays active throughout the remainder of your site, which prevents bots from (for example)
71
+ creating new users.
72
+
73
+ To disable Bot-Away for an entire controller, add this line to a file called <em>config/initializers/bot-away.rb</em>:
74
+
75
+ BotAway.disabled_for :controller => 'sessions'
76
+
77
+ And here's how to do the same for a specific action, leaving Bot-Away active for all other actions:
78
+
79
+ BotAway.disabled_for :controller => 'sessions', :action => 'login'
80
+
81
+ You can also disable Bot-Away for a given action in every controller, but I'm not sure how useful that is. In any case,
82
+ here's how to do it:
83
+
84
+ BotAway.disabled_for :action => 'index' # all we did was omit :controller
85
+
86
+ This line can be specified multiple times, for each of the controllers and/or actions that you need it disabled for.
87
+
88
+ == Disabling Bot-Away in Development
89
+
90
+ If, while developing your app, you find yourself viewing the HTML source code, it'll probably be more helpful
91
+ to have Bot-Away disabled entirely so that you're not confused by MD5 tags and legions of honeypots. This is easy enough
92
+ to do:
93
+
94
+ BotAway.disabled_for :mode => :development
95
+
96
+
97
+ == Further Configuration (Mostly for Debugging):
98
+
99
+ In general, Bot-Away doesn't have that much to configure. Most options only exist for your debugging pleasure, in
100
+ case something isn't quite working as you'd expected. As shown above, these settings should be specified in a file
101
+ called <em>config/initializers/bot-away.rb</em>. Configuration options available to you are as follows:
102
+
103
+ === Accepting Unfiltered Params
104
+
105
+ Sometimes you need to tell Bot-Away to explicitly _not_ filter a parameter. This is most notable with fields you've
106
+ dynamically added via JavaScript, since those can confuse Bot-Away's catching techniques. (It tends to think Javascript-
107
+ generated fields are honeypots, and raises an error based on that.) Here's how to tell Bot-Away that such fields are
108
+ not to be checked:
109
+
110
+ BotAway.accepts_unfiltered_params "name_of_param", "name_of_another_param"
111
+
112
+ Note that these parameters can be either model keys, field keys or exact matches. For example, imagine the following
113
+ scenario: you have two models, User and Group, and each has_many :roles. That means you'll likely have an administration
114
+ screen somewhere with check boxes representing user roles and group roles. Here are the different ways you can control
115
+ how Bot-Away interacts with these fields:
116
+
117
+ BotAway.accepts_unfiltered_params "user"
118
+ # disables BotAway filtering for ALL fields belonging to 'user', but NO fields belonging to 'group'
119
+
120
+ BotAway.accepts_unfiltered_params 'user[role_ids]', 'group[role_ids]'
121
+ # disables BotAway filtering for ONLY the 'role_ids' field belonging to BOTH 'user' and 'group', while leaving
122
+ # filtering enabled for ALL OTHER fields.
123
+
124
+ BotAway.accepts_unfiltered_params 'role_ids'
125
+ # disables BotAway filtering for ONLY the 'role_ids' fields belonging to ALL MODELS, while leaving all
126
+ # other fields enabled.
127
+
128
+ You can specify this option as many times as you need to do.
129
+
130
+ === Showing the Honeypots
131
+
132
+ Generally, you want to keep honeypots hidden, because they will clutter your interface and confuse your users. However,
133
+ there was an issue awhile back (near the 1.0 release of Bot-Away) where Safari was a bit smarter than its competitors,
134
+ successfully prefilling honeypots with data where Chrome, FF and IE all failed to do so. Eventually, I added the ability
135
+ to show honeypots on the screen, proving my suspicion that Safari was being "too smart". After resolving the issue, I
136
+ decided to leave this option available to Bot-Away as a debugging tool for handling future issues. To enable:
137
+
138
+ BotAway.show_honeypots = true
139
+
140
+ === Dumping Params
141
+
142
+ Like showing honeypots, above, this option is only useful if you're debugging issues in development
143
+ mode. You can enable this if you need to see exactly what Rails sees _before_ Bot-Away steps in to intervene. Enabling
144
+ this is a major security risk in production mode because it'll include sensitive data such as passwords; but it's very
145
+ useful for debugging false positives (that is, Bot-Away thinks you're a bot, but you're not).
146
+
147
+ BotAway.dump_params = true
148
+
149
+ == Features / Problems:
37
150
 
38
151
  * Wherever protection from forgery is not enabled in your Rails app, the Rails forms will be generated as if this gem
39
152
  did not exist. That means hashed elements won't be generated, honeypots won't be generated, and posted forms will not
@@ -55,68 +168,12 @@ here's a brief run-down of what's going on:
55
168
  BotAway.accepts_unfiltered_params 'role_ids'
56
169
  BotAway.accepts_unfiltered_params 'user' # this can be called multiple times
57
170
  You should also take note that this is an array, not a hash. So if you have a user[role_ids] as well as a
58
- group[role_ids], the +role_ids+ will not be matched on EITHER of these models.
171
+ group[role_ids], the +role_ids+ will not be filtered on EITHER of these models.
59
172
 
60
173
  * Currently, there's no direct support for per-request configuration of unfiltered params. This is mostly due to
61
174
  Bot-Away's low-level approach to filtering bots: the params have already been filtered by the time your controller
62
175
  is created. I'd like to revisit per-request filtering sometime in the future, once I figure out the best way to do it.
63
176
 
64
- == REQUIREMENTS:
177
+ == Requirements:
65
178
 
66
179
  * Rails 2.3.5 or better.
67
-
68
- == INSTALL:
69
-
70
- * sudo gem install bot-away
71
-
72
- == USAGE:
73
-
74
- In your Rails config/environment.rb:
75
-
76
- * config.gem 'bot-away'
77
-
78
- That's it.
79
-
80
- == OPTIONAL CONFIGURATION:
81
-
82
- In general, there's not much to the configuration of Bot-Away. Most options are here for your debugging pleasure, in
83
- case something isn't quite working as you'd expected and Bot-Away seems to be a potential cause. To set a configuration
84
- option, you should do so from a Rails initializer -- just create a file with any name (ending with ".rb", of course)
85
- in your config/initializers directory, and it'll get run during server start-up. Configuration options available to you
86
- for Bot-Away are as follows:
87
-
88
- BotAway.accepts_unfiltered_params "name_of_param", "name_of_another_param"
89
- # Causes the specified parameter to NOT be filtered. If, for instance, "role_ids" is given, then parameters such as
90
- # user[role_ids], group[role_ids], etc. will not be processed by Bot-Away.
91
- BotAway.show_honeypots = true
92
- # Causes Bot-Away to NOT disguise honeypots with CSS or any other technique. This will cause honeypot elements to
93
- # be displayed on your page. Not ideal for production, but helpful for debugging browser auto-fill issues.
94
- BotAway.dump_params = true
95
- # Probably a major security risk in a production application, but again useful in development for gaining insight
96
- # into what, exactly, is being passed by the browser into Rails before Bot-Away does its thing. If you're getting
97
- # false positives, this may prove helpful in figuring out why.
98
-
99
- == LICENSE:
100
-
101
- (The MIT License)
102
-
103
- Copyright (c) 2010 Colin MacKenzie IV
104
-
105
- Permission is hereby granted, free of charge, to any person obtaining
106
- a copy of this software and associated documentation files (the
107
- 'Software'), to deal in the Software without restriction, including
108
- without limitation the rights to use, copy, modify, merge, publish,
109
- distribute, sublicense, and/or sell copies of the Software, and to
110
- permit persons to whom the Software is furnished to do so, subject to
111
- the following conditions:
112
-
113
- The above copyright notice and this permission notice shall be
114
- included in all copies or substantial portions of the Software.
115
-
116
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
117
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
118
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
119
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
120
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
121
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
122
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,4 +1,60 @@
1
1
  require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'bot-away'
8
+ gem.summary = %Q{Unobtrusively detects form submissions made by spambots, and silently drops those submissions.}
9
+ gem.description = %Q{Unobtrusively detects form submissions made by spambots, and silently drops those submissions.}
10
+ gem.email = "sinisterchipmunk@gmail.com"
11
+ gem.homepage = "http://www.thoughtsincomputation.com"
12
+ gem.authors = ["Colin MacKenzie IV"]
13
+ gem.add_dependency "actionpack", ">= 2.3.5"
14
+ gem.add_dependency "sc-core-ext", ">= 1.1.1"
15
+ gem.add_development_dependency "jeweler", ">= 1.4.0"
16
+ gem.add_development_dependency "rspec", ">= 1.3.0"
17
+ gem.add_development_dependency "rspec-rails", ">= 1.3.2"
18
+ end
19
+ Jeweler::GemcutterTasks.new
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
22
+ end
23
+
24
+ require File.join(File.dirname(__FILE__), "spec/rspec_version")
25
+
26
+ if RSPEC_VERSION >= "2.0.0"
27
+ RSpec::Core::RakeTask.new(:spec) do |spec|
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ end
30
+ else # Rake task for 1.3.x
31
+ Spec::Rake::SpecTask.new(:spec) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.spec_files = FileList['spec/**/*_spec.rb']
34
+ end
35
+
36
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
37
+ spec.libs << 'lib' << 'spec'
38
+ spec.pattern = 'spec/**/*_spec.rb'
39
+ spec.rcov = true
40
+ end
41
+ end
42
+
43
+ task :spec => :check_dependencies
44
+ task :default => :spec
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?("VERSION") ? File.read("VERSION") : ""
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "bot-away #{version}"
51
+ rdoc.rdoc_files.include("README*")
52
+ rdoc.rdoc_files.include("*")
53
+ rdoc.rdoc_files.include("lib/**/*.rb")
54
+ end
55
+
56
+ =begin
57
+ require 'rubygems'
2
58
  gem 'hoe', '>= 2.1.0'
3
59
  require 'hoe'
4
60
  require 'fileutils'
@@ -43,3 +99,4 @@ end
43
99
  # TODO - want other tests/tasks run by default? Add them to the list
44
100
  # remove_task :default
45
101
  # task :default => [:spec, :features]
102
+ =end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.2.0
@@ -0,0 +1,96 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{bot-away}
8
+ s.version = "1.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Colin MacKenzie IV"]
12
+ s.date = %q{2010-10-14}
13
+ s.description = %q{Unobtrusively detects form submissions made by spambots, and silently drops those submissions.}
14
+ s.email = %q{sinisterchipmunk@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "History.txt",
22
+ "LICENSE",
23
+ "Manifest.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "bot-away.gemspec",
28
+ "lib/bot-away.rb",
29
+ "lib/bot-away/action_dispatch/request.rb",
30
+ "lib/bot-away/action_view/helpers/instance_tag.rb",
31
+ "lib/bot-away/param_parser.rb",
32
+ "lib/bot-away/spinner.rb",
33
+ "script/console",
34
+ "script/destroy",
35
+ "script/generate",
36
+ "spec/controllers/test_controller_spec.rb",
37
+ "spec/rspec_version.rb",
38
+ "spec/spec_helper.rb",
39
+ "spec/support/honeypot_matcher.rb",
40
+ "spec/support/obfuscation_helper.rb",
41
+ "spec/support/obfuscation_matcher.rb",
42
+ "spec/support/rails/mock_logger.rb",
43
+ "spec/support/test_controller.rb",
44
+ "spec/support/views/test/index.html.erb",
45
+ "spec/support/views/test/model_form.html.erb",
46
+ "spec/views/lib/action_view/helpers/instance_tag_spec.rb",
47
+ "spec/views/lib/disabled_for_spec.rb",
48
+ "spec/views/lib/form_builder_spec.rb",
49
+ "spec/views/lib/param_parser_spec.rb"
50
+ ]
51
+ s.homepage = %q{http://www.thoughtsincomputation.com}
52
+ s.rdoc_options = ["--charset=UTF-8"]
53
+ s.require_paths = ["lib"]
54
+ s.rubygems_version = %q{1.3.7}
55
+ s.summary = %q{Unobtrusively detects form submissions made by spambots, and silently drops those submissions.}
56
+ s.test_files = [
57
+ "spec/controllers/test_controller_spec.rb",
58
+ "spec/rspec_version.rb",
59
+ "spec/spec_helper.rb",
60
+ "spec/support/honeypot_matcher.rb",
61
+ "spec/support/obfuscation_helper.rb",
62
+ "spec/support/obfuscation_matcher.rb",
63
+ "spec/support/rails/mock_logger.rb",
64
+ "spec/support/test_controller.rb",
65
+ "spec/views/lib/action_view/helpers/instance_tag_spec.rb",
66
+ "spec/views/lib/disabled_for_spec.rb",
67
+ "spec/views/lib/form_builder_spec.rb",
68
+ "spec/views/lib/param_parser_spec.rb"
69
+ ]
70
+
71
+ if s.respond_to? :specification_version then
72
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
73
+ s.specification_version = 3
74
+
75
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
76
+ s.add_runtime_dependency(%q<actionpack>, [">= 2.3.5"])
77
+ s.add_runtime_dependency(%q<sc-core-ext>, [">= 1.1.1"])
78
+ s.add_development_dependency(%q<jeweler>, [">= 1.4.0"])
79
+ s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
80
+ s.add_development_dependency(%q<rspec-rails>, [">= 1.3.2"])
81
+ else
82
+ s.add_dependency(%q<actionpack>, [">= 2.3.5"])
83
+ s.add_dependency(%q<sc-core-ext>, [">= 1.1.1"])
84
+ s.add_dependency(%q<jeweler>, [">= 1.4.0"])
85
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
86
+ s.add_dependency(%q<rspec-rails>, [">= 1.3.2"])
87
+ end
88
+ else
89
+ s.add_dependency(%q<actionpack>, [">= 2.3.5"])
90
+ s.add_dependency(%q<sc-core-ext>, [">= 1.1.1"])
91
+ s.add_dependency(%q<jeweler>, [">= 1.4.0"])
92
+ s.add_dependency(%q<rspec>, [">= 1.3.0"])
93
+ s.add_dependency(%q<rspec-rails>, [">= 1.3.2"])
94
+ end
95
+ end
96
+