rucaptcha 2.6.1 → 3.0.0.beta1
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 +4 -4
- data/README.md +3 -9
- data/Rakefile +34 -0
- data/ext/rucaptcha/Cargo.lock +1226 -0
- data/ext/rucaptcha/Cargo.toml +14 -0
- data/ext/rucaptcha/extconf.rb +3 -1
- data/ext/rucaptcha/src/captcha.rs +250 -0
- data/ext/rucaptcha/src/lib.rs +18 -0
- data/lib/rucaptcha/configuration.rb +2 -6
- data/lib/rucaptcha/version.rb +1 -1
- data/lib/rucaptcha/view_helpers.rb +2 -2
- data/lib/rucaptcha.rb +16 -12
- metadata +18 -24
- data/CHANGELOG.md +0 -93
- data/app/controllers/ru_captcha/captcha_controller.rb +0 -13
- data/config/locales/rucaptcha.en.yml +0 -3
- data/config/locales/rucaptcha.pt-BR.yml +0 -3
- data/config/locales/rucaptcha.zh-CN.yml +0 -3
- data/config/locales/rucaptcha.zh-TW.yml +0 -3
- data/config/routes.rb +0 -3
- data/ext/rucaptcha/colors.h +0 -365
- data/ext/rucaptcha/font.h +0 -27
- data/ext/rucaptcha/rucaptcha.c +0 -301
data/ext/rucaptcha/extconf.rb
CHANGED
@@ -0,0 +1,250 @@
|
|
1
|
+
use image::{ImageBuffer, Rgb};
|
2
|
+
use imageproc::drawing::{draw_cubic_bezier_curve_mut, draw_hollow_ellipse_mut, draw_text_mut};
|
3
|
+
use imageproc::noise::{gaussian_noise_mut, salt_and_pepper_noise_mut};
|
4
|
+
use rand::{thread_rng, Rng};
|
5
|
+
use rusttype::{Font, Scale};
|
6
|
+
use std::io::Cursor;
|
7
|
+
|
8
|
+
static BASIC_CHAR: [char; 54] = [
|
9
|
+
'2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M',
|
10
|
+
'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
11
|
+
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
12
|
+
];
|
13
|
+
|
14
|
+
static FONT_BYTES1: &[u8; 145008] = include_bytes!("../fonts/FuzzyBubbles-Regular.ttf");
|
15
|
+
static FONT_BYTES2: &[u8; 37792] = include_bytes!("../fonts/Handlee-Regular.ttf");
|
16
|
+
|
17
|
+
static COLORS: [(u8, u8, u8); 10] = [
|
18
|
+
(204, 11, 143),
|
19
|
+
(124, 10, 190),
|
20
|
+
(87, 0, 200),
|
21
|
+
(61, 86, 168),
|
22
|
+
(63, 166, 126),
|
23
|
+
(69, 187, 48),
|
24
|
+
(105, 208, 3),
|
25
|
+
(160, 208, 3),
|
26
|
+
(216, 219, 2),
|
27
|
+
(50, 50, 50),
|
28
|
+
];
|
29
|
+
|
30
|
+
static SCALE_SM: u32 = 32;
|
31
|
+
static SCALE_MD: u32 = 45;
|
32
|
+
static SCALE_LG: u32 = 55;
|
33
|
+
|
34
|
+
fn rand_num(len: usize) -> usize {
|
35
|
+
let mut rng = thread_rng();
|
36
|
+
rng.gen_range(0..=len)
|
37
|
+
}
|
38
|
+
|
39
|
+
fn get_captcha(len: usize) -> Vec<String> {
|
40
|
+
let mut res = vec![];
|
41
|
+
for _ in 0..len {
|
42
|
+
let rnd = rand_num(53);
|
43
|
+
res.push(BASIC_CHAR[rnd].to_string())
|
44
|
+
}
|
45
|
+
res
|
46
|
+
}
|
47
|
+
|
48
|
+
#[allow(unused)]
|
49
|
+
fn get_color() -> Rgb<u8> {
|
50
|
+
let rnd = rand_num(COLORS.len());
|
51
|
+
let c = COLORS[rnd];
|
52
|
+
Rgb([c.0, c.1, c.2])
|
53
|
+
}
|
54
|
+
|
55
|
+
fn get_colors(num: usize) -> Vec<Rgb<u8>> {
|
56
|
+
let rnd = rand_num(COLORS.len());
|
57
|
+
let mut out = vec![];
|
58
|
+
for i in 0..num {
|
59
|
+
let c = COLORS[(rnd + i) % COLORS.len()];
|
60
|
+
out.push(Rgb([c.0, c.1, c.2]))
|
61
|
+
}
|
62
|
+
|
63
|
+
out
|
64
|
+
}
|
65
|
+
|
66
|
+
fn get_next(min: f32, max: u32) -> f32 {
|
67
|
+
min + rand_num(max as usize - min as usize) as f32
|
68
|
+
}
|
69
|
+
|
70
|
+
fn get_font() -> Font<'static> {
|
71
|
+
match rand_num(2) {
|
72
|
+
0 => Font::try_from_bytes(FONT_BYTES1).unwrap(),
|
73
|
+
1 => Font::try_from_bytes(FONT_BYTES2).unwrap(),
|
74
|
+
_ => Font::try_from_bytes(FONT_BYTES1).unwrap(),
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
fn get_image(width: usize, height: usize) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
|
79
|
+
ImageBuffer::from_fn(width as u32, height as u32, |_, _| {
|
80
|
+
image::Rgb([255, 255, 255])
|
81
|
+
})
|
82
|
+
}
|
83
|
+
|
84
|
+
fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>) {
|
85
|
+
let c = (image.width() - 20) / res.len() as u32;
|
86
|
+
let y = image.height() / 3 - 15;
|
87
|
+
|
88
|
+
let h = image.height() as f32;
|
89
|
+
|
90
|
+
let scale = match res.len() {
|
91
|
+
1..=3 => SCALE_LG,
|
92
|
+
4..=5 => SCALE_MD,
|
93
|
+
_ => SCALE_SM,
|
94
|
+
} as f32;
|
95
|
+
|
96
|
+
let colors = get_colors(res.len());
|
97
|
+
|
98
|
+
let xscale = scale - rand_num((scale * 0.2) as usize) as f32;
|
99
|
+
let yscale = h as f32 - rand_num((h * 0.2) as usize) as f32;
|
100
|
+
|
101
|
+
for (i, _) in res.iter().enumerate() {
|
102
|
+
let text = &res[i];
|
103
|
+
|
104
|
+
let color = colors[i];
|
105
|
+
let font = get_font();
|
106
|
+
let line_color = colors[rand_num(colors.len() - 1)];
|
107
|
+
|
108
|
+
for j in 0..(rand_num(2) + 1) as i32 {
|
109
|
+
let offset = j * (rand_num(3) as i32 + 1);
|
110
|
+
draw_text_mut(
|
111
|
+
image,
|
112
|
+
color,
|
113
|
+
10 + offset + (i as u32 * c) as i32,
|
114
|
+
y as i32 as i32,
|
115
|
+
Scale {
|
116
|
+
x: xscale + offset as f32,
|
117
|
+
y: yscale as f32,
|
118
|
+
},
|
119
|
+
&font,
|
120
|
+
text,
|
121
|
+
);
|
122
|
+
}
|
123
|
+
|
124
|
+
draw_interference_line(1, image, line_color);
|
125
|
+
draw_interference_ellipse(1, image, line_color);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>, color: Rgb<u8>) {
|
130
|
+
for _ in 0..num {
|
131
|
+
let width = image.width();
|
132
|
+
let height = image.height();
|
133
|
+
let x1: f32 = 5.0;
|
134
|
+
let y1 = get_next(x1, height / 2);
|
135
|
+
|
136
|
+
let x2 = (width - 5) as f32;
|
137
|
+
let y2 = get_next(5.0, height - 5);
|
138
|
+
|
139
|
+
let ctrl_x = get_next((width / 6) as f32, width / 4 * 3);
|
140
|
+
let ctrl_y = get_next(x1, height - 5);
|
141
|
+
|
142
|
+
let ctrl_x2 = get_next((width / 4) as f32, width / 4 * 3);
|
143
|
+
let ctrl_y2 = get_next(x1, height - 5);
|
144
|
+
// Randomly draw bezier curves
|
145
|
+
draw_cubic_bezier_curve_mut(
|
146
|
+
image,
|
147
|
+
(x1, y1),
|
148
|
+
(x2, y2),
|
149
|
+
(ctrl_x, ctrl_y),
|
150
|
+
(ctrl_x2, ctrl_y2),
|
151
|
+
color,
|
152
|
+
);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
fn draw_interference_ellipse(
|
157
|
+
num: usize,
|
158
|
+
image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
|
159
|
+
color: Rgb<u8>,
|
160
|
+
) {
|
161
|
+
for _ in 0..num {
|
162
|
+
let w = (10 + rand_num(10)) as i32;
|
163
|
+
let x = rand_num((image.width() - 25) as usize) as i32;
|
164
|
+
let y = rand_num((image.height() - 15) as usize) as i32;
|
165
|
+
draw_hollow_ellipse_mut(image, (x, y), w, w, color);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
pub struct Captcha {
|
170
|
+
pub text: String,
|
171
|
+
pub image: Vec<u8>,
|
172
|
+
}
|
173
|
+
|
174
|
+
pub struct CaptchaBuilder {
|
175
|
+
length: usize,
|
176
|
+
width: usize,
|
177
|
+
height: usize,
|
178
|
+
complexity: usize,
|
179
|
+
}
|
180
|
+
|
181
|
+
impl CaptchaBuilder {
|
182
|
+
pub fn new() -> Self {
|
183
|
+
CaptchaBuilder {
|
184
|
+
length: 4,
|
185
|
+
width: 240,
|
186
|
+
height: 64,
|
187
|
+
complexity: 5,
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
pub fn length(mut self, length: usize) -> Self {
|
192
|
+
self.length = length;
|
193
|
+
self
|
194
|
+
}
|
195
|
+
|
196
|
+
// pub fn width(mut self, width: usize) -> Self {
|
197
|
+
// self.width = width;
|
198
|
+
// self
|
199
|
+
// }
|
200
|
+
|
201
|
+
// pub fn height(mut self, height: usize) -> Self {
|
202
|
+
// self.height = height;
|
203
|
+
// self
|
204
|
+
// }
|
205
|
+
|
206
|
+
pub fn complexity(mut self, complexity: usize) -> Self {
|
207
|
+
let mut complexity = complexity;
|
208
|
+
if complexity > 10 {
|
209
|
+
complexity = 10;
|
210
|
+
}
|
211
|
+
if complexity < 1 {
|
212
|
+
complexity = 1;
|
213
|
+
}
|
214
|
+
self.complexity = complexity;
|
215
|
+
self
|
216
|
+
}
|
217
|
+
|
218
|
+
pub fn build(self) -> Captcha {
|
219
|
+
// Generate an array of captcha characters
|
220
|
+
let res = get_captcha(self.length);
|
221
|
+
|
222
|
+
let text = res.join("");
|
223
|
+
|
224
|
+
// Create a white background image
|
225
|
+
let mut image = get_image(self.width, self.height);
|
226
|
+
|
227
|
+
// Loop to write the verification code string into the background image
|
228
|
+
cyclic_write_character(&res, &mut image);
|
229
|
+
|
230
|
+
gaussian_noise_mut(
|
231
|
+
&mut image,
|
232
|
+
(self.complexity - 1) as f64,
|
233
|
+
((10 * self.complexity) - 10) as f64,
|
234
|
+
((5 * self.complexity) - 5) as u64,
|
235
|
+
);
|
236
|
+
|
237
|
+
salt_and_pepper_noise_mut(
|
238
|
+
&mut image,
|
239
|
+
((0.001 * self.complexity as f64) - 0.001) as f64,
|
240
|
+
(0.8 * self.complexity as f64) as u64,
|
241
|
+
);
|
242
|
+
|
243
|
+
let mut bytes: Vec<u8> = Vec::new();
|
244
|
+
image
|
245
|
+
.write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)
|
246
|
+
.unwrap();
|
247
|
+
|
248
|
+
Captcha { text, image: bytes }
|
249
|
+
}
|
250
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
use magnus::{define_class, function, Error, Object};
|
2
|
+
|
3
|
+
mod captcha;
|
4
|
+
|
5
|
+
pub fn create(len: usize, difficulty: usize) -> (String, Vec<u8>) {
|
6
|
+
let c = captcha::CaptchaBuilder::new();
|
7
|
+
let out = c.complexity(difficulty).length(len).build();
|
8
|
+
|
9
|
+
(out.text, out.image)
|
10
|
+
}
|
11
|
+
|
12
|
+
#[magnus::init]
|
13
|
+
fn init() -> Result<(), Error> {
|
14
|
+
let class = define_class("RuCaptchaCore", Default::default())?;
|
15
|
+
class.define_singleton_method("create", function!(create, 2))?;
|
16
|
+
|
17
|
+
Ok(())
|
18
|
+
}
|
@@ -5,14 +5,10 @@ module RuCaptcha
|
|
5
5
|
attr_accessor :cache_store
|
6
6
|
# rucaptcha expire time, default 2 minutes
|
7
7
|
attr_accessor :expires_in
|
8
|
-
# Color style, default: :colorful, allows: [:colorful, :black_white]
|
9
|
-
attr_accessor :style
|
10
8
|
# Chars length: default 5, allows: [3..7]
|
11
9
|
attr_accessor :length
|
12
|
-
#
|
13
|
-
attr_accessor :
|
14
|
-
# outline style for hard mode, default: false
|
15
|
-
attr_accessor :outline
|
10
|
+
# Hard mode, default: 5, allows: [1..10]
|
11
|
+
attr_accessor :difficulty
|
16
12
|
# skip_cache_store_check, default: false
|
17
13
|
attr_accessor :skip_cache_store_check
|
18
14
|
end
|
data/lib/rucaptcha/version.rb
CHANGED
@@ -5,14 +5,14 @@ module RuCaptcha
|
|
5
5
|
opts[:type] = "text"
|
6
6
|
opts[:autocorrect] = "off"
|
7
7
|
opts[:autocapitalize] = "off"
|
8
|
-
opts[:pattern] = "[a-zA-
|
8
|
+
opts[:pattern] = "[a-zA-Z0-9]*"
|
9
9
|
opts[:autocomplete] = "off"
|
10
10
|
opts[:maxlength] = RuCaptcha.config.length
|
11
11
|
tag(:input, opts)
|
12
12
|
end
|
13
13
|
|
14
14
|
def rucaptcha_image_tag(opts = {})
|
15
|
-
@rucaptcha_image_tag__image_path_in_this_request ||= "#{ru_captcha.root_path}?t=#{Time.now.strftime(
|
15
|
+
@rucaptcha_image_tag__image_path_in_this_request ||= "#{ru_captcha.root_path}?t=#{Time.now.strftime('%s%L')}"
|
16
16
|
opts[:class] = opts[:class] || "rucaptcha-image"
|
17
17
|
opts[:src] = @rucaptcha_image_tag__image_path_in_this_request
|
18
18
|
opts[:onclick] = "this.src = '#{ru_captcha.root_path}?t=' + Date.now();"
|
data/lib/rucaptcha.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
require "rails"
|
2
2
|
require "action_controller"
|
3
3
|
require "active_support/all"
|
4
|
-
|
4
|
+
|
5
|
+
begin
|
6
|
+
# load the precompiled extension file
|
7
|
+
ruby_version = /(\d+\.\d+)/.match(::RUBY_VERSION)
|
8
|
+
require_relative "rucaptcha/#{ruby_version}/rucaptcha"
|
9
|
+
rescue LoadError
|
10
|
+
require "rucaptcha/rucaptcha"
|
11
|
+
end
|
12
|
+
|
5
13
|
require "rucaptcha/version"
|
6
14
|
require "rucaptcha/configuration"
|
7
15
|
require "rucaptcha/controller_helpers"
|
@@ -16,18 +24,16 @@ module RuCaptcha
|
|
16
24
|
return @config if defined?(@config)
|
17
25
|
|
18
26
|
@config = Configuration.new
|
19
|
-
@config.style = :colorful
|
20
27
|
@config.length = 5
|
21
|
-
@config.
|
22
|
-
@config.outline = false
|
28
|
+
@config.difficulty = 3
|
23
29
|
@config.expires_in = 2.minutes
|
24
30
|
@config.skip_cache_store_check = false
|
25
31
|
|
26
32
|
@config.cache_store = if Rails.application
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
Rails.application.config.cache_store
|
34
|
+
else
|
35
|
+
:mem_cache_store
|
36
|
+
end
|
31
37
|
@config.cache_store
|
32
38
|
@config
|
33
39
|
end
|
@@ -37,14 +43,12 @@ module RuCaptcha
|
|
37
43
|
end
|
38
44
|
|
39
45
|
def generate
|
40
|
-
style = config.style == :colorful ? 1 : 0
|
41
46
|
length = config.length
|
42
47
|
|
43
48
|
raise RuCaptcha::Errors::Configuration, "length config error, value must in 3..7" unless length.in?(3..7)
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
create(style, length, strikethrough, outline)
|
50
|
+
result = RuCaptchaCore.create(length, config.difficulty || 5)
|
51
|
+
[result[0], result[1].pack("c*")]
|
48
52
|
end
|
49
53
|
|
50
54
|
def check_cache_store!
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rucaptcha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Lee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -25,19 +25,19 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rb_sys
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
33
|
+
version: 0.9.18
|
34
|
+
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.9.18
|
41
41
|
description:
|
42
42
|
email: huacnlee@gmail.com
|
43
43
|
executables: []
|
@@ -45,18 +45,13 @@ extensions:
|
|
45
45
|
- ext/rucaptcha/extconf.rb
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
-
- CHANGELOG.md
|
49
48
|
- README.md
|
50
|
-
-
|
51
|
-
-
|
52
|
-
-
|
53
|
-
- config/locales/rucaptcha.zh-CN.yml
|
54
|
-
- config/locales/rucaptcha.zh-TW.yml
|
55
|
-
- config/routes.rb
|
56
|
-
- ext/rucaptcha/colors.h
|
49
|
+
- Rakefile
|
50
|
+
- ext/rucaptcha/Cargo.lock
|
51
|
+
- ext/rucaptcha/Cargo.toml
|
57
52
|
- ext/rucaptcha/extconf.rb
|
58
|
-
- ext/rucaptcha/
|
59
|
-
- ext/rucaptcha/
|
53
|
+
- ext/rucaptcha/src/captcha.rs
|
54
|
+
- ext/rucaptcha/src/lib.rs
|
60
55
|
- lib/rucaptcha.rb
|
61
56
|
- lib/rucaptcha/cache.rb
|
62
57
|
- lib/rucaptcha/configuration.rb
|
@@ -77,16 +72,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
77
72
|
requirements:
|
78
73
|
- - ">="
|
79
74
|
- !ruby/object:Gem::Version
|
80
|
-
version: 2.
|
75
|
+
version: 2.7.0
|
81
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
77
|
requirements:
|
83
|
-
- - "
|
78
|
+
- - ">"
|
84
79
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
80
|
+
version: 1.3.1
|
86
81
|
requirements: []
|
87
|
-
rubygems_version: 3.
|
82
|
+
rubygems_version: 3.4.0.dev
|
88
83
|
signing_key:
|
89
84
|
specification_version: 4
|
90
|
-
summary:
|
91
|
-
C code so it no dependencies.
|
85
|
+
summary: Captcha Gem for Rails, which generates captcha image by Rust.
|
92
86
|
test_files: []
|
data/CHANGELOG.md
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
New release please visit:
|
2
|
-
|
3
|
-
https://github.com/huacnlee/rucaptcha/releases
|
4
|
-
|
5
|
-
## 2.5.5
|
6
|
-
|
7
|
-
- Improved image for thicker interference lines.
|
8
|
-
- Add more colors.
|
9
|
-
|
10
|
-
## 2.5.4
|
11
|
-
|
12
|
-
- Fix: rucaptcha input maxlength attribute with config value.
|
13
|
-
|
14
|
-
## 2.5.3
|
15
|
-
|
16
|
-
- Fix session invalid warning, only for development env;
|
17
|
-
|
18
|
-
## 2.5.2
|
19
|
-
|
20
|
-
- Fix session.id error with upgrade Rails 6.0.2.1 or Rack 2.0.8 (#84)
|
21
|
-
|
22
|
-
## 2.5.1
|
23
|
-
|
24
|
-
- Fix invalid module name error. (#78)
|
25
|
-
|
26
|
-
## 2.5.0
|
27
|
-
|
28
|
-
- Support click captcha image to refresh new one by default.
|
29
|
-
- Use simple tag helper generate captcha img html, for avoid asset_host (#73).
|
30
|
-
|
31
|
-
## 2.4.0
|
32
|
-
|
33
|
-
- Add skip_cache_store_check configuration. (#63)
|
34
|
-
- Fix for generate captcha with relative path, not url. (#58)
|
35
|
-
|
36
|
-
## 2.3.2
|
37
|
-
|
38
|
-
- Change Yellow and Green colors to Pink and Deep Purple to pass WCAG 2.0's contrast test. (#70)
|
39
|
-
|
40
|
-
## 2.3.1
|
41
|
-
|
42
|
-
- Fix #67 a y chars will invalid error (only in 2.3.0).
|
43
|
-
|
44
|
-
## 2.3.0
|
45
|
-
|
46
|
-
- Add `config.outline` for use outline style.
|
47
|
-
- Reduce colors down to 5 (red, blue, green, yellow and black).
|
48
|
-
|
49
|
-
## 2.2.0
|
50
|
-
|
51
|
-
- Add option `config.length` for support change number chars. (#57)
|
52
|
-
- Add option `config.strikethrough` for enable or disable strikethrough. (#57)
|
53
|
-
|
54
|
-
## 2.1.3
|
55
|
-
|
56
|
-
- Windows support fixed with `send_data` method. (#45)
|
57
|
-
|
58
|
-
## 2.1.2
|
59
|
-
|
60
|
-
- Do not change captcha when `HEAD /rucaptcha`.
|
61
|
-
|
62
|
-
## 2.1.1
|
63
|
-
|
64
|
-
- Mount engine use `prepend` method to get high priority in config/routes.rb.
|
65
|
-
|
66
|
-
## 2.1.0
|
67
|
-
|
68
|
-
- Mount Router by default, not need config now.
|
69
|
-
|
70
|
-
> IMPORTANT: Wen you upgrade this version, you need remove `mount RuCaptcha::Engine` line from your `config/routes.rb`
|
71
|
-
|
72
|
-
- Default use [:file_store, 'tmp/cache/rucaptcha/session'] as RuCaptcha.config.cache_store, now it can work without any configurations.
|
73
|
-
|
74
|
-
> NOTE: But you still need care about `config.cache_store` to setup on a right way.
|
75
|
-
|
76
|
-
## 2.0.3
|
77
|
-
|
78
|
-
- Use `ActiveSupport.on_load` to extend ActionController and ActionView.
|
79
|
-
|
80
|
-
## 2.0.1
|
81
|
-
|
82
|
-
- Fix `/rucaptcha` path issue when `config.action_controller.asset_host` has setup with CDN url.
|
83
|
-
|
84
|
-
## 2.0.0
|
85
|
-
|
86
|
-
_Break Changes!_
|
87
|
-
|
88
|
-
WARNING!: This version have so many break changes!
|
89
|
-
|
90
|
-
- Use C ext instead of ImageMagick, now it's no dependencies!
|
91
|
-
- New captcha style.
|
92
|
-
- Remove `len`, `font_size`, `cache_limit` config key, no support now.
|
93
|
-
- Output `GIF` format.
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module RuCaptcha
|
2
|
-
class CaptchaController < ActionController::Base
|
3
|
-
def index
|
4
|
-
return head :ok if request.head?
|
5
|
-
|
6
|
-
headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
7
|
-
headers["Pragma"] = "no-cache"
|
8
|
-
data = generate_rucaptcha
|
9
|
-
opts = {disposition: "inline", type: "image/gif"}
|
10
|
-
send_data data, opts
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/config/routes.rb
DELETED