acts_as_textcaptcha 1.2.1 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -8,6 +8,10 @@ The gem can be configured with your very own logic questions (to fall back on if
8
8
 
9
9
  Text CAPTCHA's logic questions are aimed at a child's age of 7, so can be solved easily by all but the most cognitively impaired users. As they involve human logic, such questions cannot be solved by a robot. There are both advantages and disadvantages for using logic questions over image based captchas, {find out more at Text CAPTCHA}[http://textcaptcha.com/why].
10
10
 
11
+ == Rails 3
12
+
13
+ This plugin/gem is now fully Rails 3 compatible.
14
+
11
15
  == Demo
12
16
 
13
17
  Here's a {fully working demo on heroku}[http://textcaptcha.heroku.com]!
@@ -16,7 +20,7 @@ Here's a {fully working demo on heroku}[http://textcaptcha.heroku.com]!
16
20
 
17
21
  What do you need?
18
22
 
19
- * {Rails}[http://github.com/rails/rails] >= 2.3
23
+ * {Rails}[http://github.com/rails/rails] >= 2.3.x (including Rails 3)
20
24
  * {Ruby}[http://ruby-lang.org/] >= 1.8.7
21
25
  * {bcrypt-ruby}[http://bcrypt-ruby.rubyforge.org/] gem (to securely encrypt the spam answers in your session)
22
26
  * {Text CAPTCHA api key}[http://textcaptcha.com/register] (_optional_, since you can define your own logic questions, see below for details)
@@ -24,19 +28,25 @@ What do you need?
24
28
 
25
29
  == Installing
26
30
 
27
- Install the gems
31
+ Install the gem
28
32
 
29
- sudo gem install acts_as_textcaptcha bcrypt-ruby
33
+ sudo gem install acts_as_textcaptcha
30
34
 
31
- Or you can install acts_as_textcaptcha as a Rails plugin
35
+ Or you can install acts_as_textcaptcha as a Rails plugin
32
36
 
33
37
  script/plugin install git://github.com/matthutchinson/acts_as_textcaptcha
38
+ (if you do this be sure to include {bcrypt-ruby}[http://bcrypt-ruby.rubyforge.org/] in your Gemfile or with config.gem in your environment)
34
39
 
35
- == Using
40
+ == Using
41
+
42
+ First the gem to your Gemfile
43
+
44
+ gem "acts_as_textcaptcha"
36
45
 
37
- First, add the gem in your environment.rb file;
46
+ OR add the gem in your environment.rb config;
38
47
 
39
48
  config.gem 'acts_as_textcaptcha'
49
+
40
50
 
41
51
  Next configure your models to be spam protected; (this is the most basic way to configure the gem, with an api key only)
42
52
 
@@ -63,11 +73,13 @@ Next in your controller *new* and *create* actions you'll want to _spamify_ your
63
73
 
64
74
  Finally, in your form/view erb do something like the following;
65
75
 
66
- <%- if @comment.validate_spam_answer -%>
67
- <%= f.hidden_field :spam_answer, :value => @comment.spam_answer -%>
68
- <%- else -%>
69
- <%= f.label :spam_answer, @comment.spam_question %>
70
- <%= f.text_field :spam_answer, :value => '' %>
76
+ <%- if @comment.new_record? -%>
77
+ <%- if @comment.validate_spam_answer -%>
78
+ <%= f.hidden_field :spam_answer, :value => @comment.spam_answer -%>
79
+ <%- else -%>
80
+ <%= f.label :spam_answer, @comment.spam_question %>
81
+ <%= f.text_field :spam_answer, :value => '' %>
82
+ <%- end -%>
71
83
  <%- end -%>
72
84
 
73
85
  == More Configurations
@@ -101,7 +113,7 @@ It *also* is possible to configure to use only your own user defined logic quest
101
113
 
102
114
  The gem contains two parts, a module for your ActiveRecord models, and a tiny helper method (spamify).
103
115
 
104
- A call to spamify(@model) in your controller will query the Text CAPTCHA web service. A restful GET request is made with Net::HTTP and parsed using the standard XML::Parser. A spam_question is assigned to the model, and an array of possible answers are encrypted in the session.
116
+ A call to spamify(@model) in your controller will query the Text CAPTCHA web service. A GET request is made with Net::HTTP and parsed using the default Rails ActiveSupport::XMLMini backend (or the standard XML::Parser in older versions of Rails). A spam_question is assigned to the model, and an array of possible answers are encrypted in the session.
105
117
 
106
118
  validate_spam_answer() is called on @model.validate() and checks that the @model.spam_answer matches one of those possible answers in the session. This validation is _only_ carried out on new records, i.e. never on edit, only on create. User's attempted spam answers are not case-sensitive and have trailing/leading white-space removed.
107
119
 
@@ -137,6 +149,10 @@ For more details on the code please check the {documentation}[http://rdoc.info/p
137
149
  * {Text CAPTCHA}[http://textcaptcha.com] api and service by {Rob Tuley}[http://openknot.com/me/] at {Openknot}[http://openknot.com]
138
150
  * {bcrypt-ruby}[http://bcrypt-ruby.rubyforge.org/] Gem by {Coda Hale}[http://codahale.com]
139
151
 
152
+ == Todo
153
+
154
+ * Test in other Ruby versions
155
+
140
156
  == Usage
141
157
 
142
158
  This code is currently used in a number of production websites and apps. It was originally extracted from code developed for {Bugle}[http://bugleblogs.com]
@@ -0,0 +1,2 @@
1
+ ActiveRecord::Base.extend ActsAsTextcaptcha::Textcaptcha
2
+ ActionController::Base.send(:include, ActsAsTextcaptcha::TextcaptchaHelper)
@@ -0,0 +1,7 @@
1
+ ActiveSupport.on_load(:active_record) do
2
+ extend ActsAsTextcaptcha::Textcaptcha
3
+ end
4
+
5
+ ActiveSupport.on_load(:action_controller) do
6
+ include ActsAsTextcaptcha::TextcaptchaHelper
7
+ end
@@ -0,0 +1,119 @@
1
+ require 'yaml'
2
+ require 'net/http'
3
+ require 'md5'
4
+ require 'logger'
5
+
6
+ # compatiblity with < Rails 3.0.0
7
+ require 'xml' unless defined?(ActiveSupport::XmlMini)
8
+
9
+ # if using as a plugin in /vendor/plugins
10
+ begin
11
+ require 'bcrypt'
12
+ rescue LoadError => e
13
+ puts "ActsAsTextcaptcha - please gem install bcrypt-ruby and add `gem \"bcrypt-ruby\"` to your Gemfile (or environment config)"
14
+ raise e
15
+ end
16
+
17
+ module ActsAsTextcaptcha
18
+ module Textcaptcha #:nodoc:
19
+
20
+ def acts_as_textcaptcha(options = nil)
21
+ cattr_accessor :textcaptcha_config
22
+ attr_accessor :spam_answer, :spam_question, :possible_answers
23
+ validate :validate_textcaptcha
24
+
25
+ if options.is_a?(Hash)
26
+ self.textcaptcha_config = options
27
+ else
28
+ begin
29
+ self.textcaptcha_config = YAML.load(File.read("#{Rails.root.to_s}/config/textcaptcha.yml"))[Rails.env]
30
+ rescue Errno::ENOENT
31
+ raise('./config/textcaptcha.yml not found')
32
+ end
33
+ end
34
+
35
+ include InstanceMethods
36
+ end
37
+
38
+
39
+ module InstanceMethods
40
+
41
+ # override this method to toggle spam checking, default is on (true)
42
+ def perform_spam_check?; true end
43
+
44
+ # override this method to toggle allowing the model to be created, default is on (true)
45
+ # if returning false model.validate will always be false with errors on base
46
+ def allowed?; true end
47
+
48
+ def validate_textcaptcha
49
+ if new_record?
50
+ if allowed?
51
+ if possible_answers && perform_spam_check? && !validate_spam_answer
52
+ errors.add(:spam_answer, 'is incorrect, try another question instead')
53
+ return false
54
+ end
55
+ else
56
+ errors.add(:base, "Sorry, #{self.class.name.pluralize.downcase} are currently disabled")
57
+ return false
58
+ end
59
+ end
60
+ true
61
+ end
62
+
63
+ def validate_spam_answer
64
+ (spam_answer && possible_answers) ? possible_answers.include?(encrypt_answer(Digest::MD5.hexdigest(spam_answer.strip.downcase.to_s))) : false
65
+ end
66
+
67
+ def encrypt_answers(answers)
68
+ answers.map {|answer| encrypt_answer(answer) }
69
+ end
70
+
71
+ def encrypt_answer(answer)
72
+ return answer unless(textcaptcha_config['bcrypt_salt'])
73
+ BCrypt::Engine.hash_secret(answer, textcaptcha_config['bcrypt_salt'], (textcaptcha_config['bcrypt_cost'] || 10))
74
+ end
75
+
76
+ def generate_spam_question(use_textcaptcha = true)
77
+ if use_textcaptcha && textcaptcha_config && textcaptcha_config['api_key']
78
+ begin
79
+ resp = Net::HTTP.get(URI.parse('http://textcaptcha.com/api/'+textcaptcha_config['api_key']))
80
+ return [] if resp.empty?
81
+
82
+ if defined?(ActiveSupport::XmlMini)
83
+ parsed_xml = ActiveSupport::XmlMini.parse(resp)['captcha']
84
+ self.spam_question = parsed_xml['question']['__content__']
85
+ if parsed_xml['answer'].is_a?(Array)
86
+ self.possible_answers = encrypt_answers(parsed_xml['answer'].collect {|a| a['__content__']})
87
+ else
88
+ self.possible_answers = encrypt_answers([parsed_xml['answer']['__content__']])
89
+ end
90
+ else
91
+ parsed_xml = XML::Parser.string(resp).parse
92
+ self.spam_question = parsed_xml.find('/captcha/question')[0].inner_xml
93
+ self.possible_answers = encrypt_answers(parsed_xml.find('/captcha/answer').map(&:inner_xml))
94
+ end
95
+ return possible_answers if spam_question && !possible_answers.empty?
96
+ rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Errno::ECONNREFUSED,
97
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, URI::InvalidURIError => e
98
+ log_textcaptcha("failed to load or parse textcaptcha with key '#{textcaptcha_config['api_key']}'; #{e}")
99
+ end
100
+ end
101
+
102
+ # fall back to textcaptcha_config questions
103
+ if textcaptcha_config && textcaptcha_config['questions']
104
+ log_textcaptcha('falling back to random logic question from config') if textcaptcha_config['api_key']
105
+ random_question = textcaptcha_config['questions'][rand(textcaptcha_config['questions'].size)]
106
+ self.spam_question = random_question['question']
107
+ self.possible_answers = encrypt_answers(random_question['answers'].split(',').map!{|ans| Digest::MD5.hexdigest(ans)})
108
+ end
109
+ possible_answers
110
+ end
111
+
112
+ private
113
+ def log_textcaptcha(message)
114
+ logger ||= Logger.new(STDOUT)
115
+ logger.info "Textcaptcha >> #{message}"
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,9 @@
1
+ module ActsAsTextcaptcha
2
+ module TextcaptchaHelper
3
+
4
+ # generates a spam question and possible answers for a model, answers are stored in session[:possible_answers]
5
+ def spamify(model)
6
+ session[:possible_answers] = model.generate_spam_question unless model.validate_spam_answer
7
+ end
8
+ end
9
+ end
@@ -1,100 +1,3 @@
1
- begin
2
- require 'xml'
3
- require 'yaml'
4
- require 'net/http'
5
- require 'md5'
6
- require 'logger'
7
- require 'bcrypt'
8
- rescue LoadError
9
- end
10
-
11
- module ActsAsTextcaptcha #:nodoc:
12
-
13
- def acts_as_textcaptcha(options = nil)
14
- cattr_accessor :textcaptcha_config
15
- attr_accessor :spam_answer, :spam_question, :possible_answers
16
-
17
- if options.is_a?(Hash)
18
- self.textcaptcha_config = options
19
- else
20
- begin
21
- self.textcaptcha_config = YAML.load(File.read("#{(defined? RAILS_ROOT) ? "#{RAILS_ROOT}" : '.'}/config/textcaptcha.yml"))[((defined? RAILS_ENV) ? RAILS_ENV : 'test')]
22
- rescue Errno::ENOENT
23
- raise('./config/textcaptcha.yml not found')
24
- end
25
- end
26
-
27
- include InstanceMethods
28
- end
29
-
30
-
31
- module InstanceMethods
32
-
33
- # override this method to toggle spam checking, default is on (true)
34
- def perform_spam_check?; true end
35
-
36
- # override this method to toggle allowing the model to be created, default is on (true)
37
- # if returning false model.validate will always be false with errors on base
38
- def allowed?; true end
39
-
40
- def validate
41
- super
42
- if new_record?
43
- if allowed?
44
- if possible_answers && perform_spam_check? && !validate_spam_answer
45
- errors.add(:spam_answer, 'is incorrect, try another question instead')
46
- return false
47
- end
48
- else
49
- errors.add_to_base("Sorry, #{self.class.name.pluralize.downcase} are currently disabled")
50
- return false
51
- end
52
- end
53
- true
54
- end
55
-
56
- def validate_spam_answer
57
- (spam_answer && possible_answers) ? possible_answers.include?(encrypt_answer(Digest::MD5.hexdigest(spam_answer.strip.downcase.to_s))) : false
58
- end
59
-
60
- def encrypt_answers(answers)
61
- answers.map {|answer| encrypt_answer(answer) }
62
- end
63
-
64
- def encrypt_answer(answer)
65
- return answer unless(textcaptcha_config['bcrypt_salt'])
66
- BCrypt::Engine.hash_secret(answer, textcaptcha_config['bcrypt_salt'], (textcaptcha_config['bcrypt_cost'] || 10))
67
- end
68
-
69
- def generate_spam_question(use_textcaptcha = true)
70
- if use_textcaptcha && textcaptcha_config && textcaptcha_config['api_key']
71
- begin
72
- resp = Net::HTTP.get(URI.parse('http://textcaptcha.com/api/'+textcaptcha_config['api_key']))
73
- if !resp.empty? && xml = XML::Parser.string(resp).parse
74
- self.spam_question = xml.find('/captcha/question')[0].inner_xml
75
- self.possible_answers = encrypt_answers(xml.find('/captcha/answer').map(&:inner_xml))
76
- end
77
- return possible_answers if spam_question && !possible_answers.empty?
78
- rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Errno::ECONNREFUSED,
79
- Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, URI::InvalidURIError => e
80
- log_textcaptcha("failed to load or parse textcaptcha with key '#{textcaptcha_config['api_key']}'; #{e}")
81
- end
82
- end
83
-
84
- # fall back to textcaptcha_config questions
85
- if textcaptcha_config && textcaptcha_config['questions']
86
- log_textcaptcha('falling back to random logic question from config') if textcaptcha_config['api_key']
87
- random_question = textcaptcha_config['questions'][rand(textcaptcha_config['questions'].size)]
88
- self.spam_question = random_question['question']
89
- self.possible_answers = encrypt_answers(random_question['answers'].split(',').map!{|ans| Digest::MD5.hexdigest(ans)})
90
- end
91
- possible_answers
92
- end
93
-
94
- private
95
- def log_textcaptcha(message)
96
- logger ||= Logger.new(STDOUT)
97
- logger.info "Textcaptcha >> #{message}"
98
- end
99
- end
100
- end
1
+ require 'acts_as_textcaptcha/textcaptcha'
2
+ require 'acts_as_textcaptcha/textcaptcha_helper'
3
+ require "acts_as_textcaptcha/framework/rails#{Rails::VERSION::MAJOR}" if defined?(Rails)
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  class Widget < ActiveRecord::Base
4
4
  # uses textcaptcha.yml file for configuration
@@ -38,34 +38,42 @@ describe 'ActsAsTextcaptcha' do
38
38
 
39
39
  before(:each) do
40
40
  @note.generate_spam_question
41
- @note.validate.should be_false
41
+ @note.validate_textcaptcha.should be_false
42
+ @note.should_not be_valid
42
43
  end
43
44
 
44
45
  it 'should validate spam answer with possible answers' do
45
46
  @note.spam_answer = '2'
46
- @note.validate.should be_true
47
+ @note.validate_textcaptcha.should be_true
48
+ @note.should be_valid
47
49
 
48
50
  @note.spam_answer = 'two'
49
- @note.validate.should be_true
51
+ @note.validate_textcaptcha.should be_true
52
+ @note.should be_valid
50
53
 
51
54
  @note.spam_answer = 'wrong'
52
- @note.validate.should be_false
55
+ @note.validate_textcaptcha.should be_false
56
+ @note.should_not be_valid
53
57
  end
54
58
 
55
59
  it 'should strip whitespace and downcase spam answer' do
56
60
  @note.spam_answer = ' tWo '
57
- @note.validate.should be_true
61
+ @note.validate_textcaptcha.should be_true
62
+ @note.should be_valid
58
63
 
59
64
  @note.spam_answer = ' 2 '
60
- @note.validate.should be_true
65
+ @note.validate_textcaptcha.should be_true
66
+ @note.should be_valid
61
67
  end
62
68
 
63
69
  it 'should always validate if not a new record' do
64
70
  @note.spam_answer = '2'
65
71
  @note.save!
66
72
  @note.generate_spam_question
73
+
67
74
  @note.new_record?.should be_false
68
- @note.validate.should be_true
75
+ @note.validate_textcaptcha.should be_true
76
+ @note.should be_valid
69
77
  end
70
78
  end
71
79
 
@@ -90,17 +98,20 @@ describe 'ActsAsTextcaptcha' do
90
98
 
91
99
  it 'should always be valid if skip_spam_check? is true' do
92
100
  @comment.generate_spam_question
93
- @comment.validate.should be_false
101
+ @comment.validate_textcaptcha.should be_false
102
+ @comment.should_not be_valid
103
+
94
104
  @comment.stub!(:perform_spam_check?).and_return(false)
95
- @comment.validate.should be_true
105
+ @comment.validate_textcaptcha.should be_true
96
106
  @comment.should be_valid
97
107
  end
98
108
 
99
109
  it 'should always fail validation if allowed? is false' do
100
- @comment.validate.should be_true
110
+ @comment.validate_textcaptcha.should be_true
101
111
  @comment.stub!(:allowed?).and_return(false)
102
- @comment.validate.should be_false
103
- @comment.errors.on(:base).should eql('Sorry, comments are currently disabled')
112
+
113
+ @comment.validate_textcaptcha.should be_false
114
+ @comment.errors[:base].should eql(['Sorry, comments are currently disabled'])
104
115
  @comment.should_not be_valid
105
116
  end
106
117
  end
@@ -109,8 +120,11 @@ describe 'ActsAsTextcaptcha' do
109
120
 
110
121
  it 'should be configurable from inline options' do
111
122
  @comment.textcaptcha_config.should eql({'api_key' => '8u5ixtdnq9csc84cok0owswgo'})
112
- @review.textcaptcha_config.should eql({'bcrypt_cost'=>'3', 'questions'=>[{'question'=>'1+1', 'answers'=>'2,two'}, {'question'=>'The green hat is what color?', 'answers'=>'green'}, {'question'=>'Which is bigger: 67, 14 or 6', 'answers'=>'67,sixtyseven,sixty seven,sixty-seven'}], 'bcrypt_salt'=>'$2a$10$j0bmycH.SVfD1b5mpEGPpe', 'api_key'=>'8u5ixtdnq9csc84cok0owswgo'})
113
- @note.textcaptcha_config .should eql({'questions'=>[{'question'=>'1+1', 'answers'=>'2,two'}]})
123
+ @review.textcaptcha_config.should eql({'bcrypt_cost'=>'3', 'questions'=>[{'question'=>'1+1', 'answers'=>'2,two'},
124
+ {'question'=>'The green hat is what color?', 'answers'=>'green'},
125
+ {'question'=>'Which is bigger: 67, 14 or 6', 'answers'=>'67,sixtyseven,sixty seven,sixty-seven'}],
126
+ 'bcrypt_salt'=>'$2a$10$j0bmycH.SVfD1b5mpEGPpe', 'api_key'=>'8u5ixtdnq9csc84cok0owswgo'})
127
+ @note.textcaptcha_config.should eql({'questions'=>[{'question'=>'1+1', 'answers'=>'2,two'}]})
114
128
  end
115
129
 
116
130
  it 'should generate spam question from textcaptcha service' do
@@ -118,7 +132,9 @@ describe 'ActsAsTextcaptcha' do
118
132
  @comment.spam_question.should_not be_nil
119
133
  @comment.possible_answers.should_not be_nil
120
134
  @comment.possible_answers.should be_an(Array)
121
- @comment.validate.should be_false
135
+
136
+ @comment.validate_textcaptcha.should be_false
137
+ @comment.should_not be_valid
122
138
  end
123
139
 
124
140
  describe 'and textcaptcha unavailable' do
@@ -132,14 +148,17 @@ describe 'ActsAsTextcaptcha' do
132
148
  @review.spam_question.should_not be_nil
133
149
  @review.possible_answers.should_not be_nil
134
150
  @review.possible_answers.should be_an(Array)
135
- @review.validate.should be_false
151
+
152
+ @review.validate_textcaptcha.should be_false
153
+ @review.should_not be_valid
136
154
  end
137
155
 
138
156
  it 'should not generate any spam question/answer if no user defined questions set' do
139
157
  @comment.generate_spam_question
140
158
  @comment.spam_question.should be_nil
141
159
  @comment.possible_answers.should be_nil
142
- @comment.validate.should be_true
160
+ @comment.validate_textcaptcha.should be_true
161
+ @comment.should be_valid
143
162
  end
144
163
  end
145
164
  end
@@ -162,7 +181,8 @@ describe 'ActsAsTextcaptcha' do
162
181
  @widget.spam_question.should_not be_nil
163
182
  @widget.possible_answers.should_not be_nil
164
183
  @widget.possible_answers.should be_an(Array)
165
- @widget.validate.should be_false
184
+ @widget.validate_textcaptcha.should be_false
185
+ @widget.should_not be_valid
166
186
  end
167
187
 
168
188
  describe 'and textcaptcha unavailable' do
@@ -176,7 +196,8 @@ describe 'ActsAsTextcaptcha' do
176
196
  @widget.spam_question.should_not be_nil
177
197
  @widget.possible_answers.should_not be_nil
178
198
  @widget.possible_answers.should be_an(Array)
179
- @widget.validate.should be_false
199
+ @widget.validate_textcaptcha.should be_false
200
+ @widget.should_not be_valid
180
201
  end
181
202
  end
182
203
  end
data/spec/schema.rb CHANGED
@@ -3,15 +3,15 @@ ActiveRecord::Schema.define(:version => 0) do
3
3
  create_table :widgets, :force => true do |t|
4
4
  t.string :name
5
5
  end
6
-
6
+
7
7
  create_table :comments, :force => true do |t|
8
8
  t.string :name
9
- end
10
-
9
+ end
10
+
11
11
  create_table :reviews, :force => true do |t|
12
12
  t.string :name
13
13
  end
14
-
14
+
15
15
  create_table :notes, :force => true do |t|
16
16
  t.string :name
17
17
  end
data/spec/spec_helper.rb CHANGED
@@ -1,22 +1,13 @@
1
- # This file is copied to ~/spec when you run 'ruby script/generate rspec'
2
- # from the project root directory.
3
1
  ENV["RAILS_ENV"] ||= 'test'
2
+
4
3
  require 'rubygems'
5
4
  require 'spec'
6
5
  require 'active_record'
7
6
  require 'spec/autorun'
8
7
 
9
- # Uncomment the next line to use webrat's matchers
10
- #require 'webrat/integrations/rspec-rails'
11
-
12
- # Requires supporting files with custom matchers and macros, etc,
13
- # in ./support/ and its subdirectories.
14
- Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
15
-
16
8
  require File.dirname(__FILE__) + '/../lib/acts_as_textcaptcha'
17
9
  require File.dirname(__FILE__) + '/../init.rb'
18
10
 
19
- config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
20
- ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
11
+ ActiveRecord::Base.establish_connection(YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))[ENV['DB'] || 'sqlite3'])
21
12
 
22
13
  load(File.dirname(__FILE__) + "/schema.rb")
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_textcaptcha
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
- - 1
8
7
  - 2
9
8
  - 1
10
- version: 1.2.1
9
+ - 1
10
+ version: 2.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthew Hutchinson
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-07-29 00:00:00 +01:00
18
+ date: 2010-09-02 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -47,21 +47,15 @@ extra_rdoc_files:
47
47
  - LICENSE
48
48
  - README.rdoc
49
49
  files:
50
- - .gitignore
50
+ - lib/acts_as_textcaptcha.rb
51
+ - lib/acts_as_textcaptcha/framework/rails2.rb
52
+ - lib/acts_as_textcaptcha/framework/rails3.rb
53
+ - lib/acts_as_textcaptcha/textcaptcha.rb
54
+ - lib/acts_as_textcaptcha/textcaptcha_helper.rb
51
55
  - LICENSE
52
56
  - README.rdoc
53
- - Rakefile
54
- - VERSION
55
- - acts_as_textcaptcha.gemspec
56
- - config/textcaptcha.yml
57
- - init.rb
58
- - lib/acts_as_textcaptcha.rb
59
- - lib/textcaptcha_helper.rb
60
- - rails/init.rb
61
57
  - spec/acts_as_textcaptcha_spec.rb
62
- - spec/database.yml
63
58
  - spec/schema.rb
64
- - spec/spec.opts
65
59
  - spec/spec_helper.rb
66
60
  has_rdoc: true
67
61
  homepage: http://github.com/matthutchinson/acts_as_textcaptcha
data/.gitignore DELETED
@@ -1,5 +0,0 @@
1
- acts_as_textcaptcha.sqlite3.db
2
- *.gem
3
- *.db
4
- doc
5
- coverage
data/Rakefile DELETED
@@ -1,81 +0,0 @@
1
- require 'rake'
2
- require 'rake/rdoctask'
3
- require 'spec/rake/spectask'
4
- require 'spec'
5
-
6
- desc 'Default: run spec tests.'
7
- task :default => :spec
8
- task :test => :spec
9
-
10
- desc "Run all specs"
11
- Spec::Rake::SpecTask.new(:spec) do |t|
12
- t.spec_files = FileList['spec/*_spec.rb']
13
- t.spec_opts = ['--options', 'spec/spec.opts']
14
- end
15
-
16
- desc "Run all specs with RCov"
17
- Spec::Rake::SpecTask.new(:rcov) do |t|
18
- t.spec_files = FileList['spec/*_spec.rb']
19
- t.rcov = true
20
- t.rcov_opts = ['--exclude', 'spec']
21
- end
22
-
23
- desc 'Generate documentation for the acts_as_textcaptcha plugin.'
24
- Rake::RDocTask.new(:rdoc) do |rdoc|
25
- rdoc.rdoc_dir = 'doc'
26
- rdoc.title = 'acts_as_textcaptcha'
27
- rdoc.options << '--line-numbers' << '--inline-source'
28
- rdoc.rdoc_files.include('README.rdoc', 'LICENSE')
29
- rdoc.rdoc_files.include('lib/**/*.rb')
30
- end
31
-
32
- begin
33
- require 'jeweler'
34
- Jeweler::Tasks.new do |gemspec|
35
- gemspec.name = "acts_as_textcaptcha"
36
- gemspec.summary = "Spam protection for your models via logic questions and the excellent textcaptcha.com api"
37
- gemspec.description = "Spam protection for your ActiveRecord models using logic questions and the excellent textcaptcha api. See textcaptcha.com for more details and to get your api key.
38
- The logic questions are aimed at a child's age of 7, so can be solved easily by all but the most cognitively impaired users. As they involve human logic, such questions cannot be solved by a robot.
39
- For more reasons on why logic questions are useful, see here; http://textcaptcha.com/why"
40
- gemspec.email = "matt@hiddenloop.com"
41
- gemspec.homepage = "http://github.com/matthutchinson/acts_as_textcaptcha"
42
- gemspec.authors = ["Matthew Hutchinson"]
43
-
44
- gemspec.add_dependency('bcrypt-ruby', '>= 2.1.2')
45
- end
46
- Jeweler::GemcutterTasks.new
47
- rescue LoadError
48
- end
49
-
50
- begin
51
- require 'metric_fu'
52
- MetricFu::Configuration.run do |config|
53
- config.metrics = [ :churn, :saikuro, :flog, :flay, :reek, :roodi, :rcov ]
54
- config.graphs = [ :flog, :flay, :reek, :roodi, :rcov ]
55
- config.flay = { :dirs_to_flay => ['lib'],
56
- :minimum_score => 75 }
57
- config.flog = { :dirs_to_flog => ['lib'] }
58
- config.reek = { :dirs_to_reek => ['lib'] }
59
- config.roodi = { :dirs_to_roodi => ['lib'] }
60
- config.saikuro = { :output_directory => 'tmp/metric_fu/scratch/saikuro',
61
- :input_directory => ['lib'],
62
- :cyclo => "",
63
- :filter_cyclo => "0",
64
- :warn_cyclo => "5",
65
- :error_cyclo => "7",
66
- :formater => "text" }
67
- config.churn = { :start_date => "1 year ago", :minimum_churn_count => 10 }
68
- config.rcov = { :environment => 'test',
69
- :test_files => ['spec/*_spec.rb'],
70
- :rcov_opts => ["--sort coverage",
71
- "--no-html",
72
- "--text-coverage",
73
- "--no-color",
74
- "--profile",
75
- "--rails",
76
- "--exclude spec"]}
77
- config.graph_engine = :bluff
78
- end
79
- rescue LoadError
80
- puts "Metric Fu not available. Install it with: sudo gem install metric_fu reek roodi flay googlecharts"
81
- end
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.2.1
@@ -1,63 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{acts_as_textcaptcha}
8
- s.version = "1.2.1"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Matthew Hutchinson"]
12
- s.date = %q{2010-07-29}
13
- s.description = %q{Spam protection for your ActiveRecord models using logic questions and the excellent textcaptcha api. See textcaptcha.com for more details and to get your api key.
14
- The logic questions are aimed at a child's age of 7, so can be solved easily by all but the most cognitively impaired users. As they involve human logic, such questions cannot be solved by a robot.
15
- For more reasons on why logic questions are useful, see here; http://textcaptcha.com/why}
16
- s.email = %q{matt@hiddenloop.com}
17
- s.extra_rdoc_files = [
18
- "LICENSE",
19
- "README.rdoc"
20
- ]
21
- s.files = [
22
- ".gitignore",
23
- "LICENSE",
24
- "README.rdoc",
25
- "Rakefile",
26
- "VERSION",
27
- "acts_as_textcaptcha.gemspec",
28
- "config/textcaptcha.yml",
29
- "init.rb",
30
- "lib/acts_as_textcaptcha.rb",
31
- "lib/textcaptcha_helper.rb",
32
- "rails/init.rb",
33
- "spec/acts_as_textcaptcha_spec.rb",
34
- "spec/database.yml",
35
- "spec/schema.rb",
36
- "spec/spec.opts",
37
- "spec/spec_helper.rb"
38
- ]
39
- s.homepage = %q{http://github.com/matthutchinson/acts_as_textcaptcha}
40
- s.rdoc_options = ["--charset=UTF-8"]
41
- s.require_paths = ["lib"]
42
- s.rubygems_version = %q{1.3.7}
43
- s.summary = %q{Spam protection for your models via logic questions and the excellent textcaptcha.com api}
44
- s.test_files = [
45
- "spec/acts_as_textcaptcha_spec.rb",
46
- "spec/schema.rb",
47
- "spec/spec_helper.rb"
48
- ]
49
-
50
- if s.respond_to? :specification_version then
51
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
52
- s.specification_version = 3
53
-
54
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
55
- s.add_runtime_dependency(%q<bcrypt-ruby>, [">= 2.1.2"])
56
- else
57
- s.add_dependency(%q<bcrypt-ruby>, [">= 2.1.2"])
58
- end
59
- else
60
- s.add_dependency(%q<bcrypt-ruby>, [">= 2.1.2"])
61
- end
62
- end
63
-
@@ -1,36 +0,0 @@
1
- development: &non_production_settings
2
- api_key: 8u5ixtdnq9csc84cok0owswgo
3
- # bcrypt can be used to encrypt valid possible answers in your session; http://bcrypt-ruby.rubyforge.org/
4
- # (recommended if you are using cookie session storage)
5
- # NOTE: bcrypt_salt must be a valid bcrypt salt; for security PLEASE CHANGE THIS, open irb and enter; require 'bcrypt'; BCrypt::Engine.generate_salt
6
- bcrypt_salt: $2a$10$j0bmycH.SVfD1b5mpEGPpe
7
- # an optional logarithmic var which determines how computational expensive the hash is to calculate (a cost of 4 is twice as much work as a cost of 3)
8
- bcrypt_cost: 10 # default is 10, must be > 4 (large number means slower encryption)
9
- # if you'd rather NOT use bcrypt, just remove these two settings, bcrypt_salt and bcrypt_cost, valid possible answers will be MD5 digested in your session
10
- questions:
11
- - question: 'Is ice hot or cold?'
12
- answers: 'cold'
13
- - question: 'what color is an orange?'
14
- answers: 'orange'
15
- - question: 'what is two plus 3?'
16
- answers: '5,five'
17
- - question: 'what is 5 times two?'
18
- answers: '10,ten'
19
- - question: 'How many colors in the list, green, brown, foot and blue?'
20
- answers: '3,three'
21
- - question: 'what is Georges name?'
22
- answers: 'george'
23
- - question: '11 minus 1?'
24
- answers: '10,ten'
25
- - question: 'is boiling water hot or cold?'
26
- answers: 'hot'
27
- - question: 'what color is my blue shirt today?'
28
- answers: 'blue'
29
- - question: 'what is 16 plus 4?'
30
- answers: '20,twenty'
31
-
32
- test:
33
- *non_production_settings
34
-
35
- production:
36
- *non_production_settings
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require File.dirname(__FILE__) + '/rails/init'
@@ -1,7 +0,0 @@
1
- module TextcaptchaHelper
2
-
3
- # generates a spam question and possible answers for a model, answers are stored in session[:possible_answers]
4
- def spamify(model)
5
- session[:possible_answers] = model.generate_spam_question unless model.validate_spam_answer
6
- end
7
- end
data/rails/init.rb DELETED
@@ -1,9 +0,0 @@
1
- require 'acts_as_textcaptcha'
2
-
3
- if defined?(ActiveRecord::Base)
4
- ActiveRecord::Base.extend ActsAsTextcaptcha
5
- end
6
-
7
- if defined?(ActionController::Base)
8
- ActionController::Base.send :include, TextcaptchaHelper
9
- end
data/spec/database.yml DELETED
@@ -1,21 +0,0 @@
1
- sqlite:
2
- :adapter: sqlite
3
- :database: acts_as_textcaptcha.sqlite.db
4
-
5
- sqlite3:
6
- :adapter: sqlite3
7
- :database: acts_as_textcaptcha.sqlite3.db
8
-
9
- postgresql:
10
- :adapter: postgresql
11
- :username: postgres
12
- :password: postgres
13
- :database: acts_as_textcaptcha_test
14
- :min_messages: ERROR
15
-
16
- mysql:
17
- :adapter: mysql
18
- :host: localhost
19
- :username: root
20
- :password:
21
- :database: acts_as_textcaptcha_test
data/spec/spec.opts DELETED
@@ -1,2 +0,0 @@
1
- -cfs
2
- --loadby mtime