rucaptcha 3.1.4-x86_64-linux-musl → 3.2.2-x86_64-linux-musl

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3af47c69388045f547d6607f5ca66c2e3b73117f3b3a08edf8202d22f7b48071
4
- data.tar.gz: e1924c65e500ce004aea2ebedd23722ceb207308757057b0a881de9596e93440
3
+ metadata.gz: b3341ed0c4d97f6ab74e316827050ccaed3ab5553f652382fb05e19726299fd6
4
+ data.tar.gz: 80b6072bb80c6d16408610fd95ef27b44bf4c6b6d43ead6fa18c744a64c64912
5
5
  SHA512:
6
- metadata.gz: e2ff54e604aaaaa45ff22569fefd82e8d65dd1fd00b0b2b7aec72e5c342575ef66eaaffe26f3027f56b7d7b928c7b41011b319ea585fc37226f8f524016f1dab
7
- data.tar.gz: d99857cd15ef6d4a21bae2616d47a2e02a8bf3d4f712b74d7eca4c103204024201e7de826fa33171738899ae1434055c558933b899e76ff06c1f63bc5b5bffbb
6
+ metadata.gz: 6857a3556271ae2e2898f48665e0b68e28b53b51e2f9b51083434cb3b04c7a97f1da0b333b66b2b36da2f4915fb598d2f3c77fa9561e72bc9299957f8dfedadc
7
+ data.tar.gz: c20c38a3831ccc9373073411a57fd34f405753876cc9b3f3cef989371c33facf04c9c713294c6c5b75e2a521bd6565e91510d8ae30a509728516d150b8369a2f
data/README.md CHANGED
@@ -37,6 +37,7 @@ Create `config/initializers/rucaptcha.rb`
37
37
  RuCaptcha.configure do
38
38
  # Custom captcha code expire time if you need, default: 2 minutes
39
39
  # self.expires_in = 120
40
+
40
41
   # [Requirement / 重要]
41
42
  # Store Captcha code where, this config more like Rails config.cache_store
42
43
  # default: Read config info from `Rails.application.config.cache_store`
@@ -44,10 +45,25 @@ RuCaptcha.configure do
44
45
   # 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符
45
46
   # 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 cache_store
46
47
   self.cache_store = :mem_cache_store
48
+
49
+ # If you wants disable `cache_store` check warning, you can do it, default: false
47
50
  # 如果想要 disable cache_store 的 warning,就设置为 true,default false
48
51
  # self.skip_cache_store_check = true
52
+
49
53
  # Chars length, default: 5, allows: [3 - 7]
50
54
  # self.length = 5
55
+
56
+ # Enable or disable Strikethrough, default: true
57
+ # self.line = true
58
+
59
+ # Enable or disable noise, default: false
60
+ # self.noise = false
61
+
62
+ # Set the image format, default: png, allows: [jpeg, png, webp]
63
+ # self.format = 'png'
64
+
65
+ # Custom mount path, default: '/rucaptcha'
66
+ # self.mount_path = '/rucaptcha'
51
67
  end
52
68
  ```
53
69
 
data/Rakefile CHANGED
@@ -27,9 +27,14 @@ end
27
27
  RSpec::Core::RakeTask.new(:spec)
28
28
  task default: :spec
29
29
 
30
+ def create_captcha(length = 5, difficulty = 5)
31
+ require "rucaptcha"
32
+ RuCaptchaCore.create(length, difficulty, false, false, "png")
33
+ end
34
+
30
35
  task :preview do
31
36
  require "rucaptcha"
32
- res = RuCaptchaCore.create(5, 5)
37
+ res = create_captcha()
33
38
  warn "-------------------------\n#{res[0]}"
34
39
  puts res[1].pack("c*")
35
40
  end
@@ -38,11 +43,11 @@ task :memory do
38
43
  require "rucaptcha"
39
44
  require "memory_profiler"
40
45
 
41
- RuCaptchaCore.create(5, 5)
46
+ create_captcha()
42
47
 
43
48
  report = MemoryProfiler.report do
44
49
  1000.times do
45
- RuCaptchaCore.create(5, 5)
50
+ create_captcha()
46
51
  end
47
52
  end
48
53
 
@@ -57,10 +62,10 @@ task :benchmark do
57
62
  require "rucaptcha"
58
63
  require "benchmark/ips"
59
64
 
60
- RuCaptchaCore.create(5, 5)
65
+ RuCaptchaCore.create(5, 5, true, true, "png")
61
66
 
62
67
  Benchmark.ips do |x|
63
- x.report("Generate image") { RuCaptchaCore.create(5, 5) }
68
+ x.report("Generate image") { RuCaptchaCore.create(5, 5, true, true, "png") }
64
69
  x.compare!
65
70
  end
66
71
  end
@@ -1,6 +1,4 @@
1
- use image::{ImageBuffer, Rgb};
2
- use imageproc::drawing::{draw_cubic_bezier_curve_mut, draw_text_mut};
3
- use imageproc::noise::gaussian_noise_mut;
1
+ use image::{ImageBuffer, Rgba};
4
2
  use rand::{thread_rng, Rng};
5
3
  use rusttype::{Font, Scale};
6
4
  use std::io::Cursor;
@@ -15,21 +13,21 @@ static FONT_BYTES1: &[u8; 145008] = include_bytes!("../fonts/FuzzyBubbles-Regula
15
13
  static FONT_BYTES2: &[u8; 37792] = include_bytes!("../fonts/Handlee-Regular.ttf");
16
14
 
17
15
  // https://coolors.co/cc0b8f-7c0abe-5700c8-3c2ea4-3d56a8-3fa67e-45bb30-69d003-a0d003-d8db02
18
- static COLORS: [(u8, u8, u8); 14] = [
19
- (197, 166, 3),
20
- (187, 87, 5),
21
- (176, 7, 7),
22
- (186, 9, 56),
23
- (204, 11, 143),
24
- (124, 10, 190),
25
- (87, 0, 200),
26
- (61, 86, 168),
27
- (63, 166, 126),
28
- (69, 187, 48),
29
- (105, 208, 3),
30
- (160, 208, 3),
31
- (216, 219, 2),
32
- (50, 50, 50),
16
+ static COLORS: [(u8, u8, u8, u8); 14] = [
17
+ (197, 166, 3, 255),
18
+ (187, 87, 5, 255),
19
+ (176, 7, 7, 255),
20
+ (186, 9, 56, 255),
21
+ (204, 11, 143, 255),
22
+ (124, 10, 190, 255),
23
+ (87, 0, 200, 255),
24
+ (61, 86, 168, 255),
25
+ (63, 166, 126, 255),
26
+ (69, 187, 48, 255),
27
+ (105, 208, 3, 255),
28
+ (160, 208, 3, 255),
29
+ (216, 219, 2, 255),
30
+ (50, 50, 50, 255),
33
31
  ];
34
32
 
35
33
  static SCALE_SM: u32 = 32;
@@ -51,18 +49,18 @@ fn get_captcha(len: usize) -> Vec<String> {
51
49
  }
52
50
 
53
51
  #[allow(unused)]
54
- fn get_color() -> Rgb<u8> {
52
+ fn get_color() -> Rgba<u8> {
55
53
  let rnd = rand_num(COLORS.len() - 1);
56
54
  let c = COLORS[rnd];
57
- Rgb([c.0, c.1, c.2])
55
+ Rgba([c.0, c.1, c.2, c.3])
58
56
  }
59
57
 
60
- fn get_colors(num: usize) -> Vec<Rgb<u8>> {
58
+ fn get_colors(num: usize) -> Vec<Rgba<u8>> {
61
59
  let rnd = rand_num(COLORS.len());
62
60
  let mut out = vec![];
63
61
  for i in 0..num {
64
62
  let c = COLORS[(rnd + i) % COLORS.len()];
65
- out.push(Rgb([c.0, c.1, c.2]))
63
+ out.push(Rgba([c.0, c.1, c.2, c.3]))
66
64
  }
67
65
 
68
66
  out
@@ -80,13 +78,13 @@ fn get_font() -> Font<'static> {
80
78
  }
81
79
  }
82
80
 
83
- fn get_image(width: usize, height: usize) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
81
+ fn get_image(width: usize, height: usize) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
84
82
  ImageBuffer::from_fn(width as u32, height as u32, |_, _| {
85
- image::Rgb([255, 255, 255])
83
+ image::Rgba([255, 255, 255, 255])
86
84
  })
87
85
  }
88
86
 
89
- fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>) {
87
+ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, lines: bool) {
90
88
  let c = (image.width() - 20) / res.len() as u32;
91
89
  let y = image.height() / 3 - 15;
92
90
 
@@ -107,7 +105,10 @@ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u
107
105
  // Draw line, ellipse first as background
108
106
  for (i, _) in res.iter().enumerate() {
109
107
  let line_color = line_colors[i];
110
- draw_interference_line(1, image, line_color);
108
+
109
+ if lines {
110
+ draw_interference_line(1, image, line_color);
111
+ }
111
112
  draw_interference_ellipse(1, image, line_color);
112
113
  }
113
114
 
@@ -121,7 +122,7 @@ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u
121
122
  for j in 0..(rand_num(3) + 1) as i32 {
122
123
  // Draw text again with offset
123
124
  let offset = j * (rand_num(2) as i32);
124
- draw_text_mut(
125
+ imageproc::drawing::draw_text_mut(
125
126
  image,
126
127
  color,
127
128
  10 + offset + (i as u32 * c) as i32,
@@ -137,7 +138,7 @@ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u
137
138
  }
138
139
  }
139
140
 
140
- fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>, color: Rgb<u8>) {
141
+ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, color: Rgba<u8>) {
141
142
  for _ in 0..num {
142
143
  let width = image.width();
143
144
  let height = image.height();
@@ -153,7 +154,7 @@ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
153
154
  let ctrl_x2 = get_next((width / 12) as f32, width / 12 * 3);
154
155
  let ctrl_y2 = get_next(x1, height - 5);
155
156
  // Randomly draw bezier curves
156
- draw_cubic_bezier_curve_mut(
157
+ imageproc::drawing::draw_cubic_bezier_curve_mut(
157
158
  image,
158
159
  (x1, y1),
159
160
  (x2, y2),
@@ -166,8 +167,8 @@ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
166
167
 
167
168
  fn draw_interference_ellipse(
168
169
  num: usize,
169
- image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
170
- color: Rgb<u8>,
170
+ image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>,
171
+ color: Rgba<u8>,
171
172
  ) {
172
173
  for _ in 0..num {
173
174
  // max cycle width 20px
@@ -189,6 +190,9 @@ pub struct CaptchaBuilder {
189
190
  width: usize,
190
191
  height: usize,
191
192
  complexity: usize,
193
+ line: bool,
194
+ noise: bool,
195
+ format: image::ImageFormat,
192
196
  }
193
197
 
194
198
  impl CaptchaBuilder {
@@ -198,6 +202,9 @@ impl CaptchaBuilder {
198
202
  width: 220,
199
203
  height: 70,
200
204
  complexity: 5,
205
+ line: true,
206
+ noise: false,
207
+ format: image::ImageFormat::Png,
201
208
  }
202
209
  }
203
210
 
@@ -206,15 +213,26 @@ impl CaptchaBuilder {
206
213
  self
207
214
  }
208
215
 
209
- // pub fn width(mut self, width: usize) -> Self {
210
- // self.width = width;
211
- // self
212
- // }
216
+ pub fn line(mut self, line: bool) -> Self {
217
+ self.line = line;
218
+ self
219
+ }
220
+
221
+ pub fn noise(mut self, noise: bool) -> Self {
222
+ self.noise = noise;
223
+ self
224
+ }
225
+
226
+ pub fn format(mut self, format: &str) -> Self {
227
+ self.format = match format {
228
+ "png" => image::ImageFormat::Png,
229
+ "jpg" | "jpeg" => image::ImageFormat::Jpeg,
230
+ "webp" => image::ImageFormat::WebP,
231
+ _ => image::ImageFormat::Png,
232
+ };
213
233
 
214
- // pub fn height(mut self, height: usize) -> Self {
215
- // self.height = height;
216
- // self
217
- // }
234
+ self
235
+ }
218
236
 
219
237
  pub fn complexity(mut self, complexity: usize) -> Self {
220
238
  let mut complexity = complexity;
@@ -238,20 +256,86 @@ impl CaptchaBuilder {
238
256
  let mut image = get_image(self.width, self.height);
239
257
 
240
258
  // Loop to write the verification code string into the background image
241
- cyclic_write_character(&res, &mut image);
242
-
243
- gaussian_noise_mut(
244
- &mut image,
245
- (self.complexity - 1) as f64,
246
- ((10 * self.complexity) - 10) as f64,
247
- ((5 * self.complexity) - 5) as u64,
248
- );
259
+ cyclic_write_character(&res, &mut image, self.line);
260
+
261
+ if self.noise {
262
+ imageproc::noise::gaussian_noise_mut(
263
+ &mut image,
264
+ (self.complexity - 1) as f64,
265
+ ((10 * self.complexity) - 10) as f64,
266
+ ((5 * self.complexity) - 5) as u64,
267
+ );
268
+ }
249
269
 
250
270
  let mut bytes: Vec<u8> = Vec::new();
251
271
  image
252
- .write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Jpeg)
272
+ .write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)
253
273
  .unwrap();
254
274
 
255
275
  Captcha { text, image: bytes }
256
276
  }
257
277
  }
278
+
279
+ #[cfg(test)]
280
+ mod tests {
281
+ use super::*;
282
+
283
+ #[test]
284
+ fn test_format() {
285
+ let mut builder = CaptchaBuilder::new();
286
+ assert_eq!(builder.format, image::ImageFormat::Png);
287
+
288
+ builder = builder.format("jpg");
289
+ assert_eq!(builder.format, image::ImageFormat::Jpeg);
290
+ builder = builder.format("jpeg");
291
+ assert_eq!(builder.format, image::ImageFormat::Jpeg);
292
+ builder = builder.format("webp");
293
+ assert_eq!(builder.format, image::ImageFormat::WebP);
294
+ builder = builder.format("png");
295
+ assert_eq!(builder.format, image::ImageFormat::Png);
296
+ builder = builder.format("gif");
297
+ assert_eq!(builder.format, image::ImageFormat::Png);
298
+ }
299
+
300
+ #[test]
301
+ fn test_line() {
302
+ let mut builder = CaptchaBuilder::new();
303
+ assert!(builder.line);
304
+
305
+ builder = builder.line(false);
306
+ assert!(!builder.line);
307
+ }
308
+
309
+ #[test]
310
+ fn test_noise() {
311
+ let mut builder = CaptchaBuilder::new();
312
+ assert!(!builder.noise);
313
+
314
+ builder = builder.noise(true);
315
+ assert!(builder.noise);
316
+ }
317
+
318
+ #[test]
319
+ fn test_difficulty() {
320
+ let mut builder = CaptchaBuilder::new();
321
+ assert_eq!(builder.complexity, 5);
322
+
323
+ builder = builder.complexity(10);
324
+ assert_eq!(builder.complexity, 10);
325
+
326
+ builder = builder.complexity(11);
327
+ assert_eq!(builder.complexity, 10);
328
+
329
+ builder = builder.complexity(0);
330
+ assert_eq!(builder.complexity, 1);
331
+ }
332
+
333
+ #[test]
334
+ fn test_length() {
335
+ let mut builder = CaptchaBuilder::new();
336
+ assert_eq!(builder.length, 4);
337
+
338
+ builder = builder.length(10);
339
+ assert_eq!(builder.length, 10);
340
+ }
341
+ }
@@ -2,9 +2,21 @@ use magnus::{define_class, function, Error, Object};
2
2
 
3
3
  mod captcha;
4
4
 
5
- pub fn create(len: usize, difficulty: usize) -> (String, Vec<u8>) {
5
+ pub fn create(
6
+ len: usize,
7
+ difficulty: usize,
8
+ line: bool,
9
+ noise: bool,
10
+ format: String,
11
+ ) -> (String, Vec<u8>) {
6
12
  let c = captcha::CaptchaBuilder::new();
7
- let out = c.complexity(difficulty).length(len).build();
13
+ let out = c
14
+ .complexity(difficulty)
15
+ .length(len)
16
+ .line(line)
17
+ .noise(noise)
18
+ .format(&format)
19
+ .build();
8
20
 
9
21
  (out.text, out.image)
10
22
  }
@@ -12,7 +24,7 @@ pub fn create(len: usize, difficulty: usize) -> (String, Vec<u8>) {
12
24
  #[magnus::init]
13
25
  fn init() -> Result<(), Error> {
14
26
  let class = define_class("RuCaptchaCore", Default::default())?;
15
- class.define_singleton_method("create", function!(create, 2))?;
27
+ class.define_singleton_method("create", function!(create, 5))?;
16
28
 
17
29
  Ok(())
18
30
  }
Binary file
Binary file
@@ -9,7 +9,15 @@ module RuCaptcha
9
9
  attr_accessor :length
10
10
  # Hard mode, default: 5, allows: [1..10]
11
11
  attr_accessor :difficulty
12
+ # Enable or disable strikethrough lines on captcha image, default: true
13
+ attr_accessor :line
14
+ # Enable or disable noise on captcha image, default: false
15
+ attr_accessor :noise
16
+ # Image format allow: ['jpeg', 'png', 'webp'], default: 'png'
17
+ attr_accessor :format
12
18
  # skip_cache_store_check, default: false
13
19
  attr_accessor :skip_cache_store_check
20
+ # custom rucaptcha mount path, default: '/rucaptcha'
21
+ attr_accessor :mount_path
14
22
  end
15
23
  end
@@ -6,7 +6,7 @@ module RuCaptcha
6
6
  # https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/routing/route_set.rb#L268
7
7
  # `app.routes.prepend` start from Rails 3.2 - 5.0
8
8
  app.routes.prepend do
9
- mount RuCaptcha::Engine => "/rucaptcha"
9
+ mount RuCaptcha::Engine => RuCaptcha.config.mount_path
10
10
  end
11
11
 
12
12
  RuCaptcha.check_cache_store! unless RuCaptcha.config.skip_cache_store_check
@@ -1,3 +1,3 @@
1
1
  module RuCaptcha
2
- VERSION = "3.1.4"
2
+ VERSION = "3.2.2"
3
3
  end
data/lib/rucaptcha.rb CHANGED
@@ -28,6 +28,10 @@ module RuCaptcha
28
28
  @config.difficulty = 3
29
29
  @config.expires_in = 2.minutes
30
30
  @config.skip_cache_store_check = false
31
+ @config.line = true
32
+ @config.noise = true
33
+ @config.format = "png"
34
+ @config.mount_path = "/rucaptcha"
31
35
 
32
36
  @config.cache_store = if Rails.application
33
37
  Rails.application.config.cache_store
@@ -47,7 +51,7 @@ module RuCaptcha
47
51
 
48
52
  raise RuCaptcha::Errors::Configuration, "length config error, value must in 3..7" unless length.in?(3..7)
49
53
 
50
- result = RuCaptchaCore.create(length, config.difficulty || 5)
54
+ result = RuCaptchaCore.create(length, config.difficulty || 5, config.line, config.noise, config.format)
51
55
  [result[0].downcase, result[1].pack("c*")]
52
56
  end
53
57
 
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.1.4
4
+ version: 3.2.2
5
5
  platform: x86_64-linux-musl
6
6
  authors:
7
7
  - Jason Lee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-11 00:00:00.000000000 Z
11
+ date: 2023-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  requirements: []
96
- rubygems_version: 3.4.3
96
+ rubygems_version: 3.4.4
97
97
  signing_key:
98
98
  specification_version: 4
99
99
  summary: Captcha Gem for Rails, which generates captcha image by Rust.