acts_as_textcaptcha 1.2.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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