rucaptcha 3.2.4-x86_64-darwin → 3.3.0-x86_64-darwin
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 +14 -2
- data/Rakefile +3 -3
- data/ext/rucaptcha/Cargo.toml +1 -1
- data/ext/rucaptcha/src/captcha.rs +115 -110
- data/ext/rucaptcha/src/lib.rs +3 -1
- data/lib/rucaptcha/3.2/rucaptcha.bundle +0 -0
- data/lib/rucaptcha/3.3/rucaptcha.bundle +0 -0
- data/lib/rucaptcha/3.4/rucaptcha.bundle +0 -0
- data/lib/rucaptcha/configuration.rb +4 -0
- data/lib/rucaptcha/controller_helpers.rb +9 -2
- data/lib/rucaptcha/version.rb +1 -1
- data/lib/rucaptcha.rb +9 -3
- metadata +8 -9
- data/lib/rucaptcha/3.1/rucaptcha.bundle +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f44b2c6c4fde92fe157d382d04977cf22810092897abad7d4c7dd619bc307fa
|
4
|
+
data.tar.gz: 199f8b389636713abd6a1f789aa5a2fddeacf6c36e2337dc76c6bfcb44ebc914
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c48b7e02e592b4d92b685c99528e690e210c8466f7942a4843d1864b22c5e2b50360d699ddfe84e10105bb846dddb9fdd0e523f019bab6f5eb2a032cbc07bfe7
|
7
|
+
data.tar.gz: 5542adfee183097dd342573c8707072acb4aefaa4b8979800fea2a844ae54b1cbf1ecc6b1d8bf3bc4dc7c12e5252872f732eb3a4b004ed724b9f7ac9e2c7514a
|
data/README.md
CHANGED
@@ -59,6 +59,16 @@ RuCaptcha.configure do
|
|
59
59
|
# Enable or disable noise, default: false
|
60
60
|
# self.noise = false
|
61
61
|
|
62
|
+
# Enable or disable circle background, default: true
|
63
|
+
# self.circle = true
|
64
|
+
|
65
|
+
# Set the difficulty level, default: 5, allows: [1..10].
|
66
|
+
# Only valid when noise is enabled
|
67
|
+
# self.difficulty = 5
|
68
|
+
|
69
|
+
# Set the case sensitive, default: false
|
70
|
+
# self.case_sensitive = false
|
71
|
+
|
62
72
|
# Set the image format, default: png, allows: [jpeg, png, webp]
|
63
73
|
# self.format = 'png'
|
64
74
|
|
@@ -181,11 +191,13 @@ end
|
|
181
191
|
|
182
192
|
## Performance
|
183
193
|
|
194
|
+
> Based on MacBook Pro (Apple M3)
|
195
|
+
|
184
196
|
`rake benchmark` to run benchmark test.
|
185
197
|
|
186
198
|
```
|
187
199
|
Warming up --------------------------------------
|
188
|
-
Generate image
|
200
|
+
Generate image 84.000 i/100ms
|
189
201
|
Calculating -------------------------------------
|
190
|
-
Generate image
|
202
|
+
Generate image 859.075 (± 1.5%) i/s (1.16 ms/i) - 4.368k in 5.085775s
|
191
203
|
```
|
data/Rakefile
CHANGED
@@ -30,7 +30,7 @@ task default: :spec
|
|
30
30
|
|
31
31
|
def create_captcha(length = 5, difficulty = 5)
|
32
32
|
require "rucaptcha"
|
33
|
-
RuCaptchaCore.create(length, difficulty, false, false, "png")
|
33
|
+
RuCaptchaCore.create(length, difficulty, false, false, false, "png")
|
34
34
|
end
|
35
35
|
|
36
36
|
task :preview do
|
@@ -63,10 +63,10 @@ task :benchmark do
|
|
63
63
|
require "rucaptcha"
|
64
64
|
require "benchmark/ips"
|
65
65
|
|
66
|
-
RuCaptchaCore.create(5, 5, true, true, "png")
|
66
|
+
RuCaptchaCore.create(5, 5, true, true, true, "png")
|
67
67
|
|
68
68
|
Benchmark.ips do |x|
|
69
|
-
x.report("Generate image") { RuCaptchaCore.create(5, 5, true, true, "png") }
|
69
|
+
x.report("Generate image") { RuCaptchaCore.create(5, 5, true, true, true, "png") }
|
70
70
|
x.compare!
|
71
71
|
end
|
72
72
|
end
|
data/ext/rucaptcha/Cargo.toml
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
use image::{ImageBuffer, Rgba};
|
2
|
+
use imageproc::{
|
3
|
+
drawing::{draw_cubic_bezier_curve_mut, draw_filled_ellipse_mut},
|
4
|
+
noise::gaussian_noise_mut,
|
5
|
+
};
|
2
6
|
use rand::{thread_rng, Rng};
|
3
7
|
use rusttype::{Font, Scale};
|
4
|
-
use std::io::Cursor;
|
8
|
+
use std::{io::Cursor, sync::LazyLock};
|
5
9
|
|
6
10
|
static BASIC_CHAR: [char; 54] = [
|
7
11
|
'2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M',
|
@@ -9,9 +13,6 @@ static BASIC_CHAR: [char; 54] = [
|
|
9
13
|
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
10
14
|
];
|
11
15
|
|
12
|
-
static FONT_BYTES1: &[u8; 145008] = include_bytes!("../fonts/FuzzyBubbles-Regular.ttf");
|
13
|
-
static FONT_BYTES2: &[u8; 37792] = include_bytes!("../fonts/Handlee-Regular.ttf");
|
14
|
-
|
15
16
|
// https://coolors.co/cc0b8f-7c0abe-5700c8-3c2ea4-3d56a8-3fa67e-45bb30-69d003-a0d003-d8db02
|
16
17
|
static COLORS: [(u8, u8, u8, u8); 14] = [
|
17
18
|
(197, 166, 3, 255),
|
@@ -33,32 +34,34 @@ static COLORS: [(u8, u8, u8, u8); 14] = [
|
|
33
34
|
static SCALE_SM: u32 = 32;
|
34
35
|
static SCALE_MD: u32 = 45;
|
35
36
|
static SCALE_LG: u32 = 55;
|
37
|
+
static FONT_0: LazyLock<Font> = LazyLock::new(|| {
|
38
|
+
Font::try_from_bytes(include_bytes!("../fonts/FuzzyBubbles-Regular.ttf")).unwrap()
|
39
|
+
});
|
40
|
+
static FONT_1: LazyLock<Font> =
|
41
|
+
LazyLock::new(|| Font::try_from_bytes(include_bytes!("../fonts/Handlee-Regular.ttf")).unwrap());
|
36
42
|
|
43
|
+
#[inline(always)]
|
37
44
|
fn rand_num(len: usize) -> usize {
|
38
45
|
let mut rng = thread_rng();
|
39
46
|
rng.gen_range(0..=len)
|
40
47
|
}
|
41
48
|
|
42
|
-
|
43
|
-
|
49
|
+
/// Generate a random captcha string with a given length
|
50
|
+
#[inline]
|
51
|
+
fn rand_captcha(len: usize) -> String {
|
52
|
+
let mut result = String::with_capacity(len);
|
53
|
+
let seed = BASIC_CHAR.len() - 1;
|
44
54
|
for _ in 0..len {
|
45
|
-
let rnd = rand_num(
|
46
|
-
|
55
|
+
let rnd = rand_num(seed);
|
56
|
+
result.push(BASIC_CHAR[rnd])
|
47
57
|
}
|
48
|
-
|
49
|
-
}
|
50
|
-
|
51
|
-
#[allow(unused)]
|
52
|
-
fn get_color() -> Rgba<u8> {
|
53
|
-
let rnd = rand_num(COLORS.len() - 1);
|
54
|
-
let c = COLORS[rnd];
|
55
|
-
Rgba([c.0, c.1, c.2, c.3])
|
58
|
+
result
|
56
59
|
}
|
57
60
|
|
58
|
-
fn get_colors(
|
61
|
+
fn get_colors(len: usize) -> Vec<Rgba<u8>> {
|
59
62
|
let rnd = rand_num(COLORS.len());
|
60
|
-
let mut out =
|
61
|
-
for i in 0..
|
63
|
+
let mut out = Vec::with_capacity(len);
|
64
|
+
for i in 0..len {
|
62
65
|
let c = COLORS[(rnd + i) % COLORS.len()];
|
63
66
|
out.push(Rgba([c.0, c.1, c.2, c.3]))
|
64
67
|
}
|
@@ -66,78 +69,11 @@ fn get_colors(num: usize) -> Vec<Rgba<u8>> {
|
|
66
69
|
out
|
67
70
|
}
|
68
71
|
|
72
|
+
#[inline(always)]
|
69
73
|
fn get_next(min: f32, max: u32) -> f32 {
|
70
74
|
min + rand_num(max as usize - min as usize) as f32
|
71
75
|
}
|
72
76
|
|
73
|
-
fn get_font() -> Font<'static> {
|
74
|
-
match rand_num(2) {
|
75
|
-
0 => Font::try_from_bytes(FONT_BYTES1).unwrap(),
|
76
|
-
1 => Font::try_from_bytes(FONT_BYTES2).unwrap(),
|
77
|
-
_ => Font::try_from_bytes(FONT_BYTES1).unwrap(),
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
fn get_image(width: usize, height: usize) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
|
82
|
-
ImageBuffer::from_fn(width as u32, height as u32, |_, _| {
|
83
|
-
image::Rgba([255, 255, 255, 255])
|
84
|
-
})
|
85
|
-
}
|
86
|
-
|
87
|
-
fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, lines: bool) {
|
88
|
-
let c = (image.width() - 20) / res.len() as u32;
|
89
|
-
let y = image.height() / 3 - 15;
|
90
|
-
|
91
|
-
let h = image.height() as f32;
|
92
|
-
|
93
|
-
let scale = match res.len() {
|
94
|
-
1..=3 => SCALE_LG,
|
95
|
-
4..=5 => SCALE_MD,
|
96
|
-
_ => SCALE_SM,
|
97
|
-
} as f32;
|
98
|
-
|
99
|
-
let colors = get_colors(res.len());
|
100
|
-
let line_colors = get_colors(res.len());
|
101
|
-
|
102
|
-
let xscale = scale - rand_num((scale * 0.2) as usize) as f32;
|
103
|
-
let yscale = h as f32 - rand_num((h * 0.2) as usize) as f32;
|
104
|
-
|
105
|
-
// Draw line, ellipse first as background
|
106
|
-
for (i, _) in res.iter().enumerate() {
|
107
|
-
let line_color = line_colors[i];
|
108
|
-
|
109
|
-
if lines {
|
110
|
-
draw_interference_line(1, image, line_color);
|
111
|
-
}
|
112
|
-
draw_interference_ellipse(1, image, line_color);
|
113
|
-
}
|
114
|
-
|
115
|
-
// Draw text
|
116
|
-
for (i, _) in res.iter().enumerate() {
|
117
|
-
let text = &res[i];
|
118
|
-
|
119
|
-
let color = colors[i];
|
120
|
-
let font = get_font();
|
121
|
-
|
122
|
-
for j in 0..(rand_num(3) + 1) as i32 {
|
123
|
-
// Draw text again with offset
|
124
|
-
let offset = j * (rand_num(2) as i32);
|
125
|
-
imageproc::drawing::draw_text_mut(
|
126
|
-
image,
|
127
|
-
color,
|
128
|
-
10 + offset + (i as u32 * c) as i32,
|
129
|
-
y as i32 as i32,
|
130
|
-
Scale {
|
131
|
-
x: xscale + offset as f32,
|
132
|
-
y: yscale as f32,
|
133
|
-
},
|
134
|
-
&font,
|
135
|
-
text,
|
136
|
-
);
|
137
|
-
}
|
138
|
-
}
|
139
|
-
}
|
140
|
-
|
141
77
|
fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, color: Rgba<u8>) {
|
142
78
|
for _ in 0..num {
|
143
79
|
let width = image.width();
|
@@ -154,7 +90,7 @@ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>
|
|
154
90
|
let ctrl_x2 = get_next((width / 12) as f32, width / 12 * 3);
|
155
91
|
let ctrl_y2 = get_next(x1, height - 5);
|
156
92
|
// Randomly draw bezier curves
|
157
|
-
|
93
|
+
draw_cubic_bezier_curve_mut(
|
158
94
|
image,
|
159
95
|
(x1, y1),
|
160
96
|
(x2, y2),
|
@@ -176,7 +112,7 @@ fn draw_interference_ellipse(
|
|
176
112
|
let x = rand_num((image.width() - 25) as usize) as i32;
|
177
113
|
let y = rand_num((image.height() - 15) as usize) as i32;
|
178
114
|
|
179
|
-
|
115
|
+
draw_filled_ellipse_mut(image, (x, y), w, w, color);
|
180
116
|
}
|
181
117
|
}
|
182
118
|
|
@@ -187,16 +123,17 @@ pub struct Captcha {
|
|
187
123
|
|
188
124
|
pub struct CaptchaBuilder {
|
189
125
|
length: usize,
|
190
|
-
width:
|
191
|
-
height:
|
126
|
+
width: u32,
|
127
|
+
height: u32,
|
192
128
|
complexity: usize,
|
193
129
|
line: bool,
|
194
130
|
noise: bool,
|
131
|
+
circle: bool,
|
195
132
|
format: image::ImageFormat,
|
196
133
|
}
|
197
134
|
|
198
|
-
impl CaptchaBuilder {
|
199
|
-
|
135
|
+
impl Default for CaptchaBuilder {
|
136
|
+
fn default() -> Self {
|
200
137
|
CaptchaBuilder {
|
201
138
|
length: 4,
|
202
139
|
width: 220,
|
@@ -204,9 +141,16 @@ impl CaptchaBuilder {
|
|
204
141
|
complexity: 5,
|
205
142
|
line: true,
|
206
143
|
noise: false,
|
144
|
+
circle: true,
|
207
145
|
format: image::ImageFormat::Png,
|
208
146
|
}
|
209
147
|
}
|
148
|
+
}
|
149
|
+
|
150
|
+
impl CaptchaBuilder {
|
151
|
+
pub fn new() -> Self {
|
152
|
+
Self::default()
|
153
|
+
}
|
210
154
|
|
211
155
|
pub fn length(mut self, length: usize) -> Self {
|
212
156
|
self.length = length;
|
@@ -223,6 +167,11 @@ impl CaptchaBuilder {
|
|
223
167
|
self
|
224
168
|
}
|
225
169
|
|
170
|
+
pub fn circle(mut self, circle: bool) -> Self {
|
171
|
+
self.circle = circle;
|
172
|
+
self
|
173
|
+
}
|
174
|
+
|
226
175
|
pub fn format(mut self, format: &str) -> Self {
|
227
176
|
self.format = match format {
|
228
177
|
"png" => image::ImageFormat::Png,
|
@@ -235,32 +184,89 @@ impl CaptchaBuilder {
|
|
235
184
|
}
|
236
185
|
|
237
186
|
pub fn complexity(mut self, complexity: usize) -> Self {
|
238
|
-
|
239
|
-
|
240
|
-
|
187
|
+
self.complexity = complexity.clamp(1, 10);
|
188
|
+
self
|
189
|
+
}
|
190
|
+
|
191
|
+
fn cyclic_write_character(
|
192
|
+
&self,
|
193
|
+
captcha: &str,
|
194
|
+
image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>,
|
195
|
+
lines: bool,
|
196
|
+
) {
|
197
|
+
let c = (image.width() - 20) / captcha.len() as u32;
|
198
|
+
let y = image.height() / 3 - 15;
|
199
|
+
|
200
|
+
let h = image.height() as f32;
|
201
|
+
|
202
|
+
let scale = match captcha.len() {
|
203
|
+
1..=3 => SCALE_LG,
|
204
|
+
4..=5 => SCALE_MD,
|
205
|
+
_ => SCALE_SM,
|
206
|
+
} as f32;
|
207
|
+
|
208
|
+
let colors = get_colors(captcha.len());
|
209
|
+
let line_colors = get_colors(captcha.len());
|
210
|
+
|
211
|
+
let xscale = scale - rand_num((scale * 0.2) as usize) as f32;
|
212
|
+
let yscale = h - rand_num((h * 0.2) as usize) as f32;
|
213
|
+
|
214
|
+
// Draw line, ellipse first as background
|
215
|
+
if self.circle {
|
216
|
+
(0..captcha.len()).for_each(|i| {
|
217
|
+
let line_color = line_colors[i];
|
218
|
+
|
219
|
+
if lines {
|
220
|
+
draw_interference_line(1, image, line_color);
|
221
|
+
}
|
222
|
+
draw_interference_ellipse(1, image, line_color);
|
223
|
+
});
|
241
224
|
}
|
242
|
-
|
243
|
-
|
225
|
+
|
226
|
+
let font = match rand_num(2) {
|
227
|
+
0 => &FONT_0,
|
228
|
+
1 => &FONT_1,
|
229
|
+
_ => &FONT_1,
|
230
|
+
};
|
231
|
+
|
232
|
+
// Draw text
|
233
|
+
for (i, ch) in captcha.chars().enumerate() {
|
234
|
+
let color = colors[i];
|
235
|
+
|
236
|
+
for j in 0..(rand_num(3) + 1) as i32 {
|
237
|
+
// Draw text again with offset
|
238
|
+
let offset = j * (rand_num(2) as i32);
|
239
|
+
imageproc::drawing::draw_text_mut(
|
240
|
+
image,
|
241
|
+
color,
|
242
|
+
10 + offset + (i as u32 * c) as i32,
|
243
|
+
y as i32,
|
244
|
+
Scale {
|
245
|
+
x: xscale + offset as f32,
|
246
|
+
y: yscale as f32,
|
247
|
+
},
|
248
|
+
font,
|
249
|
+
&ch.to_string(),
|
250
|
+
);
|
251
|
+
}
|
244
252
|
}
|
245
|
-
self.complexity = complexity;
|
246
|
-
self
|
247
253
|
}
|
248
254
|
|
249
255
|
pub fn build(self) -> Captcha {
|
250
256
|
// Generate an array of captcha characters
|
251
|
-
let
|
252
|
-
|
253
|
-
let text = res.join("");
|
257
|
+
let text = rand_captcha(self.length);
|
254
258
|
|
255
259
|
// Create a white background image
|
256
|
-
let mut
|
260
|
+
let mut buf = ImageBuffer::from_fn(self.width, self.height, |_, _| {
|
261
|
+
image::Rgba([255, 255, 255, 255])
|
262
|
+
});
|
257
263
|
|
258
264
|
// Loop to write the verification code string into the background image
|
259
|
-
cyclic_write_character(&
|
265
|
+
self.cyclic_write_character(&text, &mut buf, self.line);
|
260
266
|
|
261
267
|
if self.noise {
|
262
|
-
|
263
|
-
&mut
|
268
|
+
gaussian_noise_mut(
|
269
|
+
&mut buf,
|
264
270
|
(self.complexity - 1) as f64,
|
265
271
|
((10 * self.complexity) - 10) as f64,
|
266
272
|
((5 * self.complexity) - 5) as u64,
|
@@ -268,9 +274,8 @@ impl CaptchaBuilder {
|
|
268
274
|
}
|
269
275
|
|
270
276
|
let mut bytes: Vec<u8> = Vec::new();
|
271
|
-
image
|
272
|
-
.
|
273
|
-
.unwrap();
|
277
|
+
buf.write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)
|
278
|
+
.expect("failed to write rucaptcha image into png");
|
274
279
|
|
275
280
|
Captcha { text, image: bytes }
|
276
281
|
}
|
data/ext/rucaptcha/src/lib.rs
CHANGED
@@ -7,6 +7,7 @@ pub fn create(
|
|
7
7
|
difficulty: usize,
|
8
8
|
line: bool,
|
9
9
|
noise: bool,
|
10
|
+
circle: bool,
|
10
11
|
format: String,
|
11
12
|
) -> (String, Vec<u8>) {
|
12
13
|
let c = captcha::CaptchaBuilder::new();
|
@@ -15,6 +16,7 @@ pub fn create(
|
|
15
16
|
.length(len)
|
16
17
|
.line(line)
|
17
18
|
.noise(noise)
|
19
|
+
.circle(circle)
|
18
20
|
.format(&format)
|
19
21
|
.build();
|
20
22
|
|
@@ -24,7 +26,7 @@ pub fn create(
|
|
24
26
|
#[magnus::init]
|
25
27
|
fn init() -> Result<(), Error> {
|
26
28
|
let class = define_class("RuCaptchaCore", magnus::class::object())?;
|
27
|
-
class.define_singleton_method("create", function!(create,
|
29
|
+
class.define_singleton_method("create", function!(create, 6))?;
|
28
30
|
|
29
31
|
Ok(())
|
30
32
|
}
|
Binary file
|
Binary file
|
Binary file
|
@@ -13,11 +13,15 @@ module RuCaptcha
|
|
13
13
|
attr_accessor :line
|
14
14
|
# Enable or disable noise on captcha image, default: false
|
15
15
|
attr_accessor :noise
|
16
|
+
# Enable or disable circle background on captcha image, default: true
|
17
|
+
attr_accessor :circle
|
16
18
|
# Image format allow: ['jpeg', 'png', 'webp'], default: 'png'
|
17
19
|
attr_accessor :format
|
18
20
|
# skip_cache_store_check, default: false
|
19
21
|
attr_accessor :skip_cache_store_check
|
20
22
|
# custom rucaptcha mount path, default: '/rucaptcha'
|
21
23
|
attr_accessor :mount_path
|
24
|
+
# Enable or disable case sensitive, default: false
|
25
|
+
attr_accessor :case_sensitive
|
22
26
|
end
|
23
27
|
end
|
@@ -62,10 +62,17 @@ module RuCaptcha
|
|
62
62
|
return add_rucaptcha_validation_error if (Time.now.to_i - store_info[:time]) > RuCaptcha.config.expires_in
|
63
63
|
|
64
64
|
# Make sure parama have captcha
|
65
|
-
captcha = (opts[:captcha] || params[:_rucaptcha] || "").
|
65
|
+
captcha = (opts[:captcha] || params[:_rucaptcha] || "").strip
|
66
|
+
saved_code = store_info[:code]
|
67
|
+
|
66
68
|
return add_rucaptcha_validation_error if captcha.blank?
|
67
69
|
|
68
|
-
|
70
|
+
unless RuCaptcha.config.case_sensitive
|
71
|
+
captcha.downcase!
|
72
|
+
saved_code.downcase!
|
73
|
+
end
|
74
|
+
|
75
|
+
return add_rucaptcha_validation_error if captcha != saved_code
|
69
76
|
|
70
77
|
true
|
71
78
|
end
|
data/lib/rucaptcha/version.rb
CHANGED
data/lib/rucaptcha.rb
CHANGED
@@ -29,9 +29,11 @@ module RuCaptcha
|
|
29
29
|
@config.expires_in = 2.minutes
|
30
30
|
@config.skip_cache_store_check = false
|
31
31
|
@config.line = true
|
32
|
-
@config.noise =
|
32
|
+
@config.noise = false
|
33
|
+
@config.circle = true
|
33
34
|
@config.format = "png"
|
34
35
|
@config.mount_path = "/rucaptcha"
|
36
|
+
@config.case_sensitive = false
|
35
37
|
|
36
38
|
@config.cache_store = if Rails.application
|
37
39
|
Rails.application.config.cache_store
|
@@ -51,8 +53,12 @@ module RuCaptcha
|
|
51
53
|
|
52
54
|
raise RuCaptcha::Errors::Configuration, "length config error, value must in 3..7" unless length.in?(3..7)
|
53
55
|
|
54
|
-
result = RuCaptchaCore.create(length, config.difficulty || 5, config.line, config.noise, config.format)
|
55
|
-
|
56
|
+
result = RuCaptchaCore.create(length, config.difficulty || 5, config.line, config.noise, config.circle, config.format)
|
57
|
+
unless config.case_sensitive
|
58
|
+
result[0].downcase!
|
59
|
+
end
|
60
|
+
|
61
|
+
[result[0], result[1].pack("c*")]
|
56
62
|
end
|
57
63
|
|
58
64
|
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: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: x86_64-darwin
|
6
6
|
authors:
|
7
7
|
- Jason Lee
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -24,21 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.2'
|
27
|
-
force_ruby_platform: false
|
28
27
|
- !ruby/object:Gem::Dependency
|
29
28
|
name: rb_sys
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
31
|
- - ">="
|
33
32
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.9.
|
33
|
+
version: 0.9.105
|
35
34
|
type: :runtime
|
36
35
|
prerelease: false
|
37
36
|
version_requirements: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
38
|
- - ">="
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.9.
|
40
|
+
version: 0.9.105
|
42
41
|
description:
|
43
42
|
email: huacnlee@gmail.com
|
44
43
|
executables: []
|
@@ -62,9 +61,9 @@ files:
|
|
62
61
|
- ext/rucaptcha/src/captcha.rs
|
63
62
|
- ext/rucaptcha/src/lib.rs
|
64
63
|
- lib/rucaptcha.rb
|
65
|
-
- lib/rucaptcha/3.1/rucaptcha.bundle
|
66
64
|
- lib/rucaptcha/3.2/rucaptcha.bundle
|
67
65
|
- lib/rucaptcha/3.3/rucaptcha.bundle
|
66
|
+
- lib/rucaptcha/3.4/rucaptcha.bundle
|
68
67
|
- lib/rucaptcha/cache.rb
|
69
68
|
- lib/rucaptcha/configuration.rb
|
70
69
|
- lib/rucaptcha/controller_helpers.rb
|
@@ -84,17 +83,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
83
|
requirements:
|
85
84
|
- - ">="
|
86
85
|
- !ruby/object:Gem::Version
|
87
|
-
version: '3.
|
86
|
+
version: '3.2'
|
88
87
|
- - "<"
|
89
88
|
- !ruby/object:Gem::Version
|
90
|
-
version: 3.
|
89
|
+
version: 3.5.dev
|
91
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
91
|
requirements:
|
93
92
|
- - ">="
|
94
93
|
- !ruby/object:Gem::Version
|
95
94
|
version: '0'
|
96
95
|
requirements: []
|
97
|
-
rubygems_version: 3.
|
96
|
+
rubygems_version: 3.5.23
|
98
97
|
signing_key:
|
99
98
|
specification_version: 4
|
100
99
|
summary: Captcha Gem for Rails, which generates captcha image by Rust.
|
Binary file
|