glebtv-simple_captcha 0.1.6
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/README.rdoc +221 -0
- data/Rakefile +22 -0
- data/lib/generators/USAGE +4 -0
- data/lib/generators/simple_captcha_generator.rb +14 -0
- data/lib/generators/templates/partial.erb +37 -0
- data/lib/simple_captcha.rb +52 -0
- data/lib/simple_captcha/active_record.rb +72 -0
- data/lib/simple_captcha/controller.rb +29 -0
- data/lib/simple_captcha/engine.rb +24 -0
- data/lib/simple_captcha/form_builder.rb +34 -0
- data/lib/simple_captcha/formtastic.rb +14 -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 +25 -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/test/simple_captcha_test.rb +8 -0
- metadata +81 -0
data/README.rdoc
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
=SimpleCaptcha
|
2
|
+
This is a fork of wolcanus's fork of SimpleCaptcha to support Mongoid 3 and new formtastic.
|
3
|
+
This is a fork of galetahub SimpleCaptcha to support Mongoid.
|
4
|
+
Its implementation requires
|
5
|
+
adding up a single line in views and in controllers/models.
|
6
|
+
SimpleCaptcha is available to be used with Rails 3 or above and also it provides the
|
7
|
+
backward compatibility with previous versions of Rails.
|
8
|
+
|
9
|
+
==Features
|
10
|
+
|
11
|
+
* Zero FileSystem usage(secret code moved to db-store and image storage removed).
|
12
|
+
* Provides various image styles.
|
13
|
+
* Provides three level of complexity of images.
|
14
|
+
* Works absolutely fine in distributed environment(session and db based implementation works fine in distributed environment).
|
15
|
+
* Implementation is as easy as just writing a single line in your view. "<%= show_simple_captcha %>" within the 'form' tags.
|
16
|
+
* Flexible DOM and CSS handling(There is a separate view partial for rednering SimpleCaptcha DOM elements).
|
17
|
+
* Automated removal of 1 hour old unmatched simple_captcha data.
|
18
|
+
|
19
|
+
==Requirements
|
20
|
+
|
21
|
+
* {Ruby}[http://ruby-lang.org/] >= 1.8.7
|
22
|
+
* {Rails}[http://github.com/rails/rails] >= 3
|
23
|
+
* ImageMagick should be installed on your machine to use this plugin.
|
24
|
+
visit http://www.imagemagick.org/script/index.php for more details.
|
25
|
+
|
26
|
+
==Installation
|
27
|
+
|
28
|
+
gem "glebtv-simple_captcha", :require => "simple_captcha"
|
29
|
+
|
30
|
+
or
|
31
|
+
|
32
|
+
gem 'glebtv-simple_captcha', :require => 'simple_captcha', :git => 'git://github.com/glebtv/simple-captcha.git'
|
33
|
+
|
34
|
+
==Setup
|
35
|
+
|
36
|
+
After installation, follow these simple steps to setup the plugin. The setup will depend
|
37
|
+
on the version of rails your application is using.
|
38
|
+
|
39
|
+
rails generate simple_captcha
|
40
|
+
|
41
|
+
==Usage
|
42
|
+
|
43
|
+
===Controller Based
|
44
|
+
|
45
|
+
Add the following line in the file "app/controllers/application.rb"
|
46
|
+
|
47
|
+
ApplicationController < ActionController::Base
|
48
|
+
include SimpleCaptcha::ControllerHelpers
|
49
|
+
end
|
50
|
+
|
51
|
+
In the view file within the form tags add this code
|
52
|
+
|
53
|
+
<%= show_simple_captcha %>
|
54
|
+
|
55
|
+
and in the controller's action authenticate it as
|
56
|
+
|
57
|
+
if simple_captcha_valid?
|
58
|
+
do this
|
59
|
+
else
|
60
|
+
do that
|
61
|
+
end
|
62
|
+
|
63
|
+
===Model Based
|
64
|
+
|
65
|
+
In the view file within the form tags write this code
|
66
|
+
|
67
|
+
<%= show_simple_captcha(:object=>"user") %>
|
68
|
+
|
69
|
+
and in the model class add this code
|
70
|
+
|
71
|
+
class User < ActiveRecord::Basse
|
72
|
+
apply_simple_captcha
|
73
|
+
end
|
74
|
+
|
75
|
+
====FormBuilder helper
|
76
|
+
|
77
|
+
<%= form_for @user do |form| -%>
|
78
|
+
...
|
79
|
+
<%= form.simple_captcha :label => "Enter numbers.." %>
|
80
|
+
...
|
81
|
+
<% end -%>
|
82
|
+
|
83
|
+
====Validating with captcha
|
84
|
+
NOTE: @user.valid? will still work as it should, it will not validate the captcha code.
|
85
|
+
|
86
|
+
@user.valid_with_captcha?
|
87
|
+
|
88
|
+
====Saving with captcha
|
89
|
+
NOTE: @user.save will still work as it should, it will not validate the captcha code.
|
90
|
+
|
91
|
+
@user.save_with_captcha
|
92
|
+
|
93
|
+
===Formtastic integration
|
94
|
+
SimpleCaptcha detects if your use Formtastic and appends "SimpleCaptcha::CustomFormBuilder".
|
95
|
+
|
96
|
+
<%= form.input :captcha, :as => :simple_captcha %>
|
97
|
+
|
98
|
+
==Options & Examples
|
99
|
+
===View Options
|
100
|
+
|
101
|
+
* *label* - provides the custom text b/w the image and the text field, the default is "type the code from the image"
|
102
|
+
|
103
|
+
* *object* - the name of the object of the model class, to implement the model based captcha.
|
104
|
+
|
105
|
+
* *code_type* - return numeric only if set to 'numeric'
|
106
|
+
|
107
|
+
===Global options
|
108
|
+
|
109
|
+
* *image_style* - provides the specific image style for the captcha image.
|
110
|
+
There are eight different styles available with the plugin as...
|
111
|
+
1) simply_blue
|
112
|
+
2) simply_red
|
113
|
+
3) simply_green
|
114
|
+
4) charcoal_grey
|
115
|
+
5) embosed_silver
|
116
|
+
6) all_black
|
117
|
+
7) distorted_black
|
118
|
+
8) almost_invisible
|
119
|
+
Default style is 'simply_blue'.
|
120
|
+
You can also specify 'random' to select the random image style.
|
121
|
+
|
122
|
+
* *distortion* - handles the complexity of the image. The :distortion can be set to 'low', 'medium' or 'high'. Default is 'low'.
|
123
|
+
|
124
|
+
Create "rails_root/config/initializers/simple_captcha.rb"
|
125
|
+
|
126
|
+
SimpleCaptcha.setup do |sc|
|
127
|
+
# default: 100x28
|
128
|
+
sc.image_size = '120x40'
|
129
|
+
|
130
|
+
# default: 5
|
131
|
+
sc.length = 6
|
132
|
+
|
133
|
+
# default: simply_blue
|
134
|
+
# possible values:
|
135
|
+
# 'embosed_silver',
|
136
|
+
# 'simply_red',
|
137
|
+
# 'simply_green',
|
138
|
+
# 'simply_blue',
|
139
|
+
# 'distorted_black',
|
140
|
+
# 'all_black',
|
141
|
+
# 'charcoal_grey',
|
142
|
+
# 'almost_invisible'
|
143
|
+
# 'random'
|
144
|
+
sc.image_style = 'simply_green'
|
145
|
+
|
146
|
+
# default: low
|
147
|
+
# possible values: 'low', 'medium', 'high', 'random'
|
148
|
+
sc.distortion = 'medium'
|
149
|
+
end
|
150
|
+
|
151
|
+
You can add your own style:
|
152
|
+
|
153
|
+
SimpleCaptcha.setup do |sc|
|
154
|
+
sc.image_style = 'mycaptha'
|
155
|
+
sc.add_image_style('mycaptha', [
|
156
|
+
"-background '#F4F7F8'",
|
157
|
+
"-fill '#86818B'",
|
158
|
+
"-border 1",
|
159
|
+
"-bordercolor '#E0E2E3'"])
|
160
|
+
end
|
161
|
+
|
162
|
+
You can provide the path where image_magick is installed as well:
|
163
|
+
|
164
|
+
SimpleCaptcha.setup do |sc|
|
165
|
+
sc.image_magick_path = '/usr/bin' # you can check this from console by running: which convert
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
===How to change the CSS for SimpleCaptcha DOM elements?
|
170
|
+
You can change the CSS of the SimpleCaptcha DOM elements as per your need in this file.
|
171
|
+
/app/views/simple_captcha/_simple_captcha.erb
|
172
|
+
|
173
|
+
===View's Examples
|
174
|
+
====Controller Based Example
|
175
|
+
|
176
|
+
<%= show_simple_captcha %>
|
177
|
+
|
178
|
+
<%= show_simple_captcha(:label => "human authentication") %>
|
179
|
+
|
180
|
+
====Model Based Example
|
181
|
+
|
182
|
+
<%= show_simple_captcha(:object => 'user', :label => "human authentication") %>
|
183
|
+
|
184
|
+
====Model Options
|
185
|
+
|
186
|
+
* *message* - provides the custom message on failure of captcha authentication the default is "Secret Code did not match with the Image"
|
187
|
+
|
188
|
+
* *add_to_base* - if set to true, appends the error message to the base.
|
189
|
+
|
190
|
+
=====Model's Example
|
191
|
+
|
192
|
+
class User < ActiveRecord::Base
|
193
|
+
apply_simple_captcha
|
194
|
+
end
|
195
|
+
|
196
|
+
class User < ActiveRecord::Base
|
197
|
+
apply_simple_captcha :message => "The secret Image and code were different", :add_to_base => true
|
198
|
+
end
|
199
|
+
|
200
|
+
==I18n
|
201
|
+
|
202
|
+
simple_captcha:
|
203
|
+
message:
|
204
|
+
default: "Secret Code did not match with the Image"
|
205
|
+
user: "The secret Image and code were different"
|
206
|
+
|
207
|
+
==The Original Author
|
208
|
+
|
209
|
+
Enjoy the simplest captcha implementation.
|
210
|
+
|
211
|
+
Author: Sur
|
212
|
+
|
213
|
+
Blog: http://expressica.com
|
214
|
+
|
215
|
+
Contact: sur.max@gmail.com
|
216
|
+
|
217
|
+
Plugin Homepage: http://expressica.com/simple_captcha
|
218
|
+
|
219
|
+
Plugin update for rails 3: http://github.com/galetahub
|
220
|
+
|
221
|
+
Any feedback/comment/issue/donation is welcome!
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
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,14 @@
|
|
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 create_partial
|
11
|
+
template "partial.erb", File.join('app/views', 'simple_captcha', "_simple_captcha.erb")
|
12
|
+
end
|
13
|
+
|
14
|
+
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,52 @@
|
|
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
|
+
def self.add_image_style(name, params = [])
|
44
|
+
SimpleCaptcha::ImageHelpers.image_styles.update(name.to_s => params)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.setup
|
48
|
+
yield self
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
require 'simple_captcha/engine' if defined?(Rails)
|
@@ -0,0 +1,72 @@
|
|
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
|
+
if captcha && captcha.upcase.delete(" ") == SimpleCaptcha::Utils::simple_captcha_value(captcha_key)
|
58
|
+
SimpleCaptcha::Utils::simple_captcha_passed!(captcha_key)
|
59
|
+
return true
|
60
|
+
else
|
61
|
+
message = simple_captcha_options[:message] || I18n.t(self.class.model_name.downcase, :scope => [:simple_captcha, :message], :default => :default)
|
62
|
+
simple_captcha_options[:add_to_base] ? errors.add_to_base(message) : errors.add(:captcha, message)
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def save_with_captcha
|
68
|
+
valid_with_captcha? && save(:validate => false)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
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,24 @@
|
|
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") && Formtastic.const_defined?("Inputs")
|
18
|
+
require "simple_captcha/formtastic"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
config.app_middleware.use SimpleCaptcha::Middleware
|
23
|
+
end
|
24
|
+
end
|
@@ -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,14 @@
|
|
1
|
+
require "formtastic"
|
2
|
+
|
3
|
+
class SimpleCaptchaInput
|
4
|
+
include ::Formtastic::Inputs::Base
|
5
|
+
include ::Formtastic::Inputs::Base::Stringish
|
6
|
+
|
7
|
+
def to_html
|
8
|
+
input_wrapping do
|
9
|
+
input_html_options.update :object => method
|
10
|
+
label_html << builder.show_simple_captcha(input_html_options)
|
11
|
+
# label_html << builder.text_field(method, input_html_options)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
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 = RUBY_VERSION < '1.9' ? Tempfile.new('simple_captcha.jpg') : Tempfile.new(['simple_captcha', '.jpg'])
|
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,25 @@
|
|
1
|
+
module SimpleCaptcha
|
2
|
+
class SimpleCaptchaData
|
3
|
+
include Mongoid::Document
|
4
|
+
|
5
|
+
field :key, :type => String
|
6
|
+
field :value, :type => String
|
7
|
+
field :created_at, :type => Time, default: -> { Time.now }
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def get_data(key)
|
11
|
+
data = SimpleCaptchaData.where(:key => key).first || new(:key => key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def remove_data(key)
|
15
|
+
SimpleCaptchaData.where(:key => key).first.delete
|
16
|
+
clear_old_data(1.hour.ago)
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_old_data(time = 1.hour.ago)
|
20
|
+
return unless Time === time
|
21
|
+
SimpleCaptchaData.where(:updated_at.lt => time.utc).delete_all
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glebtv-simple_captcha
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.6
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Weverton do Couto Timoteo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mongoid
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
30
|
+
description: .
|
31
|
+
email: weverton@wolcan.us
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files:
|
35
|
+
- README.rdoc
|
36
|
+
files:
|
37
|
+
- lib/generators/templates/partial.erb
|
38
|
+
- lib/generators/simple_captcha_generator.rb
|
39
|
+
- lib/generators/USAGE
|
40
|
+
- lib/simple_captcha/active_record.rb
|
41
|
+
- lib/simple_captcha/version.rb
|
42
|
+
- lib/simple_captcha/view.rb
|
43
|
+
- lib/simple_captcha/utils.rb
|
44
|
+
- lib/simple_captcha/controller.rb
|
45
|
+
- lib/simple_captcha/formtastic.rb
|
46
|
+
- lib/simple_captcha/engine.rb
|
47
|
+
- lib/simple_captcha/form_builder.rb
|
48
|
+
- lib/simple_captcha/middleware.rb
|
49
|
+
- lib/simple_captcha/image.rb
|
50
|
+
- lib/simple_captcha/simple_captcha_data.rb
|
51
|
+
- lib/simple_captcha.rb
|
52
|
+
- Rakefile
|
53
|
+
- README.rdoc
|
54
|
+
- test/simple_captcha_test.rb
|
55
|
+
homepage: http://github.com/glebtv/simple-captcha
|
56
|
+
licenses: []
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
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
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.8.22
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: A fork of a wolcanus fork of galetahub SimpleCaptcha for mongoid support.
|
79
|
+
test_files:
|
80
|
+
- test/simple_captcha_test.rb
|
81
|
+
has_rdoc:
|