the_captcha 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +229 -0
- data/Rakefile +22 -0
- data/lib/generators/USAGE +4 -0
- data/lib/generators/simple_captcha_generator.rb +21 -0
- data/lib/generators/templates/migration.rb +15 -0
- data/lib/generators/templates/partial.erb +37 -0
- data/lib/simple_captcha/active_record.rb +74 -0
- data/lib/simple_captcha/controller.rb +29 -0
- data/lib/simple_captcha/engine.rb +30 -0
- data/lib/simple_captcha/form_builder.rb +34 -0
- data/lib/simple_captcha/formtastic.rb +11 -0
- data/lib/simple_captcha/image.rb +84 -0
- data/lib/simple_captcha/middleware.rb +58 -0
- data/lib/simple_captcha/simple_captcha_data.rb +33 -0
- data/lib/simple_captcha/utils.rb +36 -0
- data/lib/simple_captcha/version.rb +4 -0
- data/lib/simple_captcha/view.rb +110 -0
- data/lib/simple_captcha.rb +56 -0
- data/test/simple_captcha_test.rb +8 -0
- metadata +87 -0
data/README.rdoc
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
=SimpleCaptcha
|
2
|
+
|
3
|
+
SimpleCaptcha is the simplest and a robust captcha plugin. Its implementation requires
|
4
|
+
adding up a single line in views and in controllers/models.
|
5
|
+
SimpleCaptcha is available to be used with Rails 3 or above and also it provides the
|
6
|
+
backward compatibility with previous versions of Rails.
|
7
|
+
|
8
|
+
==Features
|
9
|
+
|
10
|
+
* Zero FileSystem usage(secret code moved to db-store and image storage removed).
|
11
|
+
* Provides various image styles.
|
12
|
+
* Provides three level of complexity of images.
|
13
|
+
* Works absolutely fine in distributed environment(session and db based implementation works fine in distributed environment).
|
14
|
+
* Implementation is as easy as just writing a single line in your view. "<%= show_simple_captcha %>" within the 'form' tags.
|
15
|
+
* Flexible DOM and CSS handling(There is a separate view partial for rednering SimpleCaptcha DOM elements).
|
16
|
+
* Automated removal of 1 hour old unmatched simple_captcha data.
|
17
|
+
|
18
|
+
==Requirements
|
19
|
+
|
20
|
+
* {Ruby}[http://ruby-lang.org/] >= 1.8.7
|
21
|
+
* {Rails}[http://github.com/rails/rails] >= 3
|
22
|
+
* ImageMagick should be installed on your machine to use this plugin.
|
23
|
+
visit http://www.imagemagick.org/script/index.php for more details.
|
24
|
+
|
25
|
+
==Installation
|
26
|
+
|
27
|
+
gem "galetahub-simple_captcha", :require => "simple_captcha"
|
28
|
+
|
29
|
+
or
|
30
|
+
|
31
|
+
gem 'galetahub-simple_captcha', :require => 'simple_captcha', :git => 'git://github.com/galetahub/simple-captcha.git'
|
32
|
+
|
33
|
+
==Setup
|
34
|
+
|
35
|
+
After installation, follow these simple steps to setup the plugin. The setup will depend
|
36
|
+
on the version of rails your application is using.
|
37
|
+
|
38
|
+
rails generate simple_captcha
|
39
|
+
|
40
|
+
rake db:migrate
|
41
|
+
|
42
|
+
==Usage
|
43
|
+
|
44
|
+
===Controller Based
|
45
|
+
|
46
|
+
Add the following line in the file "app/controllers/application.rb"
|
47
|
+
|
48
|
+
ApplicationController < ActionController::Base
|
49
|
+
include SimpleCaptcha::ControllerHelpers
|
50
|
+
end
|
51
|
+
|
52
|
+
In the view file within the form tags add this code
|
53
|
+
|
54
|
+
<%= show_simple_captcha %>
|
55
|
+
|
56
|
+
and in the controller's action authenticate it as
|
57
|
+
|
58
|
+
if simple_captcha_valid?
|
59
|
+
do this
|
60
|
+
else
|
61
|
+
do that
|
62
|
+
end
|
63
|
+
|
64
|
+
===Model Based
|
65
|
+
|
66
|
+
In the view file within the form tags write this code
|
67
|
+
|
68
|
+
<%= show_simple_captcha(:object=>"user") %>
|
69
|
+
|
70
|
+
and in the model class add this code
|
71
|
+
|
72
|
+
class User < ActiveRecord::Basse
|
73
|
+
apply_simple_captcha
|
74
|
+
end
|
75
|
+
|
76
|
+
====FormBuilder helper
|
77
|
+
|
78
|
+
<%= form_for @user do |form| -%>
|
79
|
+
...
|
80
|
+
<%= form.simple_captcha :label => "Enter numbers.." %>
|
81
|
+
...
|
82
|
+
<% end -%>
|
83
|
+
|
84
|
+
====Validating with captcha
|
85
|
+
NOTE: @user.valid? will still work as it should, it will not validate the captcha code.
|
86
|
+
|
87
|
+
@user.valid_with_captcha?
|
88
|
+
|
89
|
+
====Saving with captcha
|
90
|
+
NOTE: @user.save will still work as it should, it will not validate the captcha code.
|
91
|
+
|
92
|
+
@user.save_with_captcha
|
93
|
+
|
94
|
+
===Formtastic integration
|
95
|
+
SimpleCaptcha detects if your use Formtastic and appends "SimpleCaptcha::CustomFormBuilder".
|
96
|
+
|
97
|
+
<%= form.input :captcha, :as => :simple_captcha %>
|
98
|
+
|
99
|
+
==Options & Examples
|
100
|
+
===View Options
|
101
|
+
|
102
|
+
* *label* - provides the custom text b/w the image and the text field, the default is "type the code from the image"
|
103
|
+
|
104
|
+
* *object* - the name of the object of the model class, to implement the model based captcha.
|
105
|
+
|
106
|
+
* *code_type* - return numeric only if set to 'numeric'
|
107
|
+
|
108
|
+
===Global options
|
109
|
+
|
110
|
+
* *image_style* - provides the specific image style for the captcha image.
|
111
|
+
There are eight different styles available with the plugin as...
|
112
|
+
1) simply_blue
|
113
|
+
2) simply_red
|
114
|
+
3) simply_green
|
115
|
+
4) charcoal_grey
|
116
|
+
5) embosed_silver
|
117
|
+
6) all_black
|
118
|
+
7) distorted_black
|
119
|
+
8) almost_invisible
|
120
|
+
Default style is 'simply_blue'.
|
121
|
+
You can also specify 'random' to select the random image style.
|
122
|
+
|
123
|
+
* *distortion* - handles the complexity of the image. The :distortion can be set to 'low', 'medium' or 'high'. Default is 'low'.
|
124
|
+
|
125
|
+
Create "rails_root/config/initializers/simple_captcha.rb"
|
126
|
+
|
127
|
+
SimpleCaptcha.setup do |sc|
|
128
|
+
# default: 100x28
|
129
|
+
sc.image_size = '120x40'
|
130
|
+
|
131
|
+
# default: 5
|
132
|
+
sc.length = 6
|
133
|
+
|
134
|
+
# default: simply_blue
|
135
|
+
# possible values:
|
136
|
+
# 'embosed_silver',
|
137
|
+
# 'simply_red',
|
138
|
+
# 'simply_green',
|
139
|
+
# 'simply_blue',
|
140
|
+
# 'distorted_black',
|
141
|
+
# 'all_black',
|
142
|
+
# 'charcoal_grey',
|
143
|
+
# 'almost_invisible'
|
144
|
+
# 'random'
|
145
|
+
sc.image_style = 'simply_green'
|
146
|
+
|
147
|
+
# default: low
|
148
|
+
# possible values: 'low', 'medium', 'high', 'random'
|
149
|
+
sc.distortion = 'medium'
|
150
|
+
end
|
151
|
+
|
152
|
+
You can add your own style:
|
153
|
+
|
154
|
+
SimpleCaptcha.setup do |sc|
|
155
|
+
sc.image_style = 'mycaptha'
|
156
|
+
sc.add_image_style('mycaptha', [
|
157
|
+
"-background '#F4F7F8'",
|
158
|
+
"-fill '#86818B'",
|
159
|
+
"-border 1",
|
160
|
+
"-bordercolor '#E0E2E3'"])
|
161
|
+
end
|
162
|
+
|
163
|
+
You can provide the path where image_magick is installed as well:
|
164
|
+
|
165
|
+
SimpleCaptcha.setup do |sc|
|
166
|
+
sc.image_magick_path = '/usr/bin' # you can check this from console by running: which convert
|
167
|
+
end
|
168
|
+
|
169
|
+
You can provide the path where should be stored tmp files.
|
170
|
+
It's usefull when you dont have acces to /tmp (default directory)
|
171
|
+
|
172
|
+
SimpleCaptcha.setup do |sc|
|
173
|
+
sc.tmp_path = '/tmp' # or somewhere in project eg. Rails.root.join('tmp/simple_captcha').to_s, make shure directory exists
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
===How to change the CSS for SimpleCaptcha DOM elements?
|
178
|
+
You can change the CSS of the SimpleCaptcha DOM elements as per your need in this file.
|
179
|
+
/app/views/simple_captcha/_simple_captcha.erb
|
180
|
+
|
181
|
+
===View's Examples
|
182
|
+
====Controller Based Example
|
183
|
+
|
184
|
+
<%= show_simple_captcha %>
|
185
|
+
|
186
|
+
<%= show_simple_captcha(:label => "human authentication") %>
|
187
|
+
|
188
|
+
====Model Based Example
|
189
|
+
|
190
|
+
<%= show_simple_captcha(:object => 'user', :label => "human authentication") %>
|
191
|
+
|
192
|
+
====Model Options
|
193
|
+
|
194
|
+
* *message* - provides the custom message on failure of captcha authentication the default is "Secret Code did not match with the Image"
|
195
|
+
|
196
|
+
* *add_to_base* - if set to true, appends the error message to the base.
|
197
|
+
|
198
|
+
=====Model's Example
|
199
|
+
|
200
|
+
class User < ActiveRecord::Base
|
201
|
+
apply_simple_captcha
|
202
|
+
end
|
203
|
+
|
204
|
+
class User < ActiveRecord::Base
|
205
|
+
apply_simple_captcha :message => "The secret Image and code were different", :add_to_base => true
|
206
|
+
end
|
207
|
+
|
208
|
+
==I18n
|
209
|
+
|
210
|
+
simple_captcha:
|
211
|
+
message:
|
212
|
+
default: "Secret Code did not match with the Image"
|
213
|
+
user: "The secret Image and code were different"
|
214
|
+
|
215
|
+
==Who's who?
|
216
|
+
|
217
|
+
Enjoy the simplest captcha implementation.
|
218
|
+
|
219
|
+
Author: Sur
|
220
|
+
|
221
|
+
Blog: http://expressica.com
|
222
|
+
|
223
|
+
Contact: sur.max@gmail.com
|
224
|
+
|
225
|
+
Plugin Homepage: http://expressica.com/simple_captcha
|
226
|
+
|
227
|
+
Plugin update for rails 3: http://github.com/galetahub
|
228
|
+
|
229
|
+
Any feedback/comment/issue/donation is welcome!
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the simple_captcha plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the simple_captcha plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'SimpleCaptcha'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
class SimpleCaptchaGenerator < Rails::Generators::Base
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates/'))
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.next_migration_number(dirname)
|
11
|
+
Time.now.strftime("%Y%m%d%H%M%S")
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_partial
|
15
|
+
template "partial.erb", File.join('app/views', 'simple_captcha', "_simple_captcha.erb")
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_migration
|
19
|
+
migration_template "migration.rb", File.join('db/migrate', "create_simple_captcha_data.rb")
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateSimpleCaptchaData < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :simple_captcha_data do |t|
|
4
|
+
t.string :key, :limit => 40
|
5
|
+
t.string :value, :limit => 6
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :simple_captcha_data, :key, :name => "idx_key"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table :simple_captcha_data
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<style type="text/CSS">
|
2
|
+
.simple_captcha{border: 1px solid #ccc; padding: 5px !important;}
|
3
|
+
.simple_captcha,
|
4
|
+
.simple_captcha div{display: table;}
|
5
|
+
.simple_captcha .simple_captcha_field,
|
6
|
+
.simple_captcha .simple_captcha_image{
|
7
|
+
border: 1px solid #ccc;
|
8
|
+
margin: 0px 0px 2px 0px !important;
|
9
|
+
padding: 0px !important;
|
10
|
+
}
|
11
|
+
.simple_captcha .simple_captcha_image img{
|
12
|
+
margin: 0px !important;
|
13
|
+
padding: 0px !important;
|
14
|
+
width: 110px !important;
|
15
|
+
}
|
16
|
+
.simple_captcha .simple_captcha_label{font-size: 12px;}
|
17
|
+
.simple_captcha .simple_captcha_field input{
|
18
|
+
width: 150px !important;
|
19
|
+
font-size: 16px;
|
20
|
+
border: none;
|
21
|
+
background-color: #efefef;
|
22
|
+
}
|
23
|
+
</style>
|
24
|
+
|
25
|
+
<div class='simple_captcha'>
|
26
|
+
<div class='simple_captcha_image'>
|
27
|
+
<%%= simple_captcha_options[:image] %>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class='simple_captcha_field'>
|
31
|
+
<%%= simple_captcha_options[:field] %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class='simple_captcha_label'>
|
35
|
+
<%%= simple_captcha_options[:label] %>
|
36
|
+
</div>
|
37
|
+
</div>
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module SimpleCaptcha #:nodoc
|
2
|
+
module ModelHelpers #:nodoc
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(SingletonMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
# To implement model based simple captcha use this method in the model as...
|
8
|
+
#
|
9
|
+
# class User < ActiveRecord::Base
|
10
|
+
#
|
11
|
+
# apply_simple_captcha :message => "my customized message"
|
12
|
+
#
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# Customize the error message by using :message, the default message is "Captcha did not match".
|
16
|
+
# As in the applications captcha is needed with a very few cases like signing up the new user, but
|
17
|
+
# not every time you need to authenticate the captcha with @user.save. So as to maintain simplicity
|
18
|
+
# here we have the explicit method to save the instace with captcha validation as...
|
19
|
+
#
|
20
|
+
# * to validate the instance
|
21
|
+
#
|
22
|
+
# @user.valid_with_captcha? # whene captcha validation is required.
|
23
|
+
#
|
24
|
+
# @user.valid? # when captcha validation is not required.
|
25
|
+
#
|
26
|
+
# * to save the instance
|
27
|
+
#
|
28
|
+
# @user.save_with_captcha # whene captcha validation is required.
|
29
|
+
#
|
30
|
+
# @user.save # when captcha validation is not required.
|
31
|
+
module SingletonMethods
|
32
|
+
def apply_simple_captcha(options = {})
|
33
|
+
options = { :add_to_base => false }.merge(options)
|
34
|
+
|
35
|
+
class_attribute :simple_captcha_options
|
36
|
+
self.simple_captcha_options = options
|
37
|
+
|
38
|
+
unless self.is_a?(ClassMethods)
|
39
|
+
include InstanceMethods
|
40
|
+
extend ClassMethods
|
41
|
+
|
42
|
+
attr_accessor :captcha, :captcha_key
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
end
|
49
|
+
|
50
|
+
module InstanceMethods
|
51
|
+
|
52
|
+
def valid_with_captcha?
|
53
|
+
[valid?, is_captcha_valid?].all?
|
54
|
+
end
|
55
|
+
|
56
|
+
def is_captcha_valid?
|
57
|
+
return true if Rails.env.test?
|
58
|
+
|
59
|
+
if captcha && captcha.upcase.delete(" ") == SimpleCaptcha::Utils::simple_captcha_value(captcha_key)
|
60
|
+
SimpleCaptcha::Utils::simple_captcha_passed!(captcha_key)
|
61
|
+
return true
|
62
|
+
else
|
63
|
+
message = simple_captcha_options[:message] || I18n.t(self.class.model_name.downcase, :scope => [:simple_captcha, :message], :default => :default)
|
64
|
+
simple_captcha_options[:add_to_base] ? errors.add(:base, message) : errors.add(:captcha, message)
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def save_with_captcha
|
70
|
+
valid_with_captcha? && save(:validate => false)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SimpleCaptcha #:nodoc
|
2
|
+
module ControllerHelpers #:nodoc
|
3
|
+
# This method is to validate the simple captcha in controller.
|
4
|
+
# It means when the captcha is controller based i.e. :object has not been passed to the method show_simple_captcha.
|
5
|
+
#
|
6
|
+
# *Example*
|
7
|
+
#
|
8
|
+
# If you want to save an object say @user only if the captcha is validated then do like this in action...
|
9
|
+
#
|
10
|
+
# if simple_captcha_valid?
|
11
|
+
# @user.save
|
12
|
+
# else
|
13
|
+
# flash[:notice] = "captcha did not match"
|
14
|
+
# redirect_to :action => "myaction"
|
15
|
+
# end
|
16
|
+
def simple_captcha_valid?
|
17
|
+
return true if Rails.env.test?
|
18
|
+
|
19
|
+
if params[:captcha]
|
20
|
+
data = SimpleCaptcha::Utils::simple_captcha_value(session[:captcha])
|
21
|
+
result = data == params[:captcha].delete(" ").upcase
|
22
|
+
SimpleCaptcha::Utils::simple_captcha_passed!(session[:captcha]) if result
|
23
|
+
return result
|
24
|
+
else
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rails'
|
3
|
+
require 'simple_captcha'
|
4
|
+
|
5
|
+
module SimpleCaptcha
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
config.before_initialize do
|
8
|
+
ActiveSupport.on_load :active_record do
|
9
|
+
ActiveRecord::Base.send(:include, SimpleCaptcha::ModelHelpers)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
config.after_initialize do
|
14
|
+
ActionView::Base.send(:include, SimpleCaptcha::ViewHelper)
|
15
|
+
ActionView::Helpers::FormBuilder.send(:include, SimpleCaptcha::FormBuilder)
|
16
|
+
|
17
|
+
if Object.const_defined?("Formtastic")
|
18
|
+
if Formtastic.const_defined?("Helpers")
|
19
|
+
Formtastic::Helpers::FormHelper.builder = SimpleCaptcha::CustomFormBuilder
|
20
|
+
else
|
21
|
+
Formtastic::SemanticFormHelper.builder = SimpleCaptcha::CustomFormBuilder
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
config.app_middleware.use SimpleCaptcha::Middleware
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SimpleCaptcha
|
2
|
+
module FormBuilder
|
3
|
+
def self.included(base)
|
4
|
+
base.send(:include, SimpleCaptcha::ViewHelper)
|
5
|
+
base.send(:include, SimpleCaptcha::FormBuilder::ClassMethods)
|
6
|
+
|
7
|
+
base.delegate :render, :session, :to => :template
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# Example:
|
12
|
+
# <% form_for :post, :url => posts_path do |form| %>
|
13
|
+
# ...
|
14
|
+
# <%= form.simple_captcha :label => "Enter numbers.." %>
|
15
|
+
# <% end %>
|
16
|
+
#
|
17
|
+
def simple_captcha(options = {})
|
18
|
+
options.update :object => @object_name
|
19
|
+
show_simple_captcha(objectify_options(options))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def template
|
25
|
+
@template
|
26
|
+
end
|
27
|
+
|
28
|
+
def simple_captcha_field(options={})
|
29
|
+
text_field(:captcha, :value => '', :autocomplete => 'off') +
|
30
|
+
hidden_field(:captcha_key, {:value => options[:field_value]})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
module SimpleCaptcha #:nodoc
|
3
|
+
module ImageHelpers #:nodoc
|
4
|
+
|
5
|
+
mattr_accessor :image_styles
|
6
|
+
@@image_styles = {
|
7
|
+
'embosed_silver' => ['-fill darkblue', '-shade 20x60', '-background white'],
|
8
|
+
'simply_red' => ['-fill darkred', '-background white'],
|
9
|
+
'simply_green' => ['-fill darkgreen', '-background white'],
|
10
|
+
'simply_blue' => ['-fill darkblue', '-background white'],
|
11
|
+
'distorted_black' => ['-fill darkblue', '-edge 10', '-background white'],
|
12
|
+
'all_black' => ['-fill darkblue', '-edge 2', '-background white'],
|
13
|
+
'charcoal_grey' => ['-fill darkblue', '-charcoal 5', '-background white'],
|
14
|
+
'almost_invisible' => ['-fill red', '-solarize 50', '-background white']
|
15
|
+
}
|
16
|
+
|
17
|
+
DISTORTIONS = ['low', 'medium', 'high']
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
def image_params(key = 'simply_blue')
|
22
|
+
image_keys = @@image_styles.keys
|
23
|
+
|
24
|
+
style = begin
|
25
|
+
if key == 'random'
|
26
|
+
image_keys[rand(image_keys.length)]
|
27
|
+
else
|
28
|
+
image_keys.include?(key) ? key : 'simply_blue'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@@image_styles[style]
|
33
|
+
end
|
34
|
+
|
35
|
+
def distortion(key='low')
|
36
|
+
key =
|
37
|
+
key == 'random' ?
|
38
|
+
DISTORTIONS[rand(DISTORTIONS.length)] :
|
39
|
+
DISTORTIONS.include?(key) ? key : 'low'
|
40
|
+
case key.to_s
|
41
|
+
when 'low' then return [0 + rand(2), 80 + rand(20)]
|
42
|
+
when 'medium' then return [2 + rand(2), 50 + rand(20)]
|
43
|
+
when 'high' then return [4 + rand(2), 30 + rand(20)]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if RUBY_VERSION < '1.9'
|
49
|
+
class Tempfile < ::Tempfile
|
50
|
+
# Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
|
51
|
+
def make_tmpname(basename, n = 0)
|
52
|
+
extension = File.extname(basename)
|
53
|
+
sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def generate_simple_captcha_image(simple_captcha_key) #:nodoc
|
61
|
+
amplitude, frequency = ImageHelpers.distortion(SimpleCaptcha.distortion)
|
62
|
+
text = Utils::simple_captcha_value(simple_captcha_key)
|
63
|
+
|
64
|
+
params = ImageHelpers.image_params(SimpleCaptcha.image_style).dup
|
65
|
+
params << "-size #{SimpleCaptcha.image_size}"
|
66
|
+
params << "-wave #{amplitude}x#{frequency}"
|
67
|
+
params << "-gravity 'Center'"
|
68
|
+
params << "-pointsize 22"
|
69
|
+
params << "-implode 0.2"
|
70
|
+
|
71
|
+
dst = Tempfile.new(RUBY_VERSION < '1.9' ? 'simple_captcha.jpg' : ['simple_captcha', '.jpg'], SimpleCaptcha.tmp_path)
|
72
|
+
dst.binmode
|
73
|
+
|
74
|
+
params << "label:#{text} '#{File.expand_path(dst.path)}'"
|
75
|
+
|
76
|
+
SimpleCaptcha::Utils::run("convert", params.join(' '))
|
77
|
+
|
78
|
+
dst.close
|
79
|
+
|
80
|
+
File.expand_path(dst.path)
|
81
|
+
#dst
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module SimpleCaptcha
|
3
|
+
class Middleware
|
4
|
+
include SimpleCaptcha::ImageHelpers
|
5
|
+
|
6
|
+
DEFAULT_SEND_FILE_OPTIONS = {
|
7
|
+
:type => 'application/octet-stream'.freeze,
|
8
|
+
:disposition => 'attachment'.freeze,
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
def initialize(app, options={})
|
12
|
+
@app = app
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env) # :nodoc:
|
17
|
+
if env["REQUEST_METHOD"] == "GET" && captcha_path?(env['PATH_INFO'])
|
18
|
+
make_image(env)
|
19
|
+
else
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
def make_image(env, headers = {}, status = 404)
|
26
|
+
request = Rack::Request.new(env)
|
27
|
+
code = request.params["code"]
|
28
|
+
body = []
|
29
|
+
|
30
|
+
if !code.blank? && Utils::simple_captcha_value(code)
|
31
|
+
#status, headers, body = @app.call(env)
|
32
|
+
#status = 200
|
33
|
+
#body = generate_simple_captcha_image(code)
|
34
|
+
#headers['Content-Type'] = 'image/jpeg'
|
35
|
+
|
36
|
+
return send_file(generate_simple_captcha_image(code), :type => 'image/jpeg', :disposition => 'inline', :filename => 'simple_captcha.jpg')
|
37
|
+
end
|
38
|
+
|
39
|
+
[status, headers, body]
|
40
|
+
end
|
41
|
+
|
42
|
+
def captcha_path?(request_path)
|
43
|
+
request_path.include?('/simple_captcha')
|
44
|
+
end
|
45
|
+
|
46
|
+
def send_file(path, options = {})
|
47
|
+
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
|
48
|
+
|
49
|
+
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
|
50
|
+
|
51
|
+
status = options[:status] || 200
|
52
|
+
headers = {"Content-Disposition" => "#{options[:disposition]}; filename='#{options[:filename]}'", "Content-Type" => options[:type], 'Content-Transfer-Encoding' => 'binary', 'Cache-Control' => 'private'}
|
53
|
+
response_body = File.open(path, "rb")
|
54
|
+
|
55
|
+
[status, headers, response_body]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SimpleCaptcha
|
2
|
+
class SimpleCaptchaData < ::ActiveRecord::Base
|
3
|
+
def self.rails3?
|
4
|
+
::ActiveRecord::VERSION::MAJOR == 3
|
5
|
+
end
|
6
|
+
|
7
|
+
if rails3?
|
8
|
+
# Fixes deprecation warning in Rails 3.2:
|
9
|
+
# DEPRECATION WARNING: Calling set_table_name is deprecated. Please use `self.table_name = 'the_name'` instead.
|
10
|
+
self.table_name = "simple_captcha_data"
|
11
|
+
else
|
12
|
+
set_table_name "simple_captcha_data"
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessible :key, :value
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def get_data(key)
|
19
|
+
data = find_by_key(key) || new(:key => key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove_data(key)
|
23
|
+
delete_all(["#{connection.quote_column_name(:key)} = ?", key])
|
24
|
+
clear_old_data(1.hour.ago)
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear_old_data(time = 1.hour.ago)
|
28
|
+
return unless Time === time
|
29
|
+
delete_all(["#{connection.quote_column_name(:updated_at)} < ?", time])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module SimpleCaptcha #:nodoc
|
4
|
+
module Utils #:nodoc
|
5
|
+
# Execute command with params and return output if exit status equal expected_outcodes
|
6
|
+
def self.run(cmd, params = "", expected_outcodes = 0)
|
7
|
+
command = %Q[#{cmd} #{params}].gsub(/\s+/, " ")
|
8
|
+
command = "#{command} 2>&1"
|
9
|
+
|
10
|
+
unless (image_magick_path = SimpleCaptcha.image_magick_path).blank?
|
11
|
+
command = File.join(image_magick_path, command)
|
12
|
+
end
|
13
|
+
|
14
|
+
output = `#{command}`
|
15
|
+
|
16
|
+
unless [expected_outcodes].flatten.include?($?.exitstatus)
|
17
|
+
raise ::StandardError, "Error while running #{cmd}: #{output}"
|
18
|
+
end
|
19
|
+
|
20
|
+
output
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.simple_captcha_value(key) #:nodoc
|
24
|
+
SimpleCaptchaData.get_data(key).value rescue nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.simple_captcha_passed!(key) #:nodoc
|
28
|
+
SimpleCaptchaData.remove_data(key)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.generate_key(*args)
|
32
|
+
args << Time.now.to_s
|
33
|
+
Digest::SHA1.hexdigest(args.join)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module SimpleCaptcha #:nodoc
|
2
|
+
module ViewHelper #:nodoc
|
3
|
+
|
4
|
+
# Simple Captcha is a very simplified captcha.
|
5
|
+
#
|
6
|
+
# It can be used as a *Model* or a *Controller* based Captcha depending on what options
|
7
|
+
# we are passing to the method show_simple_captcha.
|
8
|
+
#
|
9
|
+
# *show_simple_captcha* method will return the image, the label and the text box.
|
10
|
+
# This method should be called from the view within your form as...
|
11
|
+
#
|
12
|
+
# <%= show_simple_captcha %>
|
13
|
+
#
|
14
|
+
# The available options to pass to this method are
|
15
|
+
# * label
|
16
|
+
# * object
|
17
|
+
#
|
18
|
+
# <b>Label:</b>
|
19
|
+
#
|
20
|
+
# default label is "type the text from the image", it can be modified by passing :label as
|
21
|
+
#
|
22
|
+
# <%= show_simple_captcha(:label => "new captcha label") %>.
|
23
|
+
#
|
24
|
+
# *Object*
|
25
|
+
#
|
26
|
+
# This option is needed to create a model based captcha.
|
27
|
+
# If this option is not provided, the captcha will be controller based and
|
28
|
+
# should be checked in controller's action just by calling the method simple_captcha_valid?
|
29
|
+
#
|
30
|
+
# To make a model based captcha give this option as...
|
31
|
+
#
|
32
|
+
# <%= show_simple_captcha(:object => "user") %>
|
33
|
+
# and also call the method apply_simple_captcha in the model
|
34
|
+
# this will consider "user" as the object of the model class.
|
35
|
+
#
|
36
|
+
# *Examples*
|
37
|
+
# * controller based
|
38
|
+
# <%= show_simple_captcha(:label => "Human Authentication: type the text from image above") %>
|
39
|
+
# * model based
|
40
|
+
# <%= show_simple_captcha(:object => "person", :label => "Human Authentication: type the text from image above") %>
|
41
|
+
#
|
42
|
+
# Find more detailed examples with sample images here on my blog http://EXPRESSICA.com
|
43
|
+
#
|
44
|
+
# All Feedbacks/CommentS/Issues/Queries are welcome.
|
45
|
+
def show_simple_captcha(options={})
|
46
|
+
key = simple_captcha_key(options[:object])
|
47
|
+
options[:field_value] = set_simple_captcha_data(key, options)
|
48
|
+
|
49
|
+
defaults = {
|
50
|
+
:image => simple_captcha_image(key, options),
|
51
|
+
:label => options[:label] || I18n.t('simple_captcha.label'),
|
52
|
+
:field => simple_captcha_field(options)
|
53
|
+
}
|
54
|
+
|
55
|
+
render :partial => 'simple_captcha/simple_captcha', :locals => { :simple_captcha_options => defaults }
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def simple_captcha_image(simple_captcha_key, options = {})
|
61
|
+
defaults = {}
|
62
|
+
defaults[:time] = options[:time] || Time.now.to_i
|
63
|
+
|
64
|
+
query = defaults.collect{ |key, value| "#{key}=#{value}" }.join('&')
|
65
|
+
url = "/simple_captcha?code=#{simple_captcha_key}&#{query}"
|
66
|
+
|
67
|
+
"<img src='#{url}' alt='captcha' />".html_safe
|
68
|
+
end
|
69
|
+
|
70
|
+
def simple_captcha_field(options={})
|
71
|
+
if options[:object]
|
72
|
+
text_field(options[:object], :captcha, :value => '', :autocomplete => 'off') +
|
73
|
+
hidden_field(options[:object], :captcha_key, {:value => options[:field_value]})
|
74
|
+
else
|
75
|
+
text_field_tag(:captcha, nil, :autocomplete => 'off')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_simple_captcha_data(key, options={})
|
80
|
+
code_type = options[:code_type]
|
81
|
+
|
82
|
+
value = generate_simple_captcha_data(code_type)
|
83
|
+
data = SimpleCaptcha::SimpleCaptchaData.get_data(key)
|
84
|
+
data.value = value
|
85
|
+
data.save
|
86
|
+
key
|
87
|
+
end
|
88
|
+
|
89
|
+
def generate_simple_captcha_data(code)
|
90
|
+
value = ''
|
91
|
+
|
92
|
+
case code
|
93
|
+
when 'numeric' then
|
94
|
+
SimpleCaptcha.length.times{value << (48 + rand(10)).chr}
|
95
|
+
else
|
96
|
+
SimpleCaptcha.length.times{value << (65 + rand(26)).chr}
|
97
|
+
end
|
98
|
+
|
99
|
+
return value
|
100
|
+
end
|
101
|
+
|
102
|
+
def simple_captcha_key(key_name = nil)
|
103
|
+
if key_name.nil?
|
104
|
+
session[:captcha] ||= SimpleCaptcha::Utils.generate_key(session[:id].to_s, 'captcha')
|
105
|
+
else
|
106
|
+
SimpleCaptcha::Utils.generate_key(session[:id].to_s, key_name)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SimpleCaptcha
|
4
|
+
autoload :Utils, 'simple_captcha/utils'
|
5
|
+
|
6
|
+
autoload :ImageHelpers, 'simple_captcha/image'
|
7
|
+
autoload :ViewHelper, 'simple_captcha/view'
|
8
|
+
autoload :ControllerHelpers, 'simple_captcha/controller'
|
9
|
+
autoload :ModelHelpers, 'simple_captcha/active_record'
|
10
|
+
|
11
|
+
autoload :FormBuilder, 'simple_captcha/form_builder'
|
12
|
+
autoload :CustomFormBuilder, 'simple_captcha/formtastic'
|
13
|
+
|
14
|
+
autoload :SimpleCaptchaData, 'simple_captcha/simple_captcha_data'
|
15
|
+
autoload :Middleware, 'simple_captcha/middleware'
|
16
|
+
|
17
|
+
mattr_accessor :image_size
|
18
|
+
@@image_size = "100x28"
|
19
|
+
|
20
|
+
mattr_accessor :length
|
21
|
+
@@length = 5
|
22
|
+
|
23
|
+
# 'embosed_silver',
|
24
|
+
# 'simply_red',
|
25
|
+
# 'simply_green',
|
26
|
+
# 'simply_blue',
|
27
|
+
# 'distorted_black',
|
28
|
+
# 'all_black',
|
29
|
+
# 'charcoal_grey',
|
30
|
+
# 'almost_invisible'
|
31
|
+
# 'random'
|
32
|
+
mattr_accessor :image_style
|
33
|
+
@@image_style = 'simply_blue'
|
34
|
+
|
35
|
+
# 'low', 'medium', 'high', 'random'
|
36
|
+
mattr_accessor :distortion
|
37
|
+
@@distortion = 'low'
|
38
|
+
|
39
|
+
# command path
|
40
|
+
mattr_accessor :image_magick_path
|
41
|
+
@@image_magick_path = ''
|
42
|
+
|
43
|
+
# tmp directory
|
44
|
+
mattr_accessor :tmp_path
|
45
|
+
@@tmp_path = nil
|
46
|
+
|
47
|
+
def self.add_image_style(name, params = [])
|
48
|
+
SimpleCaptcha::ImageHelpers.image_styles.update(name.to_s => params)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.setup
|
52
|
+
yield self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
require 'simple_captcha/engine' if defined?(Rails)
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: the_captcha
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ilya N. Zykin
|
14
|
+
- Pavlo Galeta
|
15
|
+
- Igor Galeta
|
16
|
+
autorequire:
|
17
|
+
bindir: bin
|
18
|
+
cert_chain: []
|
19
|
+
|
20
|
+
date: 2012-04-17 00:00:00 +04:00
|
21
|
+
default_executable:
|
22
|
+
dependencies: []
|
23
|
+
|
24
|
+
description: My version of SimpleCaptcha
|
25
|
+
email: galeta.igor@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README.rdoc
|
32
|
+
files:
|
33
|
+
- lib/generators/simple_captcha_generator.rb
|
34
|
+
- lib/generators/templates/migration.rb
|
35
|
+
- lib/generators/templates/partial.erb
|
36
|
+
- lib/generators/USAGE
|
37
|
+
- lib/simple_captcha/active_record.rb
|
38
|
+
- lib/simple_captcha/image.rb
|
39
|
+
- lib/simple_captcha/controller.rb
|
40
|
+
- lib/simple_captcha/form_builder.rb
|
41
|
+
- lib/simple_captcha/utils.rb
|
42
|
+
- lib/simple_captcha/simple_captcha_data.rb
|
43
|
+
- lib/simple_captcha/version.rb
|
44
|
+
- lib/simple_captcha/view.rb
|
45
|
+
- lib/simple_captcha/formtastic.rb
|
46
|
+
- lib/simple_captcha/middleware.rb
|
47
|
+
- lib/simple_captcha/engine.rb
|
48
|
+
- lib/simple_captcha.rb
|
49
|
+
- Rakefile
|
50
|
+
- README.rdoc
|
51
|
+
- test/simple_captcha_test.rb
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/the-teacher/the-captcha
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
hash: 3
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project: the_captcha
|
82
|
+
rubygems_version: 1.6.2
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: My version of SimpleCaptcha
|
86
|
+
test_files:
|
87
|
+
- test/simple_captcha_test.rb
|