Allow change chars length and disable strikethrough (#57)

This commit is contained in:
Rina 2017-12-07 16:49:42 +08:00 committed by Jason Lee
parent 2ec5e9e8a6
commit 3939d1bb02
8 changed files with 131 additions and 20 deletions

View File

@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
rucaptcha (2.1.3) rucaptcha (2.1.4)
railties (>= 3.2) railties (>= 3.2)
GEM GEM

View File

@ -20,7 +20,6 @@ This is a Captcha gem for Rails Applications which generates captcha image by C
- High performance. - High performance.
## Usage ## Usage
Put rucaptcha in your `Gemfile`: Put rucaptcha in your `Gemfile`:
``` ```
@ -42,6 +41,10 @@ RuCaptcha.configure do
 # 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符  # 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符
 # 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 cache_store  # 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 cache_store
 self.cache_store = :mem_cache_store  self.cache_store = :mem_cache_store
# 验证码长度 length, 默认是 5, allows: [3,4,5,6,7]
# self.length = 5
# 验证码横线 line, 默认显示横线, default: true, allows: [true, false], 设置为false时, 横线不是显示, 验证码识别度高.
# self.line = true
end end
``` ```
@ -53,7 +56,7 @@ RuCaptcha 没有使用 Rails Session 来存储验证码信息,因为 Rails 的
所以,我建议大家使用的时候,配置上 `cache_store` (详见 [Rails Guides 缓存配置部分](https://ruby-china.github.io/rails-guides/caching_with_rails.html#%E9%85%8D%E7%BD%AE)的文档)到一个 Memcached 或 Redis这才是最佳实践。 所以,我建议大家使用的时候,配置上 `cache_store` (详见 [Rails Guides 缓存配置部分](https://ruby-china.github.io/rails-guides/caching_with_rails.html#%E9%85%8D%E7%BD%AE)的文档)到一个 Memcached 或 Redis这才是最佳实践。
# #
(RuCaptha do not use Rails Session to store captcha information. As the default session is stored in Cookie in Rails, there's a [Replay attack](https://en.wikipedia.org/wiki/Replay_attack) bug which may causes capthcha being destroyed if we store captcha in Rails Session. (RuCaptha do not use Rails Session to store captcha information. As the default session is stored in Cookie in Rails, there's a [Replay attack](https://en.wikipedia.org/wiki/Replay_attack) bug which may causes capthcha being destroyed if we store captcha in Rails Session.
So in my design I require RuCaptcha to configure a distributed backend storage scheme, such as Memcached, Redis or other cache_store schemes which support distribution. So in my design I require RuCaptcha to configure a distributed backend storage scheme, such as Memcached, Redis or other cache_store schemes which support distribution.
@ -61,7 +64,8 @@ So in my design I require RuCaptcha to configure a distributed backend storage s
Meanwhile, for the ease of use, RuCapthca would try to use `:file_store` by default and store the capthca in `tmp/cache/rucaptcha/session` directory (kindly note that it's not working if deploy on multiple machine). Meanwhile, for the ease of use, RuCapthca would try to use `:file_store` by default and store the capthca in `tmp/cache/rucaptcha/session` directory (kindly note that it's not working if deploy on multiple machine).
For recommendation, configure the `cache_store`more details on [Rails Guides Configuration of Cache Stores](http://guides.rubyonrails.org/caching_with_rails.html#configuration) to Memcached or Redis, that would be the best practice.) For recommendation, configure the `cache_store`more details on [Rails Guides Configuration of Cache Stores](http://guides.rubyonrails.org/caching_with_rails.html#configuration) to Memcached or Redis, that would be the best practice.)
#
#
Controller `app/controller/account_controller.rb` Controller `app/controller/account_controller.rb`

View File

@ -1,6 +1,6 @@
// http://github.com/ITikhonov/captcha // http://github.com/ITikhonov/captcha
const int gifsize; const int gifsize;
void captcha(unsigned char im[70*200], unsigned char l[6]); void captcha(unsigned char im[70*200], unsigned char l[8], int length, int i_line);
void makegif(unsigned char im[70*200], unsigned char gif[gifsize], int style); void makegif(unsigned char im[70*200], unsigned char gif[gifsize], int style);
#include <unistd.h> #include <unistd.h>
@ -152,18 +152,37 @@ static void filter(unsigned char im[70*200]) {
static const char *letters="abcdafahijklmnopqrstuvwxyz"; static const char *letters="abcdafahijklmnopqrstuvwxyz";
void captcha(unsigned char im[70*200], unsigned char l[6]) { void captcha(unsigned char im[70*200], unsigned char l[8], int length, int i_line) {
unsigned char swr[200]; unsigned char swr[200];
uint8_t s1,s2; uint8_t s1,s2;
int f=open("/dev/urandom",O_RDONLY); int f=open("/dev/urandom",O_RDONLY);
read(f,l,5); read(f,swr,200); read(f,dr,sizeof(dr)); read(f,&s1,1); read(f,&s2,1); read(f,l,5); read(f,swr,200); read(f,dr,sizeof(dr)); read(f,&s1,1); read(f,&s2,1);
close(f); close(f);
memset(im,0xff,200*70); s1=s1&0x7f; s2=s2&0x3f;
memset(im,0xff,200*70); s1=s1&0x7f; s2=s2&0x3f; l[0]%=25; l[1]%=25; l[2]%=25; l[3]%=25; l[4]%=25; l[5]=0; int x;
int p=30; p=letter(l[0],p,im,swr,s1,s2); p=letter(l[1],p,im,swr,s1,s2); p=letter(l[2],p,im,swr,s1,s2); p=letter(l[3],p,im,swr,s1,s2); letter(l[4],p,im,swr,s1,s2); for(x=0;x<length;x++){
line(im,swr,s1); dots(im); // blur(im); // filter(im); l[x]%=25;
l[0]=letters[l[0]]; l[1]=letters[l[1]]; l[2]=letters[l[2]]; l[3]=letters[l[3]]; l[4]=letters[l[4]]; }
for(x=length;x<8;x++){
l[length]=0;
}
//l[0]%=25; l[1]%=25; l[2]%=25; l[3]%=25; l[4]=0; // l[4]%=25; l[5]=0;
int p=30;
for(x=0;x<length;x++){
p=letter(l[x],p,im,swr,s1,s2);
}
//p=letter(l[0],p,im,swr,s1,s2); p=letter(l[1],p,im,swr,s1,s2); p=letter(l[2],p,im,swr,s1,s2); p=letter(l[3],p,im,swr,s1,s2); //letter(l[4],p,im,swr,s1,s2);
if (i_line == 1) {
line(im,swr,s1);
}
dots(im); // blur(im); // filter(im);
for(x=0;x<length;x++){
l[x]=letters[l[x]];
}
//l[1]=letters[l[1]]; l[2]=letters[l[2]]; l[3]=letters[l[3]]; //l[4]=letters[l[4]];
} }
// #ifdef CAPTCHA // #ifdef CAPTCHA
@ -188,20 +207,22 @@ VALUE RuCaptcha = Qnil;
void Init_rucaptcha(); void Init_rucaptcha();
VALUE create(VALUE self, VALUE style); VALUE create(VALUE self, VALUE style, VALUE length, VALUE line);
void Init_rucaptcha() { void Init_rucaptcha() {
RuCaptcha = rb_define_module("RuCaptcha"); RuCaptcha = rb_define_module("RuCaptcha");
rb_define_singleton_method(RuCaptcha, "create", create, 1); rb_define_singleton_method(RuCaptcha, "create", create, 3);
} }
VALUE create(VALUE self, VALUE style) { VALUE create(VALUE self, VALUE style, VALUE length, VALUE line) {
char l[6]; char l[8];
unsigned char im[80*200]; unsigned char im[80*200];
unsigned char gif[gifsize]; unsigned char gif[gifsize];
int i_style = FIX2INT(style); int i_style = FIX2INT(style);
int i_length = FIX2INT(length);
int i_line = FIX2INT(line);
captcha(im, l); captcha(im, l, i_length, i_line);
makegif(im, gif, i_style); makegif(im, gif, i_style);
VALUE result = rb_ary_new2(2); VALUE result = rb_ary_new2(2);
@ -211,4 +232,3 @@ VALUE create(VALUE self, VALUE style) {
return result; return result;
} }

View File

@ -8,6 +8,7 @@ require 'rucaptcha/controller_helpers'
require 'rucaptcha/view_helpers' require 'rucaptcha/view_helpers'
require 'rucaptcha/cache' require 'rucaptcha/cache'
require 'rucaptcha/engine' require 'rucaptcha/engine'
require 'rucaptcha/errors/configuration'
module RuCaptcha module RuCaptcha
class << self class << self
@ -15,6 +16,8 @@ module RuCaptcha
return @config if defined?(@config) return @config if defined?(@config)
@config = Configuration.new @config = Configuration.new
@config.style = :colorful @config.style = :colorful
@config.length = 5
@config.line = true
@config.expires_in = 2.minutes @config.expires_in = 2.minutes
if Rails.application if Rails.application
@config.cache_store = Rails.application.config.cache_store @config.cache_store = Rails.application.config.cache_store
@ -31,7 +34,10 @@ module RuCaptcha
def generate() def generate()
style = config.style == :colorful ? 1 : 0 style = config.style == :colorful ? 1 : 0
self.create(style) length = config.length
raise Rucaptcha::Errors::Configuration, 'length config error, value must in 3..7' unless length.in?(3..7)
line = config.line ? 1 : 0
self.create(style, length, line)
end end
def check_cache_store! def check_cache_store!

View File

@ -7,5 +7,10 @@ module RuCaptcha
attr_accessor :expires_in attr_accessor :expires_in
# Color style, default: :colorful, allows: [:colorful, :black_white] # Color style, default: :colorful, allows: [:colorful, :black_white]
attr_accessor :style attr_accessor :style
# Captcha Digits: default 5, allows: [3,4,5,6,7]
attr_accessor :length
# rucaptcha line, default: true, allows: [true, false]
attr_accessor :line
end end
end end

View File

@ -0,0 +1,5 @@
module Rucaptcha
module Errors
class Configuration < StandardError; end
end
end

View File

@ -1,3 +1,3 @@
module RuCaptcha module RuCaptcha
VERSION = '2.1.3' VERSION = '2.1.4'
end end

View File

@ -12,17 +12,88 @@ describe RuCaptcha do
describe '.create' do describe '.create' do
it 'should len equal config.len' do it 'should len equal config.len' do
res = RuCaptcha.create(0) res = RuCaptcha.create(0, 5, 1)
expect(res.length).to eq(2) expect(res.length).to eq(2)
expect(res[0].length).to eq(5) expect(res[0].length).to eq(5)
expect(res[1]).not_to eq(nil) expect(res[1]).not_to eq(nil)
end end
it 'should work with color style' do it 'should work with color style' do
res = RuCaptcha.create(1) res = RuCaptcha.create(1, 5, 1)
expect(res.length).to eq(2) expect(res.length).to eq(2)
expect(res[0].length).to eq(5) expect(res[0].length).to eq(5)
expect(res[1]).not_to eq(nil) expect(res[1]).not_to eq(nil)
end end
it 'should raise when length not in 3..7 ' do
RuCaptcha.configure do
self.length = 2
end
#expect(RuCaptcha.generate()).to raise_error('length config error, value must in 3..7')
expect { RuCaptcha.generate() }.
to raise_error('length config error, value must in 3..7')
RuCaptcha.configure do
self.length = 5
end
end
it 'should work when length in 3..7 ' do
RuCaptcha.configure do
self.length = 5
end
res = RuCaptcha.generate()
expect(res.length).to eq(2)
expect(res[0].length).to eq(5)
expect(res[1]).not_to eq(nil)
end
it 'should len equal 3' do
res = RuCaptcha.create(1, 3, 1)
expect(res.length).to eq(2)
expect(res[0].length).to eq(3)
expect(res[1]).not_to eq(nil)
end
it 'should len equal 4' do
res = RuCaptcha.create(1, 4, 1)
expect(res.length).to eq(2)
expect(res[0].length).to eq(4)
expect(res[1]).not_to eq(nil)
end
it 'should len equal 5' do
res = RuCaptcha.create(1, 5, 1)
expect(res.length).to eq(2)
expect(res[0].length).to eq(5)
expect(res[1]).not_to eq(nil)
end
it 'should len equal 6' do
res = RuCaptcha.create(1, 6, 1)
expect(res.length).to eq(2)
expect(res[0].length).to eq(6)
expect(res[1]).not_to eq(nil)
end
it 'should len equal 7' do
res = RuCaptcha.create(1, 7, 0)
expect(res.length).to eq(2)
expect(res[0].length).to eq(7)
expect(res[1]).not_to eq(nil)
end
it 'should work with line true' do
res = RuCaptcha.create(1, 7, 1)
expect(res.length).to eq(2)
expect(res[0].length).to eq(7)
expect(res[1]).not_to eq(nil)
end
it 'should work with line false' do
res = RuCaptcha.create(1, 7, 0)
expect(res.length).to eq(2)
expect(res[0].length).to eq(7)
expect(res[1]).not_to eq(nil)
end
end end
end end