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
``` ```
@ -61,6 +64,7 @@ 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