spambust 0.1.1 → 0.1.2
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.
- checksums.yaml +8 -8
- data/README.md +107 -5
- data/lib/spambust/form_helpers.rb +95 -2
- data/lib/spambust/version.rb +1 -1
- data/spec/spambust/demo_app.rb +5 -3
- data/spec/spambust/form_helpers_spec.rb +24 -18
- data/spec/spambust/views/index.erb +1 -1
- data/spec/spec_helper.rb +2 -2
- metadata +33 -7
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NjQ1MDVhMzViYzFiMzFmNjA1OTU3NjM0ZjllNjJhM2IzZjFlNjc5Nw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZmJkZjFhNmQ1NzJjNjZjY2RjMDU5MDdlMzA3YzdiYTk2NGQ4NDM1OQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MzY3MzE3YmVlZjE3OGRjMTY3YzEzMDg3Y2VjNjI1YTM5MzYwZWEwOWJjNWYw
|
10
|
+
OGM4NmIxOTc1NzNlNjE3ZDVjOGJiYjM3NzY5MGFmOTQ4M2FmNzgwNmIxZDQ4
|
11
|
+
MGJiZTkzNTQ0OTFlZjY5ZGYzMzg4OTQwNjExMGNlZjczMDVkMzg=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OThkNjc2NjY1MDBjZjVhZmJkNDNhYzNmYTQ1Y2M4MjE4OTVkOWZhNzVhNmE2
|
14
|
+
MjdiYTJhYWViZjJmODQ5NWNlNWQwZmU2MWNjZWViZTM2N2VjYTEzMjQyM2Ux
|
15
|
+
OGFmNTcxZTI1Mzk3NmY5MjgxMGE3MTM5MDA1YjA0YWJkZDZkZDY=
|
data/README.md
CHANGED
@@ -1,8 +1,110 @@
|
|
1
|
+
[](https://travis-ci.org/chiku/spambust)
|
2
|
+
|
1
3
|
spambust
|
2
|
-
|
4
|
+
========
|
5
|
+
|
6
|
+
Overview
|
7
|
+
--------
|
8
|
+
|
9
|
+
Prevent spams bots from attacking your website.
|
10
|
+
|
11
|
+
Dependencies
|
12
|
+
------------
|
13
|
+
|
14
|
+
These are no runtime dependencies for this gem.
|
15
|
+
|
16
|
+
Installation
|
17
|
+
------------
|
18
|
+
|
19
|
+
``` script
|
20
|
+
gem install spambust
|
21
|
+
```
|
22
|
+
|
23
|
+
Usage
|
24
|
+
------
|
25
|
+
|
26
|
+
*app.rb*
|
27
|
+
|
28
|
+
``` ruby
|
29
|
+
class TestApp < Sinatra::Base
|
30
|
+
helpers Spambust::FormHelpers
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def start_app
|
34
|
+
run!
|
35
|
+
end
|
36
|
+
|
37
|
+
def direct_script_execution?
|
38
|
+
app_file == $0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
get "/" do
|
43
|
+
erb :index, :locals => { :result => "..." }
|
44
|
+
end
|
45
|
+
|
46
|
+
post '/' do
|
47
|
+
result = valid?("user", params) ? "Users is #{decrypt("user", params)}" : "Faking is bad"
|
48
|
+
erb :index, :locals => { :result => result }
|
49
|
+
end
|
50
|
+
|
51
|
+
start_app if direct_script_execution? && ENV["environment"] != "test"
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
*index.erb*
|
56
|
+
|
57
|
+
``` erb
|
58
|
+
<html>
|
59
|
+
<head>
|
60
|
+
<title>Sample Sinatra application</title>
|
61
|
+
</head>
|
62
|
+
<body>
|
63
|
+
<div id="result"><%= result %></div>
|
64
|
+
|
65
|
+
<form method="post" action="/">
|
66
|
+
<label for="user-first-name">First name</label>
|
67
|
+
<%= input ["user", "first_name"], :id => "user-first-name" %>
|
68
|
+
|
69
|
+
<label for="user-last-name">Last name</label>
|
70
|
+
<%= input ["user", "last_name"], :id => "user-last-name" %>
|
71
|
+
|
72
|
+
<label for="user-email">Email</label>
|
73
|
+
<%= input ["user", "email"], :size => 40, :id => "user-email" %>
|
74
|
+
|
75
|
+
<%= submit "Create account", :id => "user-submit" %>
|
76
|
+
</form>
|
77
|
+
</body>
|
78
|
+
</html>
|
79
|
+
```
|
80
|
+
|
81
|
+
*output*
|
82
|
+
|
83
|
+
``` html
|
84
|
+
<input type="text" name="ee11cbb19052e40b07aac0ca060c23ee[2a034e9d9e2601c21191cca53760eaaf]" id="user-first-name" />
|
85
|
+
<input type="hidden" name="user[first_name]" />
|
86
|
+
```
|
87
|
+
|
88
|
+
How does it work?
|
89
|
+
-----------------
|
90
|
+
|
91
|
+
The server will render obfustated input tags for the user to fill. The input tags for the user will be hidden. A spam bot would see the input tags will meaningful names and fill it in. The server will figure out that this response came from a bot and take approriate action.
|
92
|
+
|
93
|
+
Running tests
|
94
|
+
-------------
|
95
|
+
|
96
|
+
Clone the repository and run `rake` from the root directory.
|
97
|
+
|
98
|
+
Contributing
|
99
|
+
------------
|
100
|
+
|
101
|
+
* Fork the project.
|
102
|
+
* Make your feature addition or bug fix.
|
103
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
104
|
+
* Commit, but do not mess with the VERSION. If you want to have your own version, that is fine but bump the version in a commit by itself in another branch so I can ignore it when I pull.
|
105
|
+
* Send me a pull request.
|
3
106
|
|
4
|
-
|
107
|
+
License
|
108
|
+
-------
|
5
109
|
|
6
|
-
|
7
|
-
We expect a spam bot to fill the incorrect input tags. The server would pick the spam bot
|
8
|
-
and respond accordingly.
|
110
|
+
This gem is released under the MIT license. Please refer to LICENSE for more details.
|
@@ -1,7 +1,80 @@
|
|
1
1
|
require "digest/md5"
|
2
2
|
|
3
|
+
# form_helper.rb
|
4
|
+
#
|
5
|
+
# Author:: Chirantan Mitra
|
6
|
+
# Copyright:: Copyright (c) 2013. All rights reserved
|
7
|
+
# License:: MIT
|
8
|
+
#
|
9
|
+
|
3
10
|
module Spambust
|
11
|
+
# This module provides form helpers for sinatra or alike DSLs/frameworks to test for spams
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# class TestApp < Sinatra::Base
|
15
|
+
# helpers Spambust::FormHelpers
|
16
|
+
#
|
17
|
+
# class << self
|
18
|
+
# def start_app
|
19
|
+
# run!
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def direct_script_execution?
|
23
|
+
# app_file == $0
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# get "/" do
|
28
|
+
# erb :index, :locals => { :result => "..." }
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# post '/' do
|
32
|
+
# result = valid?("user", params) ? "Users is #{decrypt("user", params)}" : "Faking is bad"
|
33
|
+
# erb :index, :locals => { :result => result }
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# start_app if direct_script_execution? && ENV["environment"] != "test"
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# index.erb
|
40
|
+
#
|
41
|
+
# <html>
|
42
|
+
# <head>
|
43
|
+
# <title>Sample Sinatra application</title>
|
44
|
+
# </head>
|
45
|
+
# <body>
|
46
|
+
# <div id="result"><%= result %></div>
|
47
|
+
#
|
48
|
+
# <form method="post" action="/">
|
49
|
+
# <label for="user-first-name">First name</label>
|
50
|
+
# <%= input ["user", "first_name"], :id => "user-first-name" %>
|
51
|
+
#
|
52
|
+
# <label for="user-last-name">Last name</label>
|
53
|
+
# <%= input ["user", "last_name"], :id => "user-last-name" %>
|
54
|
+
#
|
55
|
+
# <label for="user-email">Email</label>
|
56
|
+
# <%= input ["user", "email"], :size => 40, :id => "user-email" %>
|
57
|
+
#
|
58
|
+
# <%= submit "Create account", :id => "user-submit" %>
|
59
|
+
# </form>
|
60
|
+
# </body>
|
61
|
+
# </html>
|
62
|
+
|
4
63
|
module FormHelpers
|
64
|
+
# Returns obfustated input tags together with its fake hidden input tags
|
65
|
+
#
|
66
|
+
# Use inside your templates to generate an obfuscated input field. This is the field that the server will use.
|
67
|
+
# If the server sees that fields with original names (which are hidden) are filled, the server should assume
|
68
|
+
# it be be a spam. It also accepts options for input type and other CSS properties.
|
69
|
+
#
|
70
|
+
# input(["user", "name"])
|
71
|
+
# # => <input type="text" name="#{user_md5}[#{name_md5}]" /><input type="hidden" name="user[name]" />
|
72
|
+
#
|
73
|
+
# input(["user", "name"], :type => "password")
|
74
|
+
# # => <input type="password" name="#{user_md5}[#{name_md5}]" /><input type="hidden" name="user[name]" />
|
75
|
+
#
|
76
|
+
# input(["user", "name"], :id => "name", :class => "name")
|
77
|
+
# # => <input type="text" name="#{user_md5}[#{name_md5}]" id="name" class="name" /><input type="hidden" name="user[name]" class="name" />
|
5
78
|
def input(paths, options = {})
|
6
79
|
type = options.delete(:type) || "text"
|
7
80
|
options_without_id = options.select { |key, value| key != :id }
|
@@ -11,17 +84,32 @@ module Spambust
|
|
11
84
|
%Q(<input type="#{type}" name="#{namify digested_paths}"#{others} /><input type="hidden" name="#{namify paths}"#{others_without_id} />)
|
12
85
|
end
|
13
86
|
|
87
|
+
# Returns submit tags
|
88
|
+
#
|
89
|
+
# Use inside your templates to generate a submit tag.
|
90
|
+
# It also accepts options for CSS properties.
|
91
|
+
#
|
92
|
+
# submit("Submit")
|
93
|
+
# # => <input type="submit" value="Submit" />
|
94
|
+
#
|
95
|
+
# submit("Submit", :id => "submit", :class => "submit")
|
96
|
+
# # => <input type="submit" value="Submit" id="submit" class="submit" />
|
14
97
|
def submit(text, options = {})
|
15
98
|
others = hash_to_options(options)
|
16
99
|
%Q(<input type="submit" value="#{text}"#{others} />)
|
17
100
|
end
|
18
101
|
|
19
|
-
def namify(paths)
|
102
|
+
def namify(paths) # :nodoc:
|
20
103
|
first = paths[0]
|
21
104
|
rest = paths[1..-1].reduce("") { |acc, path| acc << "[#{path}]" }
|
22
105
|
"#{first}#{rest}"
|
23
106
|
end
|
24
107
|
|
108
|
+
# Returns decrypted hash of user submitted POST parameters
|
109
|
+
#
|
110
|
+
# Use inside your application.
|
111
|
+
#
|
112
|
+
# decrypt("user", params)
|
25
113
|
def decrypt(lookup, global)
|
26
114
|
fake = global[lookup] || {}
|
27
115
|
hashed_lookup = Digest::MD5.hexdigest(lookup)
|
@@ -33,12 +121,17 @@ module Spambust
|
|
33
121
|
end
|
34
122
|
end
|
35
123
|
|
124
|
+
# Returns if any POST data was present in the fake input fields
|
125
|
+
#
|
126
|
+
# Use inside your application.
|
127
|
+
#
|
128
|
+
# valid?("user", params)
|
36
129
|
def valid?(lookup, global)
|
37
130
|
fake = global[lookup] || {}
|
38
131
|
fake.none? { |key, value| value != "" }
|
39
132
|
end
|
40
133
|
|
41
|
-
def hash_to_options(hash)
|
134
|
+
def hash_to_options(hash) # :nodoc:
|
42
135
|
hash.reduce("") { |acc, (key, value)| acc << %Q( #{key}="#{value}") }
|
43
136
|
end
|
44
137
|
private :hash_to_options
|
data/lib/spambust/version.rb
CHANGED
data/spec/spambust/demo_app.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
1
3
|
require "sinatra"
|
2
4
|
require File.expand_path "../../lib/spambust/form_helpers", File.dirname(__FILE__)
|
3
5
|
|
@@ -16,12 +18,12 @@ module Spambust
|
|
16
18
|
end
|
17
19
|
|
18
20
|
get "/" do
|
19
|
-
erb :index
|
21
|
+
erb :index, :locals => { :result => "..." }
|
20
22
|
end
|
21
23
|
|
22
24
|
post '/' do
|
23
|
-
|
24
|
-
erb :index
|
25
|
+
result = valid?("user", params) ? "Users is #{decrypt("user", params)}" : "Faking is bad"
|
26
|
+
erb :index, :locals => { :result => result }
|
25
27
|
end
|
26
28
|
|
27
29
|
start_app if direct_script_execution? && ENV["environment"] != "test"
|
@@ -93,31 +93,37 @@ describe "Bustspam::FormHelpers" do
|
|
93
93
|
end
|
94
94
|
|
95
95
|
describe "#valid?" do
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
describe "when none of the paths under lookup are populated" do
|
97
|
+
it "is true" do
|
98
|
+
params = {
|
99
|
+
"user" => { "name" => ""},
|
100
|
+
user_md5 => { name_md5 => "true value" }
|
101
|
+
}
|
101
102
|
|
102
|
-
|
103
|
+
subject.valid?("user", params).must_equal true
|
104
|
+
end
|
103
105
|
end
|
104
106
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
describe "when one of the paths under lookup is populated" do
|
108
|
+
it "is false" do
|
109
|
+
params = {
|
110
|
+
"user" => { "name" => "spam value"},
|
111
|
+
user_md5 => { name_md5 => "true value" }
|
112
|
+
}
|
110
113
|
|
111
|
-
|
114
|
+
subject.valid?("user", params).must_equal false
|
115
|
+
end
|
112
116
|
end
|
113
117
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
118
|
+
describe "when lookup doesn't exist" do
|
119
|
+
it "is true" do
|
120
|
+
params = {
|
121
|
+
"user" => { "name" => "spam value"},
|
122
|
+
user_md5 => { name_md5 => "true value" }
|
123
|
+
}
|
119
124
|
|
120
|
-
|
125
|
+
subject.valid?("user_missing", params).must_equal true
|
126
|
+
end
|
121
127
|
end
|
122
128
|
end
|
123
129
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spambust
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chirantan Mitra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
11
|
+
date: 2013-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-test
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: minitest
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,13 +80,11 @@ dependencies:
|
|
52
80
|
- - ! '>='
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: '0'
|
55
|
-
description: ! 'Render input tags with a masked name. The input tags with proper
|
83
|
+
description: ! 'Render input tags with a masked name. The input tags with proper names
|
56
84
|
are hidden.
|
57
85
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
and respond accordingly.
|
86
|
+
A spam bot is expected to fill the incorrect input tags. The server would indentify
|
87
|
+
this and respond appropriately.
|
62
88
|
|
63
89
|
'
|
64
90
|
email:
|