captcher 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +210 -0
- data/Rakefile +22 -0
- data/app/controllers/captcher/captchas_controller.rb +22 -0
- data/app/controllers/concerns/captcher/captcha_aware.rb +30 -0
- data/app/helpers/captcher/application_helper.rb +13 -0
- data/app/views/layouts/captcher/application.html.erb +16 -0
- data/config/routes.rb +10 -0
- data/lib/captcher.rb +57 -0
- data/lib/captcher/base_captcha.rb +46 -0
- data/lib/captcher/captchas/awesome_captcha.rb +7 -0
- data/lib/captcher/captchas/code_captcha.rb +40 -0
- data/lib/captcher/captchas/math_captcha.rb +7 -0
- data/lib/captcher/config.rb +41 -0
- data/lib/captcher/engine.rb +5 -0
- data/lib/captcher/text_image.rb +48 -0
- data/lib/captcher/version.rb +3 -0
- data/lib/fonts/Bangers-Regular.ttf +0 -0
- data/lib/fonts/CarterOne.ttf +0 -0
- data/lib/fonts/FrederickatheGreat-Regular.ttf +0 -0
- data/lib/fonts/IndieFlower-Regular.ttf +0 -0
- data/lib/fonts/LobsterTwo-BoldItalic.ttf +0 -0
- data/lib/fonts/SigmarOne-Regular.ttf +0 -0
- data/lib/tasks/captcher_tasks.rake +4 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +4 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/javascripts/cable.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/jobs/application_job.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +15 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +36 -0
- data/spec/dummy/bin/update +31 -0
- data/spec/dummy/bin/yarn +11 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +30 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +61 -0
- data/spec/dummy/config/environments/production.rb +94 -0
- data/spec/dummy/config/environments/test.rb +46 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/assets.rb +14 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/puma.rb +34 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +6608 -0
- data/spec/dummy/log/test.log +6492 -0
- data/spec/dummy/package.json +5 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/development_secret.txt +1 -0
- data/spec/helpers.rb +23 -0
- data/spec/lib/captcher/config_spec.rb +41 -0
- data/spec/models/captchas/code_captcha_spec.rb +45 -0
- data/spec/rails_helper.rb +72 -0
- data/spec/requests/captcha_management_spec.rb +48 -0
- data/spec/spec_helper.rb +96 -0
- data/spec/tmp/test.png +0 -0
- metadata +291 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 42a4bd27e904e52012256226988e854b5d21cf73a69af147f3407de4cd3e8965
|
4
|
+
data.tar.gz: 8effe1d5469292eece64a258f89dd604a2c0389473af70dd1553e80d820ae052
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 117d2b310d1ec56e1474f92c5a28ab09340df48e53e6514581f35febfe7e63ad2a6d9c5b767a9224a3209678eb90dd648d686c4c9412bbd93957cf82a0e566fd
|
7
|
+
data.tar.gz: c7a699acdf006c866d389a28caf0143db664919a1811fc039c1f79c54502ffc2c00c569e82bdbe741218af43ee338b132a2f5f8a4b393072b432c80a7ba072bc
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2019 Ivan Zinovyev
|
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
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
# Captcher
|
2
|
+
|
3
|
+
Easy to use classical captcha for Rails apps
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
|
14
|
+
gem 'captcher'
|
15
|
+
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
```
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
```bash
|
29
|
+
|
30
|
+
$ gem install captcher
|
31
|
+
|
32
|
+
```
|
33
|
+
|
34
|
+
Mount the engine inside your application by adding this line to your application's routes file at `config/routes.rb`:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
|
38
|
+
mount Captcher::Engine => "/captcher"
|
39
|
+
|
40
|
+
```
|
41
|
+
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
### Render on page
|
46
|
+
|
47
|
+
1. Include the concern with helper methods to your ApplicationController:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
|
51
|
+
class ApplicationController < ActionController::Base
|
52
|
+
include Captcher::CaptchaAware
|
53
|
+
end
|
54
|
+
|
55
|
+
```
|
56
|
+
|
57
|
+
2. Use helper methods in your controller:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
|
61
|
+
class MyController < ApplicationController
|
62
|
+
def index
|
63
|
+
reload_captcha(session) # Reload the captcha
|
64
|
+
# render response with success code ...
|
65
|
+
end
|
66
|
+
|
67
|
+
def create
|
68
|
+
@comment = Comment.new(comment_params)
|
69
|
+
captcha_check = confirm_captcha?(session, params[:captcha])
|
70
|
+
if @comment.valid? && captcha_check && @comment.save
|
71
|
+
# render response with success code ...
|
72
|
+
else
|
73
|
+
@comment.errors[:captcha] << "Captcha verification failed" unless captcha_check
|
74
|
+
# render response with error code ...
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# ... some other code
|
79
|
+
end
|
80
|
+
|
81
|
+
```
|
82
|
+
|
83
|
+
3. An example bootstrap-based html/erb code:
|
84
|
+
|
85
|
+
|
86
|
+
```html
|
87
|
+
|
88
|
+
<%= simple_form_for(some_form) do |f| %>
|
89
|
+
<!-- Some html/erb code for all form fields -->
|
90
|
+
<!-- ... -->
|
91
|
+
<!-- /Some html/erb code for all form fields -->
|
92
|
+
|
93
|
+
<div class="input-group">
|
94
|
+
<%= text_field_tag :captcha, "",
|
95
|
+
type: :text,
|
96
|
+
label: false,
|
97
|
+
class: "form-control",
|
98
|
+
placeholder: "Enter the captcha" %>
|
99
|
+
|
100
|
+
<div class="input-group-append">
|
101
|
+
<div class="input-group-text" style="padding: 0">
|
102
|
+
<%= image_tag(captcher.captcha_path(format: :png), style: "height: 35px;",
|
103
|
+
id: "captcha-image") %>
|
104
|
+
</div>
|
105
|
+
<button class="btn btn-outline-secondary" type="button" id="captcha-reload">
|
106
|
+
<i class="fa fa-refresh"></i>
|
107
|
+
</button>
|
108
|
+
</div>
|
109
|
+
</div>
|
110
|
+
|
111
|
+
<% end %>
|
112
|
+
|
113
|
+
```
|
114
|
+
|
115
|
+
4. Javascript code to refresh the capture:
|
116
|
+
|
117
|
+
|
118
|
+
```javascript
|
119
|
+
|
120
|
+
function reloadCaptcha() {
|
121
|
+
$.ajax({
|
122
|
+
type: 'GET',
|
123
|
+
url: '/captcher/captcha/reload.png',
|
124
|
+
success: function() {
|
125
|
+
var timestamp = (new Date()).getTime();
|
126
|
+
$('#captcha-image').attr("src", "/captcher/captcha.png?" + timestamp);
|
127
|
+
},
|
128
|
+
});
|
129
|
+
}
|
130
|
+
|
131
|
+
$('#captcha-reload').click(function() {
|
132
|
+
reloadCaptcha();
|
133
|
+
});
|
134
|
+
|
135
|
+
```
|
136
|
+
|
137
|
+
|
138
|
+
### API endpoints
|
139
|
+
|
140
|
+
These endpoints are available by default (as soon as you've mounted the `Captcher` engine to your `routes.rb` file) and can be used for some async requests:
|
141
|
+
|
142
|
+
* `http://your-application.com/captcher/captcha` - Load the captcha image
|
143
|
+
|
144
|
+
* `http://your-application.com/captcher/captcha/reload` - Reload the captcha
|
145
|
+
|
146
|
+
* `http://your-application.com/captcher/captcha/confirm?confirmation=code` - Confirm captcha code
|
147
|
+
|
148
|
+
|
149
|
+
## Configuration
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
|
153
|
+
# config/initialiers/captcher.rb
|
154
|
+
|
155
|
+
Captcher.configure do |c|
|
156
|
+
c.mode = :code_captcha
|
157
|
+
|
158
|
+
c.code_captcha do |cc|
|
159
|
+
cc.fonts Dir[Captcher::Engine.root.join("lib/fonts/**")]
|
160
|
+
cc.font_size 50
|
161
|
+
cc.font_color "black"
|
162
|
+
cc.count 5
|
163
|
+
cc.background "#999999"
|
164
|
+
cc.format "png"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
```
|
169
|
+
|
170
|
+
|
171
|
+
## TODO
|
172
|
+
|
173
|
+
1. Implement some other types of captcha
|
174
|
+
|
175
|
+
2. Integrate with Travis to test the gem against different versions of Ruby/ROR
|
176
|
+
|
177
|
+
3. Improve code style
|
178
|
+
|
179
|
+
4. Improve documentation
|
180
|
+
|
181
|
+
|
182
|
+
## Contributing
|
183
|
+
|
184
|
+
Contribution directions go here.
|
185
|
+
|
186
|
+
|
187
|
+
## Fonts
|
188
|
+
|
189
|
+
The fonts wich are shiped by default with this repo
|
190
|
+
are taken from https://github.com/google/fonts
|
191
|
+
and use the SIL Open Font License, v1.1
|
192
|
+
|
193
|
+
**There's a list of the origin paths of the fonts**:
|
194
|
+
|
195
|
+
* https://github.com/google/fonts/tree/master/ofl/bangers
|
196
|
+
|
197
|
+
* https://github.com/google/fonts/tree/master/ofl/carterone
|
198
|
+
|
199
|
+
* https://github.com/google/fonts/tree/master/ofl/frederickathegreat
|
200
|
+
|
201
|
+
* https://github.com/google/fonts/tree/master/ofl/indieflower
|
202
|
+
|
203
|
+
* https://github.com/google/fonts/tree/master/ofl/lobstertwo
|
204
|
+
|
205
|
+
* https://github.com/google/fonts/tree/master/ofl/sigmarone
|
206
|
+
|
207
|
+
|
208
|
+
## License
|
209
|
+
|
210
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Captcher'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Captcher
|
2
|
+
class CaptchasController < ActionController::Base
|
3
|
+
include Captcher::CaptchaAware
|
4
|
+
|
5
|
+
def show
|
6
|
+
render_captcha(load_captcha(session))
|
7
|
+
end
|
8
|
+
|
9
|
+
def reload
|
10
|
+
render_captcha(reload_captcha(session))
|
11
|
+
end
|
12
|
+
alias refresh reload
|
13
|
+
|
14
|
+
def confirm
|
15
|
+
if confirm_captcha?(session, params[:confirmation])
|
16
|
+
render json: { success: true }, status: 200
|
17
|
+
else
|
18
|
+
render json: { success: false }, status: 422
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Captcher
|
2
|
+
module CaptchaAware
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def load_captcha(session)
|
6
|
+
Captcher.captcha_class.restore_or_create(Captcher.config, session)
|
7
|
+
end
|
8
|
+
|
9
|
+
def reload_captcha(session)
|
10
|
+
captcha = Captcher.captcha_class.new(config: Captcher.config)
|
11
|
+
captcha.store(session)
|
12
|
+
captcha
|
13
|
+
end
|
14
|
+
|
15
|
+
def confirm_captcha(session, confirmation)
|
16
|
+
captcha = load_captcha(session)
|
17
|
+
captcha.validate(confirmation)
|
18
|
+
end
|
19
|
+
alias confirm_captcha? confirm_captcha
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def render_captcha(captcha)
|
24
|
+
format = params[:format] || captcha.own_config[:format]
|
25
|
+
filename = "captcha.#{format}"
|
26
|
+
type = "image/#{format}"
|
27
|
+
send_data captcha.represent, filename: filename, type: type, disposition: :inline
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Captcher
|
2
|
+
module ApplicationHelper
|
3
|
+
def captcha_tag(options)
|
4
|
+
options = options.symbolize_keys
|
5
|
+
|
6
|
+
src = options[:src] = captcha_path
|
7
|
+
|
8
|
+
options[:alt] = options.fetch(:alt) { image_alt(src) }
|
9
|
+
options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
|
10
|
+
tag("img", options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Captcher</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
|
8
|
+
<%= stylesheet_link_tag "captcher/application", media: "all" %>
|
9
|
+
<%= javascript_include_tag "captcher/application" %>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
|
13
|
+
<%= yield %>
|
14
|
+
|
15
|
+
</body>
|
16
|
+
</html>
|
data/config/routes.rb
ADDED
data/lib/captcher.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "mini_magick"
|
2
|
+
require "captcher/engine"
|
3
|
+
require "captcher/config"
|
4
|
+
require "captcher/text_image"
|
5
|
+
require "captcher/base_captcha"
|
6
|
+
require "captcher/captchas/awesome_captcha"
|
7
|
+
require "captcher/captchas/math_captcha"
|
8
|
+
require "captcher/captchas/code_captcha"
|
9
|
+
require "pry" if Rails.env.in?(%w[development test])
|
10
|
+
|
11
|
+
module Captcher
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def configure
|
15
|
+
@config = Captcher::Config.new
|
16
|
+
yield(@config)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def config
|
21
|
+
default_config.merge(@config)
|
22
|
+
end
|
23
|
+
|
24
|
+
def captcha_class
|
25
|
+
return @captcha_class if @captcha_class
|
26
|
+
|
27
|
+
klass = Captcher.config[:mode].to_s.camelize
|
28
|
+
@captcha_class = "Captcher::Captchas::#{klass}".constantize
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# rubocop:disable Metrics/MethodLength
|
34
|
+
def default_config
|
35
|
+
@default_config ||= Captcher::Config.new do |c|
|
36
|
+
c.mode = :code_captcha
|
37
|
+
|
38
|
+
c.code_captcha do |cc|
|
39
|
+
cc.fonts Dir[Captcher::Engine.root.join("lib/fonts/**")]
|
40
|
+
cc.font_size 50
|
41
|
+
cc.font_color "black"
|
42
|
+
cc.count 5
|
43
|
+
cc.background "#999999"
|
44
|
+
cc.format "png"
|
45
|
+
end
|
46
|
+
|
47
|
+
c.math_captcha do |mc|
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
c.awesome_captcha do |ac|
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# rubocop:enable Metrics/MethodLength
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Captcher
|
2
|
+
class BaseCaptcha
|
3
|
+
SESSION_KEY = "captcha_state".freeze
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
def restore(session)
|
9
|
+
state = session[SESSION_KEY]
|
10
|
+
new(state) if state
|
11
|
+
end
|
12
|
+
|
13
|
+
def restore_or_create(config, session)
|
14
|
+
restore(session) || new(config: config).store(session)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :config, :payload
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
options = options.with_indifferent_access
|
22
|
+
@config = options[:config] if options[:config]
|
23
|
+
@payload = options[:payload] if options[:payload]
|
24
|
+
after_initialize
|
25
|
+
end
|
26
|
+
|
27
|
+
def after_initialize; end
|
28
|
+
|
29
|
+
def store(session)
|
30
|
+
session[SESSION_KEY] = { payload: payload, config: config }
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def own_config
|
35
|
+
@own_config ||= @config[self.class.name.to_sym]
|
36
|
+
end
|
37
|
+
|
38
|
+
def represent(format = :html, options = {})
|
39
|
+
raise NotImplementedError
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate(confirmation)
|
43
|
+
raise NotImplementedError
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|