rack-honeypot 0.1.0 → 0.1.1
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.
- data/lib/rack/honeypot.rb +21 -17
- metadata +7 -38
- data/Gemfile +0 -7
- data/Rakefile +0 -6
- data/test/test_honeypot.rb +0 -87
data/lib/rack/honeypot.rb
CHANGED
@@ -16,52 +16,56 @@ module Rack
|
|
16
16
|
def call(env)
|
17
17
|
if spambot_submission?(Rack::Request.new(env).params)
|
18
18
|
@logger.warn("[Rack::Honeypot] Spam bot detected; responded with null") unless @logger.nil?
|
19
|
-
|
19
|
+
null_response
|
20
20
|
else
|
21
21
|
status, headers, response = @app.call(env)
|
22
|
-
new_body = insert_honeypot(
|
23
|
-
new_headers =
|
22
|
+
new_body = insert_honeypot(response_body(response))
|
23
|
+
new_headers = response_headers(headers, new_body)
|
24
24
|
[status, new_headers, new_body]
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
private
|
29
|
+
|
28
30
|
def spambot_submission?(form_hash)
|
29
31
|
form_hash && form_hash[@input_name] && form_hash[@input_name] != @input_value
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
34
|
+
def null_response
|
33
35
|
[200, {'Content-Type' => 'text/html', "Content-Length" => "0"}, []]
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
|
38
|
-
response.each { |part| response_body += part }
|
39
|
-
response_body
|
38
|
+
def response_body(response)
|
39
|
+
response.join("")
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
44
|
-
new_headers["Content-Length"] = body.length.to_s
|
45
|
-
new_headers
|
42
|
+
def response_headers(headers, body)
|
43
|
+
headers.merge("Content-Length" => body.length.to_s)
|
46
44
|
end
|
47
45
|
|
48
46
|
def insert_honeypot(body)
|
49
|
-
css
|
47
|
+
body.gsub!(/<\/head>/, css + "\n</head>")
|
48
|
+
body.gsub!(/<form(.*)>/, '<form\1>' + "\n" + div)
|
49
|
+
body
|
50
|
+
end
|
51
|
+
|
52
|
+
def css
|
53
|
+
unindent <<-BLOCK
|
50
54
|
<style type='text/css' media='all'>
|
51
55
|
div.#{@class_name} {
|
52
56
|
display:none;
|
53
57
|
}
|
54
58
|
</style>
|
55
59
|
BLOCK
|
56
|
-
|
60
|
+
end
|
61
|
+
|
62
|
+
def div
|
63
|
+
unindent <<-BLOCK
|
57
64
|
<div class='#{@class_name}'>
|
58
65
|
<label for='#{@input_name}'>#{@label}</label>
|
59
66
|
<input type='text' name='#{@input_name}' value='#{@input_value}'/>
|
60
67
|
</div>
|
61
68
|
BLOCK
|
62
|
-
body.gsub!(/<\/head>/, css + "\n</head>")
|
63
|
-
body.gsub!(/<form(.*)>/, '<form\1>' + "\n" + div)
|
64
|
-
body
|
65
69
|
end
|
66
70
|
|
67
71
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-honeypot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Luigi Montanez
|
@@ -19,24 +19,10 @@ cert_chain: []
|
|
19
19
|
|
20
20
|
date: 2011-10-05 00:00:00 Z
|
21
21
|
dependencies:
|
22
|
-
- !ruby/object:Gem::Dependency
|
23
|
-
name: rake
|
24
|
-
prerelease: false
|
25
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
|
-
requirements:
|
28
|
-
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
hash: 3
|
31
|
-
segments:
|
32
|
-
- 0
|
33
|
-
version: "0"
|
34
|
-
type: :runtime
|
35
|
-
version_requirements: *id001
|
36
22
|
- !ruby/object:Gem::Dependency
|
37
23
|
name: unindentable
|
38
24
|
prerelease: false
|
39
|
-
requirement: &
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
40
26
|
none: false
|
41
27
|
requirements:
|
42
28
|
- - "="
|
@@ -48,25 +34,11 @@ dependencies:
|
|
48
34
|
- 4
|
49
35
|
version: 0.0.4
|
50
36
|
type: :runtime
|
51
|
-
version_requirements: *
|
37
|
+
version_requirements: *id001
|
52
38
|
- !ruby/object:Gem::Dependency
|
53
39
|
name: rack
|
54
40
|
prerelease: false
|
55
|
-
requirement: &
|
56
|
-
none: false
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
hash: 3
|
61
|
-
segments:
|
62
|
-
- 0
|
63
|
-
version: "0"
|
64
|
-
type: :runtime
|
65
|
-
version_requirements: *id003
|
66
|
-
- !ruby/object:Gem::Dependency
|
67
|
-
name: rack-test
|
68
|
-
prerelease: false
|
69
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
70
42
|
none: false
|
71
43
|
requirements:
|
72
44
|
- - ">="
|
@@ -76,7 +48,7 @@ dependencies:
|
|
76
48
|
- 0
|
77
49
|
version: "0"
|
78
50
|
type: :runtime
|
79
|
-
version_requirements: *
|
51
|
+
version_requirements: *id002
|
80
52
|
description: This middleware acts as a spam trap. It inserts, into every outputted <form>, a text field that a spambot will really want to fill in, but is actually not used by the app. The field is hidden to humans via CSS, and includes a warning label for screenreading software.
|
81
53
|
email: luigi.montanez@gmail.com
|
82
54
|
executables: []
|
@@ -87,13 +59,10 @@ extra_rdoc_files:
|
|
87
59
|
- LICENSE.md
|
88
60
|
- README.md
|
89
61
|
files:
|
90
|
-
- Gemfile
|
91
62
|
- LICENSE.md
|
92
63
|
- README.md
|
93
|
-
- Rakefile
|
94
64
|
- VERSION
|
95
65
|
- lib/rack/honeypot.rb
|
96
|
-
- test/test_honeypot.rb
|
97
66
|
homepage: http://github.com/sunlightlabs/rack-honeypot
|
98
67
|
licenses: []
|
99
68
|
|
data/Gemfile
DELETED
data/Rakefile
DELETED
data/test/test_honeypot.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'rack/test'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'mocha'
|
4
|
-
require 'unindentable'
|
5
|
-
|
6
|
-
require File.expand_path(File.dirname(__FILE__) + '/../lib/rack/honeypot')
|
7
|
-
|
8
|
-
# To run this test, you need to have rack-test gem installed: sudo gem install rack-test
|
9
|
-
|
10
|
-
class HoneypotTest < Test::Unit::TestCase
|
11
|
-
include Rack::Test::Methods
|
12
|
-
include Unindentable
|
13
|
-
|
14
|
-
def setup
|
15
|
-
@logger = stub("logger", :warn => nil)
|
16
|
-
end
|
17
|
-
|
18
|
-
def app
|
19
|
-
content = unindent <<-BLOCK
|
20
|
-
<html>
|
21
|
-
<head>
|
22
|
-
</head>
|
23
|
-
<body>
|
24
|
-
<form></form>
|
25
|
-
Hello World!
|
26
|
-
</body>
|
27
|
-
</html>
|
28
|
-
BLOCK
|
29
|
-
|
30
|
-
hello_world_app = lambda do |env|
|
31
|
-
[
|
32
|
-
200,
|
33
|
-
{
|
34
|
-
'Content-Type' => 'text/plain',
|
35
|
-
'Content-Length' => content.length.to_s
|
36
|
-
},
|
37
|
-
[content]
|
38
|
-
]
|
39
|
-
end
|
40
|
-
|
41
|
-
Rack::Honeypot.new(hello_world_app, :input_name => 'honeypot_email', :logger => @logger)
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_normal_request_should_go_through
|
45
|
-
get '/'
|
46
|
-
assert_equal 200, last_response.status
|
47
|
-
assert_not_equal '', last_response.body
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_request_with_form_should_add_honeypot_css
|
51
|
-
get '/'
|
52
|
-
assert_equal 200, last_response.status
|
53
|
-
css = unindent <<-BLOCK
|
54
|
-
<style type='text/css' media='all'>
|
55
|
-
div.phonetoy {
|
56
|
-
display:none;
|
57
|
-
}
|
58
|
-
</style>
|
59
|
-
BLOCK
|
60
|
-
assert last_response.body.index(css)
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_request_with_form_should_add_honeypot_div
|
64
|
-
get '/'
|
65
|
-
assert_equal 200, last_response.status
|
66
|
-
|
67
|
-
div = unindent <<-BLOCK
|
68
|
-
<div class='phonetoy'>
|
69
|
-
<label for='honeypot_email'>Don't fill in this field</label>
|
70
|
-
<input type='text' name='honeypot_email' value=''/>
|
71
|
-
</div>
|
72
|
-
BLOCK
|
73
|
-
assert last_response.body.index(div)
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_spam_request_should_be_sent_to_dead_end
|
77
|
-
post '/', :honeypot_email => 'joe@example.com'
|
78
|
-
assert_equal 200, last_response.status
|
79
|
-
assert_equal '', last_response.body
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_spam_request_should_be_logged
|
83
|
-
@logger.expects(:warn).with("[Rack::Honeypot] Spam bot detected; responded with null")
|
84
|
-
post '/', :honeypot_email => 'joe@example.com'
|
85
|
-
end
|
86
|
-
|
87
|
-
end
|