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
remote: .
specs:
rucaptcha (2.1.3)
rucaptcha (2.1.4)
railties (>= 3.2)
GEM

View File

@ -20,7 +20,6 @@ This is a Captcha gem for Rails Applications which generates captcha image by C
- High performance.
## Usage
Put rucaptcha in your `Gemfile`:
```
@ -42,6 +41,10 @@ RuCaptcha.configure do
 # 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符
 # 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 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
```
@ -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这才是最佳实践。
#
#
(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.
@ -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).
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`

View File

@ -1,6 +1,6 @@
// http://github.com/ITikhonov/captcha
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);
#include <unistd.h>
@ -152,18 +152,37 @@ static void filter(unsigned char im[70*200]) {
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];
uint8_t s1,s2;
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);
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 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);
line(im,swr,s1); dots(im); // blur(im); // filter(im);
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]];
int x;
for(x=0;x<length;x++){
l[x]%=25;
}
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
@ -188,20 +207,22 @@ VALUE RuCaptcha = Qnil;
void Init_rucaptcha();
VALUE create(VALUE self, VALUE style);
VALUE create(VALUE self, VALUE style, VALUE length, VALUE line);
void Init_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) {
char l[6];
VALUE create(VALUE self, VALUE style, VALUE length, VALUE line) {
char l[8];
unsigned char im[80*200];
unsigned char gif[gifsize];
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);
VALUE result = rb_ary_new2(2);
@ -211,4 +232,3 @@ VALUE create(VALUE self, VALUE style) {
return result;
}

View File

@ -8,6 +8,7 @@ require 'rucaptcha/controller_helpers'
require 'rucaptcha/view_helpers'
require 'rucaptcha/cache'
require 'rucaptcha/engine'
require 'rucaptcha/errors/configuration'
module RuCaptcha
class << self
@ -15,6 +16,8 @@ module RuCaptcha
return @config if defined?(@config)
@config = Configuration.new
@config.style = :colorful
@config.length = 5
@config.line = true
@config.expires_in = 2.minutes
if Rails.application
@config.cache_store = Rails.application.config.cache_store
@ -31,7 +34,10 @@ module RuCaptcha
def generate()
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
def check_cache_store!

View File

@ -7,5 +7,10 @@ module RuCaptcha
attr_accessor :expires_in
# Color style, default: :colorful, allows: [:colorful, :black_white]
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

View File

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

View File

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

View File

@ -12,17 +12,88 @@ describe RuCaptcha do
describe '.create' 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[0].length).to eq(5)
expect(res[1]).not_to eq(nil)
end
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[0].length).to eq(5)
expect(res[1]).not_to eq(nil)
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