Commit 4fe87ea2452f92429c2f7af9d9bc1b54a9928792
Committed by
Joenio Costa
1 parent
fd5c2e61
Exists in
master
and in
8 other branches
Adding recaptcha to comments and article suggestion
(ActionItem2075)
Showing
65 changed files
with
792 additions
and
452 deletions
Show diff stats
app/controllers/my_profile/cms_controller.rb
| @@ -285,7 +285,7 @@ class CmsController < MyProfileController | @@ -285,7 +285,7 @@ class CmsController < MyProfileController | ||
| 285 | @task = SuggestArticle.new(params[:task]) | 285 | @task = SuggestArticle.new(params[:task]) |
| 286 | if request.post? | 286 | if request.post? |
| 287 | @task.target = profile | 287 | @task.target = profile |
| 288 | - if @task.save | 288 | + if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save |
| 289 | session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') | 289 | session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') |
| 290 | redirect_to @back_to | 290 | redirect_to @back_to |
| 291 | end | 291 | end |
app/controllers/public/account_controller.rb
| @@ -2,8 +2,6 @@ class AccountController < ApplicationController | @@ -2,8 +2,6 @@ class AccountController < ApplicationController | ||
| 2 | 2 | ||
| 3 | no_design_blocks | 3 | no_design_blocks |
| 4 | 4 | ||
| 5 | - inverse_captcha :field => 'e_mail' | ||
| 6 | - | ||
| 7 | require_ssl :except => [ :login_popup, :logout_popup, :profile_details ] | 5 | require_ssl :except => [ :login_popup, :logout_popup, :profile_details ] |
| 8 | 6 | ||
| 9 | before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise] | 7 | before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise] |
| @@ -69,7 +67,7 @@ class AccountController < ApplicationController | @@ -69,7 +67,7 @@ class AccountController < ApplicationController | ||
| 69 | @user.person_data = params[:profile_data] | 67 | @user.person_data = params[:profile_data] |
| 70 | @person = Person.new(params[:profile_data]) | 68 | @person = Person.new(params[:profile_data]) |
| 71 | @person.environment = @user.environment | 69 | @person.environment = @user.environment |
| 72 | - if request.post? && params[self.icaptcha_field].blank? | 70 | + if request.post? |
| 73 | @user.signup! | 71 | @user.signup! |
| 74 | owner_role = Role.find_by_name('owner') | 72 | owner_role = Role.find_by_name('owner') |
| 75 | @user.person.affiliate(@user.person, [owner_role]) if owner_role | 73 | @user.person.affiliate(@user.person, [owner_role]) if owner_role |
app/controllers/public/contact_controller.rb
| @@ -4,10 +4,9 @@ class ContactController < PublicController | @@ -4,10 +4,9 @@ class ContactController < PublicController | ||
| 4 | 4 | ||
| 5 | needs_profile | 5 | needs_profile |
| 6 | 6 | ||
| 7 | - inverse_captcha :field => 'e_mail' | ||
| 8 | def new | 7 | def new |
| 9 | @contact | 8 | @contact |
| 10 | - if request.post? && params[self.icaptcha_field].blank? && params[:confirm] == 'true' | 9 | + if request.post? && params[:confirm] == 'true' |
| 11 | @contact = user.build_contact(profile, params[:contact]) | 10 | @contact = user.build_contact(profile, params[:contact]) |
| 12 | @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil | 11 | @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil |
| 13 | @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil | 12 | @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil |
app/controllers/public/content_viewer_controller.rb
| @@ -2,8 +2,6 @@ class ContentViewerController < ApplicationController | @@ -2,8 +2,6 @@ class ContentViewerController < ApplicationController | ||
| 2 | 2 | ||
| 3 | needs_profile | 3 | needs_profile |
| 4 | 4 | ||
| 5 | - inverse_captcha :field => 'e_mail' | ||
| 6 | - | ||
| 7 | helper ProfileHelper | 5 | helper ProfileHelper |
| 8 | helper TagsHelper | 6 | helper TagsHelper |
| 9 | 7 | ||
| @@ -76,7 +74,7 @@ class ContentViewerController < ApplicationController | @@ -76,7 +74,7 @@ class ContentViewerController < ApplicationController | ||
| 76 | 74 | ||
| 77 | @form_div = params[:form] | 75 | @form_div = params[:form] |
| 78 | 76 | ||
| 79 | - if params[:comment] && params[self.icaptcha_field].blank? && params[:confirm] == 'true' | 77 | + if params[:comment] && params[:confirm] == 'true' |
| 80 | @comment = Comment.new(params[:comment]) | 78 | @comment = Comment.new(params[:comment]) |
| 81 | if request.post? && @page.accept_comments? | 79 | if request.post? && @page.accept_comments? |
| 82 | add_comment | 80 | add_comment |
| @@ -121,7 +119,7 @@ class ContentViewerController < ApplicationController | @@ -121,7 +119,7 @@ class ContentViewerController < ApplicationController | ||
| 121 | def add_comment | 119 | def add_comment |
| 122 | @comment.author = user if logged_in? | 120 | @comment.author = user if logged_in? |
| 123 | @comment.article = @page | 121 | @comment.article = @page |
| 124 | - if @comment.save | 122 | + if (@comment.reply_of_id || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save |
| 125 | @page.touch | 123 | @page.touch |
| 126 | @comment = nil # clear the comment form | 124 | @comment = nil # clear the comment form |
| 127 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] | 125 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] |
app/models/comment.rb
| 1 | class Comment < ActiveRecord::Base | 1 | class Comment < ActiveRecord::Base |
| 2 | 2 | ||
| 3 | - has_captcha | ||
| 4 | - | ||
| 5 | track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target | 3 | track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target |
| 6 | 4 | ||
| 7 | validates_presence_of :title, :body | 5 | validates_presence_of :title, :body |
app/models/suggest_article.rb
| 1 | class SuggestArticle < Task | 1 | class SuggestArticle < Task |
| 2 | 2 | ||
| 3 | - has_captcha | ||
| 4 | - | ||
| 5 | validates_presence_of :target_id, :article_name, :email, :name, :article_body | 3 | validates_presence_of :target_id, :article_name, :email, :name, :article_body |
| 6 | 4 | ||
| 7 | settings_items :email, :type => String | 5 | settings_items :email, :type => String |
app/views/account/_signup_form.rhtml
| @@ -7,8 +7,7 @@ | @@ -7,8 +7,7 @@ | ||
| 7 | </div> | 7 | </div> |
| 8 | <% end %> | 8 | <% end %> |
| 9 | 9 | ||
| 10 | -<% labelled_form_for :user, @user do |f| %> | ||
| 11 | -<%= icaptcha_field() %> | 10 | +<% labelled_form_for :user, @user, :html => { :multipart => true } do |f| %> |
| 12 | 11 | ||
| 13 | <%= hidden_field_tag :invitation_code, @invitation_code %> | 12 | <%= hidden_field_tag :invitation_code, @invitation_code %> |
| 14 | 13 |
app/views/cms/suggest_an_article.rhtml
| @@ -18,13 +18,10 @@ | @@ -18,13 +18,10 @@ | ||
| 18 | 18 | ||
| 19 | <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => :task, :abstract_method => 'article_abstract', :body_method => 'article_body'} %> | 19 | <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => :task, :abstract_method => 'article_abstract', :body_method => 'article_body'} %> |
| 20 | 20 | ||
| 21 | - <div id="captcha"> | ||
| 22 | - <%= labelled_form_field(_("What is the result of '%s = ?'") % @task.captcha.task, text_field(:task, 'captcha_solution')) %> | ||
| 23 | - <%= hidden_field :task, :captcha_secret %> | ||
| 24 | - <br style="clear: both;"> | ||
| 25 | - </div> | ||
| 26 | - | ||
| 27 | <%= hidden_field_tag('back_to', @back_to) %> | 21 | <%= hidden_field_tag('back_to', @back_to) %> |
| 22 | + | ||
| 23 | + <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> | ||
| 24 | + | ||
| 28 | <% button_bar do %> | 25 | <% button_bar do %> |
| 29 | <%= submit_button :save, _('Save') %> | 26 | <%= submit_button :save, _('Save') %> |
| 30 | <%= button :cancel, _('Cancel'), @back_to %> | 27 | <%= button :cancel, _('Cancel'), @back_to %> |
app/views/contact/new.rhtml
| @@ -4,7 +4,6 @@ | @@ -4,7 +4,6 @@ | ||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | <% labelled_form_for :contact, @contact do |f| %> | 6 | <% labelled_form_for :contact, @contact do |f| %> |
| 7 | - <%= icaptcha_field() %> | ||
| 8 | <%= hidden_field_tag(:confirm, 'false') %> | 7 | <%= hidden_field_tag(:confirm, 'false') %> |
| 9 | 8 | ||
| 10 | <%= required_fields_message %> | 9 | <%= required_fields_message %> |
app/views/content_viewer/_comment_form.rhtml
| @@ -20,7 +20,6 @@ | @@ -20,7 +20,6 @@ | ||
| 20 | </h4> | 20 | </h4> |
| 21 | 21 | ||
| 22 | <% form_tag( url_for(@page.view_url.merge({:only_path => true})), { :class => 'comment_form' } ) do %> | 22 | <% form_tag( url_for(@page.view_url.merge({:only_path => true})), { :class => 'comment_form' } ) do %> |
| 23 | - <%= icaptcha_field() %> | ||
| 24 | <%= hidden_field_tag(:confirm, 'false') %> | 23 | <%= hidden_field_tag(:confirm, 'false') %> |
| 25 | 24 | ||
| 26 | <%= required_fields_message %> | 25 | <%= required_fields_message %> |
| @@ -29,7 +28,6 @@ | @@ -29,7 +28,6 @@ | ||
| 29 | 28 | ||
| 30 | <%= required labelled_form_field(_('Name'), text_field(:comment, :name)) %> | 29 | <%= required labelled_form_field(_('Name'), text_field(:comment, :name)) %> |
| 31 | <%= required labelled_form_field(_('e-mail'), text_field(:comment, :email)) %> | 30 | <%= required labelled_form_field(_('e-mail'), text_field(:comment, :email)) %> |
| 32 | - | ||
| 33 | <p> | 31 | <p> |
| 34 | <%= _('If you are a registered user, you can login and be automatically recognized.') %> | 32 | <%= _('If you are a registered user, you can login and be automatically recognized.') %> |
| 35 | </p> | 33 | </p> |
| @@ -39,8 +37,7 @@ | @@ -39,8 +37,7 @@ | ||
| 39 | <%= required labelled_form_field(_('Title'), text_field(:comment, :title)) %> | 37 | <%= required labelled_form_field(_('Title'), text_field(:comment, :title)) %> |
| 40 | <%= required labelled_form_field(_('Enter your comment'), text_area(:comment, :body, :rows => 5)) %> | 38 | <%= required labelled_form_field(_('Enter your comment'), text_area(:comment, :body, :rows => 5)) %> |
| 41 | 39 | ||
| 42 | - <%= required labelled_form_field(_("What is the result of '%s = ?'") % @comment.captcha.task, text_field(:comment, :captcha_solution)) %> | ||
| 43 | - <%= hidden_field(:comment, :captcha_secret) %> | 40 | + <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) unless logged_in? %> |
| 44 | 41 | ||
| 45 | <% button_bar do %> | 42 | <% button_bar do %> |
| 46 | <%= submit_button('add', _('Post comment'), :onclick => "this.form.confirm.value = 'true'; this.disabled = true; this.form.submit(); return true;") %> | 43 | <%= submit_button('add', _('Post comment'), :onclick => "this.form.confirm.value = 'true'; this.disabled = true; this.form.submit(); return true;") %> |
app/views/profile_editor/edit.rhtml
features/comment.feature
| @@ -82,11 +82,6 @@ Feature: comment | @@ -82,11 +82,6 @@ Feature: comment | ||
| 82 | And I should be exactly on /booking/article-with-comment | 82 | And I should be exactly on /booking/article-with-comment |
| 83 | And I should be moved to anchor "comment_form" | 83 | And I should be moved to anchor "comment_form" |
| 84 | 84 | ||
| 85 | - Scenario: ask captcha question | ||
| 86 | - Given I am on /booking/article-with-comment | ||
| 87 | - When I follow "Post a comment" within ".post-comment-button" | ||
| 88 | - Then I should see "What is the result of " | ||
| 89 | - | ||
| 90 | @selenium | 85 | @selenium |
| 91 | Scenario: keep comments field filled while trying to do a comment | 86 | Scenario: keep comments field filled while trying to do a comment |
| 92 | Given I am on /booking/article-with-comment | 87 | Given I am on /booking/article-with-comment |
features/comment_reply.feature
| @@ -64,8 +64,7 @@ Feature: comment | @@ -64,8 +64,7 @@ Feature: comment | ||
| 64 | 64 | ||
| 65 | @selenium | 65 | @selenium |
| 66 | Scenario: reply a comment | 66 | Scenario: reply a comment |
| 67 | - Given skip comments captcha | ||
| 68 | - And I go to /booking/another-article | 67 | + Given I go to /booking/another-article |
| 69 | And I follow "Reply" within ".comment-balloon" | 68 | And I follow "Reply" within ".comment-balloon" |
| 70 | And I fill in "Name" within "comment-balloon" with "Joey" | 69 | And I fill in "Name" within "comment-balloon" with "Joey" |
| 71 | And I fill in "e-mail" within "comment-balloon" with "joey@ramones.com" | 70 | And I fill in "e-mail" within "comment-balloon" with "joey@ramones.com" |
features/step_definitions/noosfero_steps.rb
| @@ -368,7 +368,6 @@ Given /^the articles of "(.+)" are moderated$/ do |organization| | @@ -368,7 +368,6 @@ Given /^the articles of "(.+)" are moderated$/ do |organization| | ||
| 368 | end | 368 | end |
| 369 | 369 | ||
| 370 | Given /^the following comments?$/ do |table| | 370 | Given /^the following comments?$/ do |table| |
| 371 | - Comment.skip_captcha! | ||
| 372 | table.hashes.each do |item| | 371 | table.hashes.each do |item| |
| 373 | data = item.dup | 372 | data = item.dup |
| 374 | article = Article.find_by_name(data.delete("article")) | 373 | article = Article.find_by_name(data.delete("article")) |
| @@ -388,7 +387,6 @@ Given /^the community "(.+)" is closed$/ do |community| | @@ -388,7 +387,6 @@ Given /^the community "(.+)" is closed$/ do |community| | ||
| 388 | end | 387 | end |
| 389 | 388 | ||
| 390 | Given /^someone suggested the following article to be published$/ do |table| | 389 | Given /^someone suggested the following article to be published$/ do |table| |
| 391 | - SuggestArticle.skip_captcha! | ||
| 392 | table.hashes.map{|item| item.dup}.each do |item| | 390 | table.hashes.map{|item| item.dup}.each do |item| |
| 393 | target = Community[item.delete('target')] | 391 | target = Community[item.delete('target')] |
| 394 | task = SuggestArticle.create!(:target => target, :data => item) | 392 | task = SuggestArticle.create!(:target => target, :data => item) |
| @@ -422,10 +420,6 @@ Given /^the environment domain is "([^\"]*)"$/ do |domain| | @@ -422,10 +420,6 @@ Given /^the environment domain is "([^\"]*)"$/ do |domain| | ||
| 422 | d.save(false) | 420 | d.save(false) |
| 423 | end | 421 | end |
| 424 | 422 | ||
| 425 | -Given /^skip comments captcha$/ do | ||
| 426 | - Comment.any_instance.stubs(:skip_captcha?).returns(true) | ||
| 427 | -end | ||
| 428 | - | ||
| 429 | When /^([^\']*)'s account is activated$/ do |person| | 423 | When /^([^\']*)'s account is activated$/ do |person| |
| 430 | Person.find_by_name(person).user.activate | 424 | Person.find_by_name(person).user.activate |
| 431 | end | 425 | end |
features/step_definitions/selenium_steps.rb
| @@ -93,12 +93,6 @@ When /^I type "([^\"]*)" in TinyMCE field "([^\"]*)"$/ do |value, field_id| | @@ -93,12 +93,6 @@ When /^I type "([^\"]*)" in TinyMCE field "([^\"]*)"$/ do |value, field_id| | ||
| 93 | response.selenium.type("dom=document.getElementById('#{field_id}_ifr').contentDocument.body", value) | 93 | response.selenium.type("dom=document.getElementById('#{field_id}_ifr').contentDocument.body", value) |
| 94 | end | 94 | end |
| 95 | 95 | ||
| 96 | -When /^I answer the captcha$/ do | ||
| 97 | - question = response.selenium.get_text("//label[@for='task_captcha_solution']").match(/What is the result of '(.+) = \?'/)[1] | ||
| 98 | - answer = eval(question) | ||
| 99 | - response.selenium.type("id=task_captcha_solution", answer) | ||
| 100 | -end | ||
| 101 | - | ||
| 102 | When /^I refresh the page$/ do | 96 | When /^I refresh the page$/ do |
| 103 | response.selenium.refresh | 97 | response.selenium.refresh |
| 104 | end | 98 | end |
features/suggest_article.feature
| @@ -31,7 +31,6 @@ Feature: suggest article | @@ -31,7 +31,6 @@ Feature: suggest article | ||
| 31 | And I fill in "Email" with "someguy@somewhere.com" | 31 | And I fill in "Email" with "someguy@somewhere.com" |
| 32 | And I type "This is my suggestion's lead" in TinyMCE field "task_article_abstract" | 32 | And I type "This is my suggestion's lead" in TinyMCE field "task_article_abstract" |
| 33 | And I type "I like free software" in TinyMCE field "task_article_body" | 33 | And I type "I like free software" in TinyMCE field "task_article_body" |
| 34 | - And I answer the captcha | ||
| 35 | And I press "Save" | 34 | And I press "Save" |
| 36 | And I am logged in as "joaosilva" | 35 | And I am logged in as "joaosilva" |
| 37 | And I go to Sample Community's control panel | 36 | And I go to Sample Community's control panel |
public/javascripts/application.js
| @@ -662,6 +662,7 @@ function add_comment_reply_form(button, comment_id) { | @@ -662,6 +662,7 @@ function add_comment_reply_form(button, comment_id) { | ||
| 662 | var f = container.find('.comment_form'); | 662 | var f = container.find('.comment_form'); |
| 663 | if (f.length == 0) { | 663 | if (f.length == 0) { |
| 664 | f = jQuery('#page-comment-form .comment_form').clone(); | 664 | f = jQuery('#page-comment-form .comment_form').clone(); |
| 665 | + f.find('#dynamic_recaptcha').remove(); | ||
| 665 | f.find('.fieldWithErrors').map(function() { jQuery(this).replaceWith(jQuery(this).contents()); }); | 666 | f.find('.fieldWithErrors').map(function() { jQuery(this).replaceWith(jQuery(this).contents()); }); |
| 666 | f.prepend('<input type="hidden" name="comment[reply_of_id]" value="' + comment_id + '" />'); | 667 | f.prepend('<input type="hidden" name="comment[reply_of_id]" value="' + comment_id + '" />'); |
| 667 | container.append(f); | 668 | container.append(f); |
public/stylesheets/application.css
| @@ -6136,3 +6136,30 @@ h1#agenda-title { | @@ -6136,3 +6136,30 @@ h1#agenda-title { | ||
| 6136 | #user a#pending-tasks-count { | 6136 | #user a#pending-tasks-count { |
| 6137 | color: #FFFFFF; | 6137 | color: #FFFFFF; |
| 6138 | } | 6138 | } |
| 6139 | + | ||
| 6140 | +/* Captcha */ | ||
| 6141 | + | ||
| 6142 | +.comment_reply #recaptcha_area { | ||
| 6143 | + margin-bottom: 3px !important; | ||
| 6144 | +} | ||
| 6145 | + | ||
| 6146 | +.comment_reply .recaptchatable tr td + td + td { | ||
| 6147 | + display: none !important; | ||
| 6148 | +} | ||
| 6149 | + | ||
| 6150 | +.comment_reply .recaptcha-container { | ||
| 6151 | + width: 100%; | ||
| 6152 | + overflow: hidden; | ||
| 6153 | +} | ||
| 6154 | + | ||
| 6155 | +.comment_reply .recaptcha-container:hover { | ||
| 6156 | + overflow: visible; | ||
| 6157 | +} | ||
| 6158 | + | ||
| 6159 | +.comment_reply .recaptcha-container tr:hover td { | ||
| 6160 | + background: transparent; | ||
| 6161 | +} | ||
| 6162 | + | ||
| 6163 | +.comment_reply .recaptcha_image_cell { | ||
| 6164 | + background: transparent !important; | ||
| 6165 | +} |
test/functional/account_controller_test.rb
| @@ -571,17 +571,6 @@ class AccountControllerTest < Test::Unit::TestCase | @@ -571,17 +571,6 @@ class AccountControllerTest < Test::Unit::TestCase | ||
| 571 | 571 | ||
| 572 | # end of enterprise activation tests | 572 | # end of enterprise activation tests |
| 573 | 573 | ||
| 574 | - should 'not be able to signup while inverse captcha field filled' do | ||
| 575 | - assert_no_difference User, :count do | ||
| 576 | - new_user({}, @controller.icaptcha_field => 'bli@bla.email.foo') | ||
| 577 | - end | ||
| 578 | - end | ||
| 579 | - | ||
| 580 | - should 'render inverse captcha field' do | ||
| 581 | - get :signup | ||
| 582 | - assert_tag :tag => 'input', :attributes => { :type => 'text', :name => @controller.icaptcha_field } | ||
| 583 | - end | ||
| 584 | - | ||
| 585 | should 'use the current environment for the template of user' do | 574 | should 'use the current environment for the template of user' do |
| 586 | template = create_user('test_template', :email => 'test@bli.com', :password => 'pass', :password_confirmation => 'pass').person | 575 | template = create_user('test_template', :email => 'test@bli.com', :password => 'pass', :password_confirmation => 'pass').person |
| 587 | template.boxes.destroy_all | 576 | template.boxes.destroy_all |
test/functional/cms_controller_test.rb
| @@ -1320,7 +1320,6 @@ class CmsControllerTest < Test::Unit::TestCase | @@ -1320,7 +1320,6 @@ class CmsControllerTest < Test::Unit::TestCase | ||
| 1320 | should 'create a task suggest task to a profile' do | 1320 | should 'create a task suggest task to a profile' do |
| 1321 | c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) | 1321 | c = Community.create!(:name => 'test comm', :identifier => 'test_comm', :moderated_articles => true) |
| 1322 | 1322 | ||
| 1323 | - SuggestArticle.any_instance.stubs(:skip_captcha?).returns(true) | ||
| 1324 | assert_difference SuggestArticle, :count do | 1323 | assert_difference SuggestArticle, :count do |
| 1325 | post :suggest_an_article, :profile => c.identifier, :back_to => 'action_view', :task => {:article_name => 'some name', :article_body => 'some body', :email => 'some@localhost.com', :name => 'some name'} | 1324 | post :suggest_an_article, :profile => c.identifier, :back_to => 'action_view', :task => {:article_name => 'some name', :article_body => 'some body', :email => 'some@localhost.com', :name => 'some name'} |
| 1326 | end | 1325 | end |
test/functional/contact_controller_test.rb
| @@ -74,13 +74,6 @@ class ContactControllerTest < Test::Unit::TestCase | @@ -74,13 +74,6 @@ class ContactControllerTest < Test::Unit::TestCase | ||
| 74 | assert_no_tag :tag => 'select', :attributes => {:name => 'state'} | 74 | assert_no_tag :tag => 'select', :attributes => {:name => 'state'} |
| 75 | end | 75 | end |
| 76 | 76 | ||
| 77 | - should 'not be able to post contact while inverse captcha field filled' do | ||
| 78 | - post :new, :profile => enterprise.identifier, @controller.icaptcha_field => 'filled', :contact => {:subject => 'Hi', :message => 'Hi, all', :state => '', :city => ''} | ||
| 79 | - | ||
| 80 | - assert_response :success | ||
| 81 | - assert_template 'new' | ||
| 82 | - end | ||
| 83 | - | ||
| 84 | should 'not allow if not logged' do | 77 | should 'not allow if not logged' do |
| 85 | logout | 78 | logout |
| 86 | get :new, :profile => profile.identifier | 79 | get :new, :profile => profile.identifier |
| @@ -93,12 +86,6 @@ class ContactControllerTest < Test::Unit::TestCase | @@ -93,12 +86,6 @@ class ContactControllerTest < Test::Unit::TestCase | ||
| 93 | assert_equal Person['contact_test_user'], assigns(:contact).sender | 86 | assert_equal Person['contact_test_user'], assigns(:contact).sender |
| 94 | end | 87 | end |
| 95 | 88 | ||
| 96 | - should 'send contact while inverse captcha field not filled' do | ||
| 97 | - post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :message => 'Hi, all', :state => '', :city => ''}, :confirm => 'true' | ||
| 98 | - assert_response :redirect | ||
| 99 | - assert_redirected_to :action => 'new' | ||
| 100 | - end | ||
| 101 | - | ||
| 102 | should 'deliver contact if subject and message are filled' do | 89 | should 'deliver contact if subject and message are filled' do |
| 103 | post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :message => 'Hi, all'}, :confirm => 'true' | 90 | post :new, :profile => enterprise.identifier, :contact => {:subject => 'Hi', :message => 'Hi, all'}, :confirm => 'true' |
| 104 | assert_response :redirect | 91 | assert_response :redirect |
test/functional/content_viewer_controller_test.rb
| @@ -15,7 +15,6 @@ class ContentViewerControllerTest < Test::Unit::TestCase | @@ -15,7 +15,6 @@ class ContentViewerControllerTest < Test::Unit::TestCase | ||
| 15 | 15 | ||
| 16 | @profile = create_user('testinguser').person | 16 | @profile = create_user('testinguser').person |
| 17 | @environment = @profile.environment | 17 | @environment = @profile.environment |
| 18 | - Comment.skip_captcha! | ||
| 19 | end | 18 | end |
| 20 | attr_reader :profile, :environment | 19 | attr_reader :profile, :environment |
| 21 | 20 | ||
| @@ -188,17 +187,6 @@ class ContentViewerControllerTest < Test::Unit::TestCase | @@ -188,17 +187,6 @@ class ContentViewerControllerTest < Test::Unit::TestCase | ||
| 188 | end | 187 | end |
| 189 | end | 188 | end |
| 190 | 189 | ||
| 191 | - should 'not be able to post comment while inverse captcha field filled' do | ||
| 192 | - profile = create_user('popstar').person | ||
| 193 | - page = profile.articles.build(:name => 'myarticle', :body => 'the body of the text') | ||
| 194 | - page.save! | ||
| 195 | - profile.home_page = page; profile.save! | ||
| 196 | - | ||
| 197 | - assert_no_difference Comment, :count do | ||
| 198 | - post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], @controller.icaptcha_field => 'filled', :comment => { :title => 'crap!', :body => 'I think that this article is crap', :name => 'Anonymous coward', :email => 'coward@anonymous.com' } | ||
| 199 | - end | ||
| 200 | - end | ||
| 201 | - | ||
| 202 | should 'be able to remove comments if is moderator' do | 190 | should 'be able to remove comments if is moderator' do |
| 203 | commenter = create_user('commenter_user').person | 191 | commenter = create_user('commenter_user').person |
| 204 | community = Community.create!(:name => 'Community test', :identifier => 'community-test') | 192 | community = Community.create!(:name => 'Community test', :identifier => 'community-test') |
| @@ -212,15 +200,6 @@ class ContentViewerControllerTest < Test::Unit::TestCase | @@ -212,15 +200,6 @@ class ContentViewerControllerTest < Test::Unit::TestCase | ||
| 212 | end | 200 | end |
| 213 | end | 201 | end |
| 214 | 202 | ||
| 215 | - should 'render inverse captcha field' do | ||
| 216 | - profile = create_user('popstar').person | ||
| 217 | - page = profile.articles.build(:name => 'myarticle', :body => 'the body of the text') | ||
| 218 | - page.save! | ||
| 219 | - profile.home_page = page; profile.save! | ||
| 220 | - get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ] | ||
| 221 | - assert_tag :tag => 'input', :attributes => { :type => 'text', :name => @controller.icaptcha_field } | ||
| 222 | - end | ||
| 223 | - | ||
| 224 | should 'filter html content from body' do | 203 | should 'filter html content from body' do |
| 225 | login_as @profile.identifier | 204 | login_as @profile.identifier |
| 226 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | 205 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') |
test/functional/search_controller_test.rb
| @@ -17,7 +17,6 @@ class SearchControllerTest < Test::Unit::TestCase | @@ -17,7 +17,6 @@ class SearchControllerTest < Test::Unit::TestCase | ||
| 17 | domain.save! | 17 | domain.save! |
| 18 | 18 | ||
| 19 | @product_category = fast_create(ProductCategory) | 19 | @product_category = fast_create(ProductCategory) |
| 20 | - Comment.skip_captcha! | ||
| 21 | end | 20 | end |
| 22 | 21 | ||
| 23 | def create_article_with_optional_category(name, profile, category = nil) | 22 | def create_article_with_optional_category(name, profile, category = nil) |
test/functional/tasks_controller_test.rb
| @@ -238,7 +238,6 @@ class TasksControllerTest < Test::Unit::TestCase | @@ -238,7 +238,6 @@ class TasksControllerTest < Test::Unit::TestCase | ||
| 238 | c = fast_create(Community) | 238 | c = fast_create(Community) |
| 239 | c.add_admin profile | 239 | c.add_admin profile |
| 240 | @controller.stubs(:profile).returns(c) | 240 | @controller.stubs(:profile).returns(c) |
| 241 | - SuggestArticle.skip_captcha! | ||
| 242 | t = SuggestArticle.create!(:article_name => 'test name', :article_abstract => 'test abstract', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) | 241 | t = SuggestArticle.create!(:article_name => 'test name', :article_abstract => 'test abstract', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) |
| 243 | 242 | ||
| 244 | get :index | 243 | get :index |
| @@ -251,7 +250,6 @@ class TasksControllerTest < Test::Unit::TestCase | @@ -251,7 +250,6 @@ class TasksControllerTest < Test::Unit::TestCase | ||
| 251 | c = fast_create(Community) | 250 | c = fast_create(Community) |
| 252 | c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) | 251 | c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) |
| 253 | @controller.stubs(:profile).returns(c) | 252 | @controller.stubs(:profile).returns(c) |
| 254 | - SuggestArticle.skip_captcha! | ||
| 255 | t = SuggestArticle.create!(:article_name => 'test name', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) | 253 | t = SuggestArticle.create!(:article_name => 'test name', :article_body => 'test body', :name => 'some name', :email => 'test@localhost.com', :target => c) |
| 256 | 254 | ||
| 257 | post :close, :tasks => {t.id => { :task => {}, :decision => "finish"}} | 255 | post :close, :tasks => {t.id => { :task => {}, :decision => "finish"}} |
| @@ -263,7 +261,6 @@ class TasksControllerTest < Test::Unit::TestCase | @@ -263,7 +261,6 @@ class TasksControllerTest < Test::Unit::TestCase | ||
| 263 | c = fast_create(Community) | 261 | c = fast_create(Community) |
| 264 | c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) | 262 | c.affiliate(profile, Profile::Roles.all_roles(profile.environment.id)) |
| 265 | @controller.stubs(:profile).returns(c) | 263 | @controller.stubs(:profile).returns(c) |
| 266 | - SuggestArticle.skip_captcha! | ||
| 267 | t = SuggestArticle.new | 264 | t = SuggestArticle.new |
| 268 | t.article_name = 'test name' | 265 | t.article_name = 'test name' |
| 269 | t.article_body = 'test body' | 266 | t.article_body = 'test body' |
test/unit/article_test.rb
| @@ -6,7 +6,6 @@ class ArticleTest < Test::Unit::TestCase | @@ -6,7 +6,6 @@ class ArticleTest < Test::Unit::TestCase | ||
| 6 | 6 | ||
| 7 | def setup | 7 | def setup |
| 8 | @profile = create_user('testing').person | 8 | @profile = create_user('testing').person |
| 9 | - Comment.skip_captcha! | ||
| 10 | end | 9 | end |
| 11 | attr_reader :profile | 10 | attr_reader :profile |
| 12 | 11 |
test/unit/category_finder_test.rb
| @@ -7,7 +7,6 @@ class CategoryFinderTest < ActiveSupport::TestCase | @@ -7,7 +7,6 @@ class CategoryFinderTest < ActiveSupport::TestCase | ||
| 7 | @finder = CategoryFinder.new(@category) | 7 | @finder = CategoryFinder.new(@category) |
| 8 | @product_category = fast_create(ProductCategory, :name => 'Products') | 8 | @product_category = fast_create(ProductCategory, :name => 'Products') |
| 9 | 9 | ||
| 10 | - Comment.skip_captcha! | ||
| 11 | end | 10 | end |
| 12 | 11 | ||
| 13 | should 'search for articles in a specific category' do | 12 | should 'search for articles in a specific category' do |
test/unit/category_test.rb
| @@ -5,7 +5,6 @@ class CategoryTest < Test::Unit::TestCase | @@ -5,7 +5,6 @@ class CategoryTest < Test::Unit::TestCase | ||
| 5 | 5 | ||
| 6 | def setup | 6 | def setup |
| 7 | @env = fast_create(Environment) | 7 | @env = fast_create(Environment) |
| 8 | - Comment.skip_captcha! | ||
| 9 | end | 8 | end |
| 10 | 9 | ||
| 11 | def test_mandatory_field_name | 10 | def test_mandatory_field_name |
test/unit/comment_notifier_test.rb
| @@ -10,7 +10,6 @@ class CommentNotifierTest < Test::Unit::TestCase | @@ -10,7 +10,6 @@ class CommentNotifierTest < Test::Unit::TestCase | ||
| 10 | ActionMailer::Base.deliveries = [] | 10 | ActionMailer::Base.deliveries = [] |
| 11 | @profile = create_user('user_comment_test').person | 11 | @profile = create_user('user_comment_test').person |
| 12 | @article = fast_create(Article, :name => 'Article test', :profile_id => @profile.id, :notify_comments => true) | 12 | @article = fast_create(Article, :name => 'Article test', :profile_id => @profile.id, :notify_comments => true) |
| 13 | - Comment.skip_captcha! | ||
| 14 | end | 13 | end |
| 15 | 14 | ||
| 16 | should 'deliver mail after make aarticle commment' do | 15 | should 'deliver mail after make aarticle commment' do |
test/unit/comment_test.rb
| @@ -3,7 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' | @@ -3,7 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' | ||
| 3 | class CommentTest < Test::Unit::TestCase | 3 | class CommentTest < Test::Unit::TestCase |
| 4 | 4 | ||
| 5 | def setup | 5 | def setup |
| 6 | - Comment.skip_captcha! | ||
| 7 | end | 6 | end |
| 8 | 7 | ||
| 9 | should 'have a name and require it' do | 8 | should 'have a name and require it' do |
| @@ -331,12 +330,4 @@ class CommentTest < Test::Unit::TestCase | @@ -331,12 +330,4 @@ class CommentTest < Test::Unit::TestCase | ||
| 331 | assert_nil Comment.new(:email => 'my@email.com').author_url | 330 | assert_nil Comment.new(:email => 'my@email.com').author_url |
| 332 | end | 331 | end |
| 333 | 332 | ||
| 334 | - should 'have the captcha_solution be solved' do | ||
| 335 | - Comment.dont_skip_captcha! | ||
| 336 | - c = Comment.new | ||
| 337 | - assert !c.valid? && c.errors.invalid?(:captcha_solution) | ||
| 338 | - c.skip_captcha! | ||
| 339 | - assert !c.valid? && !c.errors.invalid?(:captcha_solution) | ||
| 340 | - end | ||
| 341 | - | ||
| 342 | end | 333 | end |
test/unit/community_test.rb
| @@ -4,7 +4,6 @@ class CommunityTest < Test::Unit::TestCase | @@ -4,7 +4,6 @@ class CommunityTest < Test::Unit::TestCase | ||
| 4 | 4 | ||
| 5 | def setup | 5 | def setup |
| 6 | @person = fast_create(Person) | 6 | @person = fast_create(Person) |
| 7 | - Comment.skip_captcha! | ||
| 8 | end | 7 | end |
| 9 | 8 | ||
| 10 | attr_reader :person | 9 | attr_reader :person |
test/unit/forum_helper_test.rb
| @@ -12,7 +12,6 @@ class ForumHelperTest < Test::Unit::TestCase | @@ -12,7 +12,6 @@ class ForumHelperTest < Test::Unit::TestCase | ||
| 12 | @environment = Environment.default | 12 | @environment = Environment.default |
| 13 | @profile = create_user('forum_helper_test').person | 13 | @profile = create_user('forum_helper_test').person |
| 14 | @forum = fast_create(Forum, :profile_id => profile.id, :name => 'Forum test') | 14 | @forum = fast_create(Forum, :profile_id => profile.id, :name => 'Forum test') |
| 15 | - Comment.skip_captcha! | ||
| 16 | end | 15 | end |
| 17 | 16 | ||
| 18 | attr :profile | 17 | attr :profile |
test/unit/suggest_article_test.rb
| @@ -45,18 +45,6 @@ class SuggestArticleTest < ActiveSupport::TestCase | @@ -45,18 +45,6 @@ class SuggestArticleTest < ActiveSupport::TestCase | ||
| 45 | assert t.errors.invalid?(:target_id) | 45 | assert t.errors.invalid?(:target_id) |
| 46 | end | 46 | end |
| 47 | 47 | ||
| 48 | - should 'have the captcha_solution be solved' do | ||
| 49 | - t = SuggestArticle.new | ||
| 50 | - assert !t.errors.invalid?(:captcha_solution) | ||
| 51 | - t.valid? | ||
| 52 | - assert t.errors.invalid?(:captcha_solution) | ||
| 53 | - | ||
| 54 | - t.skip_captcha! | ||
| 55 | - assert t.skip_captcha? | ||
| 56 | - t.valid? | ||
| 57 | - assert !t.errors.invalid?(:captcha_solution) | ||
| 58 | - end | ||
| 59 | - | ||
| 60 | should 'have the article_abstract' do | 48 | should 'have the article_abstract' do |
| 61 | t = SuggestArticle.new | 49 | t = SuggestArticle.new |
| 62 | assert t.respond_to?(:article_abstract) | 50 | assert t.respond_to?(:article_abstract) |
vendor/plugins/inverse_captcha/README
| @@ -1,29 +0,0 @@ | @@ -1,29 +0,0 @@ | ||
| 1 | -InverseCaptcha | ||
| 2 | -============== | ||
| 3 | - | ||
| 4 | -Implement simple Anti-Comment-Spam Technique. | ||
| 5 | - | ||
| 6 | -Basic Usage | ||
| 7 | -=========== | ||
| 8 | - | ||
| 9 | -Add method inverse_captcha on controller: | ||
| 10 | - | ||
| 11 | -ps.: dont use this method more than once time on same controller. | ||
| 12 | - | ||
| 13 | - inverse_captcha :field => 'e-mail'[, class => 'ghost'] | ||
| 14 | - | ||
| 15 | -Add the field in view form: | ||
| 16 | - | ||
| 17 | - <%= icaptcha_field() %> | ||
| 18 | - | ||
| 19 | -Check if field is blank in your controller: | ||
| 20 | - | ||
| 21 | - if params[controller.icaptcha_field].blank? | ||
| 22 | - do... | ||
| 23 | - else | ||
| 24 | - dont... | ||
| 25 | - end | ||
| 26 | - | ||
| 27 | ---- | ||
| 28 | -Joenio Costa <joenio@colivre.coop.br> | ||
| 29 | -Qui Mar 27 15:48:12 BRT 2008 |
vendor/plugins/inverse_captcha/init.rb
vendor/plugins/inverse_captcha/lib/inverse_captcha.rb
| @@ -1,18 +0,0 @@ | @@ -1,18 +0,0 @@ | ||
| 1 | -module InverseCaptcha | ||
| 2 | - | ||
| 3 | - module ClassMethods | ||
| 4 | - def inverse_captcha(opt = {}) | ||
| 5 | - InverseCaptcha.const_set("ICAPTCHA_FIELD", opt[:field]) unless InverseCaptcha.const_defined? "ICAPTCHA_FIELD" | ||
| 6 | - InverseCaptcha.const_set("ICAPTCHA_LABEL", opt[:label] || N_("Don't fill this field")) unless InverseCaptcha.const_defined? "ICAPTCHA_LABEL" | ||
| 7 | - InverseCaptcha.const_set("ICAPTCHA_STYLECLASS", opt[:class] || 'ghost') unless InverseCaptcha.const_defined? "ICAPTCHA_STYLECLASS" | ||
| 8 | - self.send(:include, InverseCaptcha) | ||
| 9 | - end | ||
| 10 | - end | ||
| 11 | - | ||
| 12 | - module InstanceMethods | ||
| 13 | - def icaptcha_field | ||
| 14 | - ICAPTCHA_FIELD | ||
| 15 | - end | ||
| 16 | - end | ||
| 17 | - | ||
| 18 | -end |
vendor/plugins/inverse_captcha/lib/inverse_captcha_helper.rb
| @@ -1,11 +0,0 @@ | @@ -1,11 +0,0 @@ | ||
| 1 | -module InverseCaptchaHelper | ||
| 2 | - | ||
| 3 | - def icaptcha_field(opt = {}) | ||
| 4 | - label = controller.class::ICAPTCHA_LABEL | ||
| 5 | - field = controller.class::ICAPTCHA_FIELD | ||
| 6 | - opt.merge!({:class => controller.class::ICAPTCHA_STYLECLASS}) | ||
| 7 | - stylesheet = "<style type='text/css'> span.#{opt[:class]} { display: none; } </style>" | ||
| 8 | - stylesheet + content_tag('span', labelled_form_field(_(label), text_field_tag(field, nil)), opt) | ||
| 9 | - end | ||
| 10 | - | ||
| 11 | -end |
vendor/plugins/rails-math-captcha/MIT-LICENSE
| @@ -1,20 +0,0 @@ | @@ -1,20 +0,0 @@ | ||
| 1 | -Copyright (c) 2007 [name of plugin creator] | ||
| 2 | - | ||
| 3 | -Permission is hereby granted, free of charge, to any person obtaining | ||
| 4 | -a copy of this software and associated documentation files (the | ||
| 5 | -"Software"), to deal in the Software without restriction, including | ||
| 6 | -without limitation the rights to use, copy, modify, merge, publish, | ||
| 7 | -distribute, sublicense, and/or sell copies of the Software, and to | ||
| 8 | -permit persons to whom the Software is furnished to do so, subject to | ||
| 9 | -the following conditions: | ||
| 10 | - | ||
| 11 | -The above copyright notice and this permission notice shall be | ||
| 12 | -included in all copies or substantial portions of the Software. | ||
| 13 | - | ||
| 14 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 15 | -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 16 | -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 17 | -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 18 | -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| 19 | -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| 20 | -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
vendor/plugins/rails-math-captcha/README
| @@ -1,45 +0,0 @@ | @@ -1,45 +0,0 @@ | ||
| 1 | -MathCaptcha | ||
| 2 | -=========== | ||
| 3 | - | ||
| 4 | -TODO: Create form helpers | ||
| 5 | - | ||
| 6 | -Validates your Model to be saved by a human (or very clever script) by asking | ||
| 7 | -the user to solve a very basic mathematical equation. | ||
| 8 | - | ||
| 9 | -It does not use the session to store the secret, but uses AES from EzCrypto. | ||
| 10 | - | ||
| 11 | - | ||
| 12 | -Requirements | ||
| 13 | -============ | ||
| 14 | - * gem ezcrypto | ||
| 15 | - * users who can calculate | ||
| 16 | - | ||
| 17 | -Usage | ||
| 18 | -===== | ||
| 19 | - | ||
| 20 | -In your Model < ActiveRecord::Base | ||
| 21 | - | ||
| 22 | - has_captcha | ||
| 23 | - | ||
| 24 | - | ||
| 25 | -In your form view: | ||
| 26 | - | ||
| 27 | - <%= @model.captcha.task %> = ? | ||
| 28 | - <%= form.text_field :captcha_solution %> | ||
| 29 | - <%= form.hidden_field :captcha_secret %> | ||
| 30 | - | ||
| 31 | - | ||
| 32 | -If you want to skip the validation (in tests/specs), you can | ||
| 33 | - | ||
| 34 | - Model.skip_captcha! # or | ||
| 35 | - @model.skip_captcha! | ||
| 36 | - | ||
| 37 | -and turn that off by | ||
| 38 | - | ||
| 39 | - Model.dont_skip_captcha! # or | ||
| 40 | - @model.dont_skip_captcha! | ||
| 41 | - | ||
| 42 | - | ||
| 43 | - | ||
| 44 | -Copyright (c) 2007 Pat Nakajima, released under the MIT license | ||
| 45 | -Copyright (c) 2009 Niklas Hofer, released under the MIT license |
vendor/plugins/rails-math-captcha/Rakefile
| @@ -1,22 +0,0 @@ | @@ -1,22 +0,0 @@ | ||
| 1 | -require 'rake' | ||
| 2 | -require 'rake/testtask' | ||
| 3 | -require 'rake/rdoctask' | ||
| 4 | - | ||
| 5 | -desc 'Default: run unit tests.' | ||
| 6 | -task :default => :test | ||
| 7 | - | ||
| 8 | -desc 'Test the math_captcha plugin.' | ||
| 9 | -Rake::TestTask.new(:test) do |t| | ||
| 10 | - t.libs << 'lib' | ||
| 11 | - t.pattern = 'test/**/*_test.rb' | ||
| 12 | - t.verbose = true | ||
| 13 | -end | ||
| 14 | - | ||
| 15 | -desc 'Generate documentation for the math_captcha plugin.' | ||
| 16 | -Rake::RDocTask.new(:rdoc) do |rdoc| | ||
| 17 | - rdoc.rdoc_dir = 'rdoc' | ||
| 18 | - rdoc.title = 'MathCaptcha' | ||
| 19 | - rdoc.options << '--line-numbers' << '--inline-source' | ||
| 20 | - rdoc.rdoc_files.include('README') | ||
| 21 | - rdoc.rdoc_files.include('lib/**/*.rb') | ||
| 22 | -end |
vendor/plugins/rails-math-captcha/init.rb
vendor/plugins/rails-math-captcha/install.rb
| @@ -1 +0,0 @@ | @@ -1 +0,0 @@ | ||
| 1 | -# Install hook code here |
vendor/plugins/rails-math-captcha/lib/math_captcha.rb
vendor/plugins/rails-math-captcha/lib/math_captcha/captcha.rb
| @@ -1,68 +0,0 @@ | @@ -1,68 +0,0 @@ | ||
| 1 | -require 'rubygems' | ||
| 2 | -require 'ezcrypto' | ||
| 3 | -class Captcha | ||
| 4 | - NUMBERS = (1..9).to_a | ||
| 5 | - OPERATORS = [:+, :-, :*] | ||
| 6 | - | ||
| 7 | - attr_reader :x, :y, :operator | ||
| 8 | - | ||
| 9 | - def initialize(x=nil, y=nil, operator=nil) | ||
| 10 | - @x = x || NUMBERS.sort_by{rand}.first | ||
| 11 | - @y = y || NUMBERS.sort_by{rand}.first | ||
| 12 | - @operator = operator || OPERATORS.sort_by{rand}.first | ||
| 13 | - end | ||
| 14 | - | ||
| 15 | - # Only the #to_secret is shared with the client. | ||
| 16 | - # It can be reused here to create the Captcha again | ||
| 17 | - def self.from_secret(secret) | ||
| 18 | - yml = cipher.decrypt64 secret | ||
| 19 | - args = YAML.load(yml) | ||
| 20 | - new(args[:x], args[:y], args[:operator]) | ||
| 21 | - end | ||
| 22 | - | ||
| 23 | - def self.cipher | ||
| 24 | - EzCrypto::Key.with_password key, 'bad_fixed_salt' | ||
| 25 | - end | ||
| 26 | - | ||
| 27 | - def self.key | ||
| 28 | - 'ultrasecret' | ||
| 29 | - end | ||
| 30 | - | ||
| 31 | - | ||
| 32 | - def check(answer) | ||
| 33 | - answer == solution | ||
| 34 | - end | ||
| 35 | - | ||
| 36 | - def task | ||
| 37 | - "#{@x} #{@operator.to_s} #{@y}" | ||
| 38 | - end | ||
| 39 | - def task_with_questionmark | ||
| 40 | - "#{@x} #{@operator.to_s} #{@y} = ?" | ||
| 41 | - end | ||
| 42 | - alias_method :to_s, :task | ||
| 43 | - | ||
| 44 | - def solution | ||
| 45 | - @x.send @operator, @y | ||
| 46 | - end | ||
| 47 | - | ||
| 48 | - def to_secret | ||
| 49 | - cipher.encrypt64(to_yaml) | ||
| 50 | - end | ||
| 51 | - | ||
| 52 | - def to_yaml | ||
| 53 | - YAML::dump({ | ||
| 54 | - :x => x, | ||
| 55 | - :y => y, | ||
| 56 | - :operator => operator | ||
| 57 | - }) | ||
| 58 | - end | ||
| 59 | - | ||
| 60 | - private | ||
| 61 | - def cipher | ||
| 62 | - @cipher ||= self.class.cipher | ||
| 63 | - end | ||
| 64 | - def reset_cipher | ||
| 65 | - @cipher = nil | ||
| 66 | - end | ||
| 67 | - | ||
| 68 | -end |
vendor/plugins/rails-math-captcha/lib/math_captcha/has_captcha.rb
| @@ -1,54 +0,0 @@ | @@ -1,54 +0,0 @@ | ||
| 1 | -module MathCaptcha | ||
| 2 | - module HasCaptcha | ||
| 3 | - module InstanceMethods | ||
| 4 | - def must_solve_captcha | ||
| 5 | - self.errors.add(:captcha_solution, "wrong answer.") unless self.captcha.check(self.captcha_solution.to_i) | ||
| 6 | - end | ||
| 7 | - def skip_captcha! | ||
| 8 | - self.class.skip_captcha! | ||
| 9 | - end | ||
| 10 | - def skip_captcha? | ||
| 11 | - self.class.skip_captcha? | ||
| 12 | - end | ||
| 13 | - def captcha | ||
| 14 | - @captcha ||= Captcha.new | ||
| 15 | - end | ||
| 16 | - def captcha_secret=(secret) | ||
| 17 | - @captcha = Captcha.from_secret(secret) | ||
| 18 | - end | ||
| 19 | - def captcha_secret | ||
| 20 | - captcha.to_secret | ||
| 21 | - end | ||
| 22 | - end | ||
| 23 | - | ||
| 24 | - module ClassMethods | ||
| 25 | - def has_captcha | ||
| 26 | - include InstanceMethods | ||
| 27 | - attr_accessor :captcha_solution | ||
| 28 | - dont_skip_captcha! | ||
| 29 | - validates_presence_of :captcha_solution, | ||
| 30 | - :on => :create, :message => "can't be blank", | ||
| 31 | - :unless => Proc.new {|record| record.skip_captcha? } | ||
| 32 | - validate_on_create :must_solve_captcha, | ||
| 33 | - :unless => Proc.new {|record| record.skip_captcha? } | ||
| 34 | - end | ||
| 35 | - def skip_captcha! | ||
| 36 | - @@skip_captcha = true | ||
| 37 | - end | ||
| 38 | - def dont_skip_captcha! | ||
| 39 | - @@skip_captcha = false | ||
| 40 | - end | ||
| 41 | - def skip_captcha? | ||
| 42 | - @@skip_captcha | ||
| 43 | - end | ||
| 44 | - def skipping_captcha(&block) | ||
| 45 | - skipping_before = skip_captcha? | ||
| 46 | - skip_captcha! | ||
| 47 | - yield | ||
| 48 | - dont_skip_captcha! if skipping_before | ||
| 49 | - end | ||
| 50 | - end | ||
| 51 | - end | ||
| 52 | -end | ||
| 53 | - | ||
| 54 | -ActiveRecord::Base.send(:extend, MathCaptcha::HasCaptcha::ClassMethods) |
vendor/plugins/rails-math-captcha/spec/captcha_spec.rb
| @@ -1,49 +0,0 @@ | @@ -1,49 +0,0 @@ | ||
| 1 | -require 'lib/math_captcha/captcha' | ||
| 2 | -require 'base64' | ||
| 3 | - | ||
| 4 | -describe Captcha do | ||
| 5 | - describe "with a random task" do | ||
| 6 | - before(:each) do | ||
| 7 | - @captcha = Captcha.new | ||
| 8 | - end | ||
| 9 | - it "should have arguments and an operator" do | ||
| 10 | - @captcha.x.should_not be_nil | ||
| 11 | - @captcha.y.should_not be_nil | ||
| 12 | - @captcha.operator.should_not be_nil | ||
| 13 | - end | ||
| 14 | - it "should use numbers bigger than zero" do | ||
| 15 | - @captcha.x.should > 0 | ||
| 16 | - @captcha.y.should > 0 | ||
| 17 | - end | ||
| 18 | - it "should offer a human readable task" do | ||
| 19 | - @captcha.task.should =~ /^\d+\s*[\+\-\*]\s*\d+$/ | ||
| 20 | - end | ||
| 21 | - it "should have a secret to use in forms" do | ||
| 22 | - @captcha.to_secret.should_not be_nil | ||
| 23 | - @captcha.to_secret.should_not be_empty | ||
| 24 | - end | ||
| 25 | - | ||
| 26 | - it "should re-use its cipher" do | ||
| 27 | - @captcha.send(:cipher).should == @captcha.send(:cipher) | ||
| 28 | - end | ||
| 29 | - | ||
| 30 | - it "should have a base64 encoded secret" do | ||
| 31 | - lambda { Base64.decode64(@captcha.to_secret).should_not be_nil }.should_not raise_error | ||
| 32 | - end | ||
| 33 | - | ||
| 34 | - describe "re-creating another from secret" do | ||
| 35 | - before(:each) do | ||
| 36 | - @secret = @captcha.to_secret | ||
| 37 | - @new_captcha = Captcha.from_secret(@secret) | ||
| 38 | - end | ||
| 39 | - it "should have the same arguments and operator" do | ||
| 40 | - @new_captcha.x.should == @captcha.x | ||
| 41 | - @new_captcha.y.should == @captcha.y | ||
| 42 | - @new_captcha.operator.should == @captcha.operator | ||
| 43 | - end | ||
| 44 | - it "should have the same string" do | ||
| 45 | - @new_captcha.task.should == @captcha.task | ||
| 46 | - end | ||
| 47 | - end | ||
| 48 | - end | ||
| 49 | -end |
vendor/plugins/rails-math-captcha/spec/spec.opts
| @@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
| 1 | +== 0.2.2 / 2009-09-14 | ||
| 2 | + | ||
| 3 | +* Add a timeout to the validator | ||
| 4 | +* Give the documentation some love | ||
| 5 | + | ||
| 6 | +== 0.2.1 / 2009-09-14 | ||
| 7 | + | ||
| 8 | +* Removed Ambethia namespace, and restructured classes a bit | ||
| 9 | +* Added an example rails app in the example-rails branch | ||
| 10 | + | ||
| 11 | +== 0.2.0 / 2009-09-12 | ||
| 12 | + | ||
| 13 | +* RecaptchaOptions AJAX API Fix | ||
| 14 | +* Added 'cucumber' as a test environment to skip | ||
| 15 | +* Ruby 1.9 compat fixes | ||
| 16 | +* Added option :message => 'Custom error message' to verify_recaptcha | ||
| 17 | +* Removed dependency on ActiveRecord constant | ||
| 18 | +* Add I18n | ||
| 19 | + | ||
| 20 | +== 0.1.0 / 2008-2-8 | ||
| 21 | + | ||
| 22 | +* 1 major enhancement | ||
| 23 | + * Initial Gem Release | ||
| 0 | \ No newline at end of file | 24 | \ No newline at end of file |
| @@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
| 1 | +Copyright (c) 2007 Jason L Perry | ||
| 2 | + | ||
| 3 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 4 | +of this software and associated documentation files (the "Software"), to deal | ||
| 5 | +in the Software without restriction, including without limitation the rights | ||
| 6 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 7 | +copies of the Software, and to permit persons to whom the Software is | ||
| 8 | +furnished to do so, subject to the following conditions: | ||
| 9 | + | ||
| 10 | +The above copyright notice and this permission notice shall be included in | ||
| 11 | +all copies or substantial portions of the Software. | ||
| 12 | + | ||
| 13 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 16 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 17 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 18 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 19 | +THE SOFTWARE. | ||
| 0 | \ No newline at end of file | 20 | \ No newline at end of file |
| @@ -0,0 +1,150 @@ | @@ -0,0 +1,150 @@ | ||
| 1 | += reCAPTCHA | ||
| 2 | + | ||
| 3 | +Author:: Jason L Perry (http://ambethia.com) | ||
| 4 | +Copyright:: Copyright (c) 2007 Jason L Perry | ||
| 5 | +License:: {MIT}[http://creativecommons.org/licenses/MIT/] | ||
| 6 | +Info:: http://ambethia.com/recaptcha | ||
| 7 | +Git:: http://github.com/ambethia/recaptcha/tree/master | ||
| 8 | +Bugs:: http://github.com/ambethia/recaptcha/issues | ||
| 9 | + | ||
| 10 | +This plugin adds helpers for the {reCAPTCHA API}[http://recaptcha.net]. In your | ||
| 11 | +views you can use the +recaptcha_tags+ method to embed the needed javascript, | ||
| 12 | +and you can validate in your controllers with +verify_recaptcha+. | ||
| 13 | + | ||
| 14 | +Beforehand you need to configure Recaptcha with your custom private and public | ||
| 15 | +key. You may find detailed examples below. Exceptions will be raised if you | ||
| 16 | +call these methods and the keys can't be found. | ||
| 17 | + | ||
| 18 | +== About this fork | ||
| 19 | + | ||
| 20 | +This fork tries to introduces a more convenient way to configure recaptcha's | ||
| 21 | +settings. The API will be inspired by {Thoughtbot's | ||
| 22 | +Hoptoad}[http://robots.thoughtbot.com/post/344833329/mygem-configure-block]. | ||
| 23 | + | ||
| 24 | +== Rails Installation | ||
| 25 | + | ||
| 26 | +reCAPTCHA for Rails, add this to your Gemfile: | ||
| 27 | + | ||
| 28 | + gem "recaptcha", :require => "recaptcha/rails" | ||
| 29 | + | ||
| 30 | +Or, it can be installed as a gem: | ||
| 31 | + | ||
| 32 | + config.gem "recaptcha", :lib => "recaptcha/rails" | ||
| 33 | + | ||
| 34 | +Or, as a standard rails plugin: | ||
| 35 | + | ||
| 36 | + script/plugin install git://github.com/ambethia/recaptcha.git | ||
| 37 | + | ||
| 38 | +== Merb Installation | ||
| 39 | + | ||
| 40 | +reCAPTCHA can also be used in a Merb application when installed as a gem: | ||
| 41 | + | ||
| 42 | + dependency "alm-recaptcha", ">=0.2.2.1", :require_as => "recaptcha/merb" | ||
| 43 | + | ||
| 44 | +Initial Merb compatability funded by ALM Labs. | ||
| 45 | + | ||
| 46 | +== Setting up your API Keys | ||
| 47 | + | ||
| 48 | +There are multiple ways to setup your reCAPTCHA API key once you | ||
| 49 | +{obtain}[http://recaptcha.net/whyrecaptcha.html] a pair. | ||
| 50 | + | ||
| 51 | +=== Recaptcha.configure | ||
| 52 | + | ||
| 53 | +You may use the block style configuration. The following code could be placed | ||
| 54 | +into a +config/initializers/recaptcha.rb+ when used in a Rails project. | ||
| 55 | + | ||
| 56 | + Recaptcha.configure do |config| | ||
| 57 | + config.public_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy' | ||
| 58 | + config.private_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx' | ||
| 59 | + config.proxy = 'http://myrpoxy.com.au:8080' | ||
| 60 | + end | ||
| 61 | + | ||
| 62 | +This way, you may also set additional options to fit recaptcha into your | ||
| 63 | +deployment environment. | ||
| 64 | + | ||
| 65 | +== Recaptcha#with_configuration | ||
| 66 | + | ||
| 67 | +If you want to temporarily overwrite the configuration you set with `Recaptcha.configure` (when testing, for example), you can use a `Recaptcha#with_configuration` block: | ||
| 68 | + | ||
| 69 | + Recaptcha.configure(:public_key => '12345') do | ||
| 70 | + # Do stuff with the overwritten public_key. | ||
| 71 | + end | ||
| 72 | + | ||
| 73 | +=== Shell environment | ||
| 74 | + | ||
| 75 | +Or, you can keep your keys out of your code base by exporting the following | ||
| 76 | +environment variables. You might do this in the .profile/rc, or equivalent for | ||
| 77 | +the user running your application: | ||
| 78 | + | ||
| 79 | + export RECAPTCHA_PUBLIC_KEY = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy' | ||
| 80 | + export RECAPTCHA_PRIVATE_KEY = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx' | ||
| 81 | + | ||
| 82 | +=== Per call | ||
| 83 | + | ||
| 84 | +You can also pass in your keys as options at runtime, for example: | ||
| 85 | + | ||
| 86 | + recaptcha_tags :public_key => '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy' | ||
| 87 | + | ||
| 88 | +and later, | ||
| 89 | + | ||
| 90 | + verify_recaptcha :private_key => '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx' | ||
| 91 | + | ||
| 92 | +This option might be useful, if the same code base is used for multiple | ||
| 93 | +reCAPTCHA setups. | ||
| 94 | + | ||
| 95 | +== To use 'recaptcha' | ||
| 96 | + | ||
| 97 | +Add +recaptcha_tags+ to each form you want to protect. | ||
| 98 | + | ||
| 99 | +And, add +verify_recaptcha+ logic to each form action that you've protected. | ||
| 100 | + | ||
| 101 | +=== +recaptcha_tags+ | ||
| 102 | + | ||
| 103 | +Some of the options available: | ||
| 104 | + | ||
| 105 | +<tt>:ssl</tt>:: Uses secure http for captcha widget (default +false+) | ||
| 106 | +<tt>:noscript</tt>:: Include <noscript> content (default +true+) | ||
| 107 | +<tt>:display</tt>:: Takes a hash containing the +theme+ and +tabindex+ options per the API. (default +nil+) | ||
| 108 | +<tt>:ajax</tt>:: Render the dynamic AJAX captcha per the API. (default +false+) | ||
| 109 | +<tt>:public_key</tt>:: Your public API key, takes precedence over the ENV variable (default +nil+) | ||
| 110 | +<tt>:error</tt>:: Override the error code returned from the reCAPTCHA API (default +nil+) | ||
| 111 | + | ||
| 112 | +You can also override the html attributes for the sizes of the generated +textarea+ and +iframe+ | ||
| 113 | +elements, if CSS isn't your thing. Inspect the source of +recaptcha_tags+ to see these options. | ||
| 114 | + | ||
| 115 | +=== +verify_recaptcha+ | ||
| 116 | + | ||
| 117 | +This method returns +true+ or +false+ after processing the parameters from the reCAPTCHA widget. Why | ||
| 118 | +isn't this a model validation? Because that violates MVC. You can use it like this, or how ever you | ||
| 119 | +like. Passing in the ActiveRecord object is optional, if you do--and the captcha fails to verify--an | ||
| 120 | +error will be added to the object for you to use. | ||
| 121 | + | ||
| 122 | +Some of the options available: | ||
| 123 | + | ||
| 124 | +<tt>:model</tt>:: Model to set errors | ||
| 125 | +<tt>:attribute</tt>:: Model attribute to receive errors (default :base) | ||
| 126 | +<tt>:message</tt>:: Custom error message | ||
| 127 | +<tt>:private_key</tt>:: Your private API key, takes precedence over the ENV variable (default +nil+). | ||
| 128 | +<tt>:timeout</tt>:: The number of seconds to wait for reCAPTCHA servers before give up. (default +3+) | ||
| 129 | + | ||
| 130 | + respond_to do |format| | ||
| 131 | + if verify_recaptcha(:model => @post, :message => "Oh! It's error with reCAPTCHA!") && @post.save | ||
| 132 | + # ... | ||
| 133 | + else | ||
| 134 | + # ... | ||
| 135 | + end | ||
| 136 | + end | ||
| 137 | + | ||
| 138 | +== I18n support | ||
| 139 | +reCAPTCHA passes two types of error explanation to a linked model. It will use the I18n gem | ||
| 140 | +to translate the default error message if I18n is available. To customize the messages to your locale, | ||
| 141 | +add these keys to your I18n backend: | ||
| 142 | + | ||
| 143 | +<tt>recaptcha.errors.verification_failed</tt>:: error message displayed if the captcha words didn't match | ||
| 144 | +<tt>recaptcha.errors.recaptcha_unavailable</tt>:: displayed if a timout error occured while attempting to verify the captcha | ||
| 145 | + | ||
| 146 | +== TODO | ||
| 147 | +* Remove Rails/ActionController dependencies | ||
| 148 | +* Framework agnostic | ||
| 149 | +* Add some helpers to use in before_filter and what not | ||
| 150 | +* Better documentation |
| @@ -0,0 +1,60 @@ | @@ -0,0 +1,60 @@ | ||
| 1 | +require 'rake' | ||
| 2 | + | ||
| 3 | +begin | ||
| 4 | + require 'jeweler' | ||
| 5 | + Jeweler::Tasks.new do |gem| | ||
| 6 | + gem.name = "recaptcha" | ||
| 7 | + gem.description = "This plugin adds helpers for the reCAPTCHA API " | ||
| 8 | + gem.summary = "Helpers for the reCAPTCHA API" | ||
| 9 | + gem.homepage = "http://ambethia.com/recaptcha" | ||
| 10 | + gem.authors = ["Jason L. Perry"] | ||
| 11 | + gem.email = "jasper@ambethia.com" | ||
| 12 | + gem.files.reject! { |fn| fn.include? ".gitignore" } | ||
| 13 | + gem.add_development_dependency "mocha" | ||
| 14 | + gem.add_development_dependency "activesupport" | ||
| 15 | + end | ||
| 16 | + Jeweler::GemcutterTasks.new | ||
| 17 | +rescue LoadError | ||
| 18 | + puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler" | ||
| 19 | +end | ||
| 20 | + | ||
| 21 | +require 'rake/rdoctask' | ||
| 22 | +Rake::RDocTask.new do |rd| | ||
| 23 | + if File.exist?('VERSION.yml') | ||
| 24 | + config = YAML.load(File.read('VERSION.yml')) | ||
| 25 | + version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}" | ||
| 26 | + else | ||
| 27 | + version = "" | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + rd.main = "README.rdoc" | ||
| 31 | + rd.rdoc_files.include "README.rdoc", "LICENSE", "lib/**/*.rb" | ||
| 32 | + rd.rdoc_dir = 'rdoc' | ||
| 33 | + rd.options << '-N' # line numbers | ||
| 34 | + rd.options << '-S' # inline source | ||
| 35 | +end | ||
| 36 | + | ||
| 37 | +require 'rake/testtask' | ||
| 38 | +Rake::TestTask.new(:test) do |test| | ||
| 39 | + test.libs << 'test' | ||
| 40 | + test.pattern = 'test/**/*_test.rb' | ||
| 41 | + # test.verbose = true | ||
| 42 | +end | ||
| 43 | + | ||
| 44 | +begin | ||
| 45 | + require 'rcov/rcovtask' | ||
| 46 | + Rcov::RcovTask.new do |test| | ||
| 47 | + test.libs << 'test' | ||
| 48 | + test.pattern = 'test/**/*_test.rb' | ||
| 49 | + test.verbose = true | ||
| 50 | + end | ||
| 51 | +rescue LoadError | ||
| 52 | + task :rcov do | ||
| 53 | + abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov" | ||
| 54 | + end | ||
| 55 | +end | ||
| 56 | + | ||
| 57 | +task :default => :test | ||
| 58 | + | ||
| 59 | + | ||
| 60 | + |
| @@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
| 1 | +0.3.2 |
| @@ -0,0 +1,58 @@ | @@ -0,0 +1,58 @@ | ||
| 1 | +require 'recaptcha/configuration' | ||
| 2 | +require 'recaptcha/client_helper' | ||
| 3 | +require 'recaptcha/verify' | ||
| 4 | + | ||
| 5 | +module Recaptcha | ||
| 6 | + module VERSION #:nodoc: | ||
| 7 | + MAJOR = 0 | ||
| 8 | + MINOR = 2 | ||
| 9 | + TINY = 2 | ||
| 10 | + PATCH = 1 | ||
| 11 | + | ||
| 12 | + STRING = [MAJOR, MINOR, TINY, PATCH].join('.') | ||
| 13 | + end | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + RECAPTCHA_API_SERVER_URL = 'http://www.google.com/recaptcha/api' | ||
| 17 | + RECAPTCHA_API_SECURE_SERVER_URL = 'https://www.google.com/recaptcha/api' | ||
| 18 | + RECAPTCHA_VERIFY_URL = 'http://www.google.com/recaptcha/api/verify' | ||
| 19 | + | ||
| 20 | + SKIP_VERIFY_ENV = ['test', 'cucumber'] | ||
| 21 | + | ||
| 22 | + # Gives access to the current Configuration. | ||
| 23 | + def self.configuration | ||
| 24 | + @configuration ||= Configuration.new | ||
| 25 | + end | ||
| 26 | + | ||
| 27 | + # Allows easy setting of multiple configuration options. See Configuration | ||
| 28 | + # for all available options. | ||
| 29 | + #-- | ||
| 30 | + # The temp assignment is only used to get a nicer rdoc. Feel free to remove | ||
| 31 | + # this hack. | ||
| 32 | + #++ | ||
| 33 | + def self.configure | ||
| 34 | + config = configuration | ||
| 35 | + yield(config) | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | + def self.with_configuration(config) | ||
| 39 | + original_config = {} | ||
| 40 | + | ||
| 41 | + config.each do |key, value| | ||
| 42 | + original_config[key] = configuration.send(key) | ||
| 43 | + configuration.send("#{key}=", value) | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + result = yield if block_given? | ||
| 47 | + | ||
| 48 | + original_config.each { |key, value| configuration.send("#{key}=", value) } | ||
| 49 | + result | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + class RecaptchaError < StandardError | ||
| 53 | + end | ||
| 54 | +end | ||
| 55 | + | ||
| 56 | +if defined?(Rails) | ||
| 57 | + require 'recaptcha/rails' | ||
| 58 | +end |
| @@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
| 1 | +module Recaptcha | ||
| 2 | + module ClientHelper | ||
| 3 | + # Your public API can be specified in the +options+ hash or preferably | ||
| 4 | + # using the Configuration. | ||
| 5 | + def recaptcha_tags(options = {}) | ||
| 6 | + # Default options | ||
| 7 | + key = options[:public_key] ||= Recaptcha.configuration.public_key | ||
| 8 | + raise RecaptchaError, "No public key specified." unless key | ||
| 9 | + error = options[:error] ||= (defined? flash ? flash[:recaptcha_error] : "") | ||
| 10 | + uri = Recaptcha.configuration.api_server_url(options[:ssl]) | ||
| 11 | + html = "" | ||
| 12 | + if options[:display] | ||
| 13 | + html << %{<script type="text/javascript">\n} | ||
| 14 | + html << %{ var RecaptchaOptions = #{options[:display].to_json};\n} | ||
| 15 | + html << %{</script>\n} | ||
| 16 | + end | ||
| 17 | + if options[:ajax] | ||
| 18 | + html << <<-EOS | ||
| 19 | + <div id="dynamic_recaptcha"></div> | ||
| 20 | + <script type="text/javascript"> | ||
| 21 | + var rc_script_tag = document.createElement('script'), | ||
| 22 | + rc_init_func = function(){Recaptcha.create("#{key}", document.getElementById("dynamic_recaptcha")#{',RecaptchaOptions' if options[:display]});} | ||
| 23 | + rc_script_tag.src = "#{uri}/js/recaptcha_ajax.js"; | ||
| 24 | + rc_script_tag.type = 'text/javascript'; | ||
| 25 | + rc_script_tag.onload = function(){rc_init_func.call();}; | ||
| 26 | + rc_script_tag.onreadystatechange = function(){ | ||
| 27 | + if (rc_script_tag.readyState == 'loaded' || rc_script_tag.readyState == 'complete') {rc_init_func.call();} | ||
| 28 | + }; | ||
| 29 | + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(rc_script_tag); | ||
| 30 | + </script> | ||
| 31 | + EOS | ||
| 32 | + else | ||
| 33 | + html << %{<script type="text/javascript" src="#{uri}/challenge?k=#{key}} | ||
| 34 | + html << %{#{error ? "&error=#{CGI::escape(error)}" : ""}"></script>\n} | ||
| 35 | + unless options[:noscript] == false | ||
| 36 | + html << %{<noscript>\n } | ||
| 37 | + html << %{<iframe src="#{uri}/noscript?k=#{key}" } | ||
| 38 | + html << %{height="#{options[:iframe_height] ||= 300}" } | ||
| 39 | + html << %{width="#{options[:iframe_width] ||= 500}" } | ||
| 40 | + html << %{style="border:none;"></iframe><br/>\n } | ||
| 41 | + html << %{<textarea name="recaptcha_challenge_field" } | ||
| 42 | + html << %{rows="#{options[:textarea_rows] ||= 3}" } | ||
| 43 | + html << %{cols="#{options[:textarea_cols] ||= 40}"></textarea>\n } | ||
| 44 | + html << %{<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>} | ||
| 45 | + html << %{</noscript>\n} | ||
| 46 | + end | ||
| 47 | + end | ||
| 48 | + return (html.respond_to?(:html_safe) && html.html_safe) || html | ||
| 49 | + end # recaptcha_tags | ||
| 50 | + end # ClientHelper | ||
| 51 | +end # Recaptcha |
| @@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
| 1 | +module Recaptcha | ||
| 2 | + # This class enables detailed configuration of the recaptcha services. | ||
| 3 | + # | ||
| 4 | + # By calling | ||
| 5 | + # | ||
| 6 | + # Recaptcha.configuration # => instance of Recaptcha::Configuration | ||
| 7 | + # | ||
| 8 | + # or | ||
| 9 | + # Recaptcha.configure do |config| | ||
| 10 | + # config # => instance of Recaptcha::Configuration | ||
| 11 | + # end | ||
| 12 | + # | ||
| 13 | + # you are able to perform configuration updates. | ||
| 14 | + # | ||
| 15 | + # Your are able to customize all attributes listed below. All values have | ||
| 16 | + # sensitive default and will very likely not need to be changed. | ||
| 17 | + # | ||
| 18 | + # Please note that the public and private key for the reCAPTCHA API Access | ||
| 19 | + # have no useful default value. The keys may be set via the Shell enviroment | ||
| 20 | + # or using this configuration. Settings within this configuration always take | ||
| 21 | + # precedence. | ||
| 22 | + # | ||
| 23 | + # Setting the keys with this Configuration | ||
| 24 | + # | ||
| 25 | + # Recaptcha.configure do |config| | ||
| 26 | + # config.public_key = '6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy' | ||
| 27 | + # config.private_key = '6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx' | ||
| 28 | + # end | ||
| 29 | + # | ||
| 30 | + class Configuration | ||
| 31 | + attr_accessor :nonssl_api_server_url, | ||
| 32 | + :ssl_api_server_url, | ||
| 33 | + :verify_url, | ||
| 34 | + :skip_verify_env, | ||
| 35 | + :private_key, | ||
| 36 | + :public_key, | ||
| 37 | + :proxy | ||
| 38 | + | ||
| 39 | + def initialize #:nodoc: | ||
| 40 | + @nonssl_api_server_url = RECAPTCHA_API_SERVER_URL | ||
| 41 | + @ssl_api_server_url = RECAPTCHA_API_SECURE_SERVER_URL | ||
| 42 | + @verify_url = RECAPTCHA_VERIFY_URL | ||
| 43 | + @skip_verify_env = SKIP_VERIFY_ENV | ||
| 44 | + | ||
| 45 | + @private_key = ENV['RECAPTCHA_PRIVATE_KEY'] | ||
| 46 | + @public_key = ENV['RECAPTCHA_PUBLIC_KEY'] | ||
| 47 | + end | ||
| 48 | + | ||
| 49 | + def api_server_url(ssl = false) #:nodoc: | ||
| 50 | + ssl ? ssl_api_server_url : nonssl_api_server_url | ||
| 51 | + end | ||
| 52 | + end | ||
| 53 | +end |
| @@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
| 1 | +require 'net/http' | ||
| 2 | +require 'recaptcha' | ||
| 3 | +module Rails | ||
| 4 | + module Recaptcha | ||
| 5 | + class Railtie < Rails::Railtie | ||
| 6 | + initializer "setup config" do | ||
| 7 | + begin | ||
| 8 | + ActionView::Base.send(:include, ::Recaptcha::ClientHelper) | ||
| 9 | + ActionController::Base.send(:include, ::Recaptcha::Verify) | ||
| 10 | + end | ||
| 11 | + end | ||
| 12 | + end | ||
| 13 | + end | ||
| 14 | +end | ||
| 15 | + |
| @@ -0,0 +1,61 @@ | @@ -0,0 +1,61 @@ | ||
| 1 | +require "uri" | ||
| 2 | +module Recaptcha | ||
| 3 | + module Verify | ||
| 4 | + # Your private API can be specified in the +options+ hash or preferably | ||
| 5 | + # using the Configuration. | ||
| 6 | + def verify_recaptcha(options = {}) | ||
| 7 | + if !options.is_a? Hash | ||
| 8 | + options = {:model => options} | ||
| 9 | + end | ||
| 10 | + | ||
| 11 | + env = options[:env] || ENV['RAILS_ENV'] | ||
| 12 | + return true if Recaptcha.configuration.skip_verify_env.include? env | ||
| 13 | + model = options[:model] | ||
| 14 | + attribute = options[:attribute] || :base | ||
| 15 | + private_key = options[:private_key] || Recaptcha.configuration.private_key | ||
| 16 | + raise RecaptchaError, "No private key specified." unless private_key | ||
| 17 | + | ||
| 18 | + begin | ||
| 19 | + recaptcha = nil | ||
| 20 | + if(Recaptcha.configuration.proxy) | ||
| 21 | + proxy_server = URI.parse(Recaptcha.configuration.proxy) | ||
| 22 | + http = Net::HTTP::Proxy(proxy_server.host, proxy_server.port) | ||
| 23 | + else | ||
| 24 | + http = Net::HTTP | ||
| 25 | + end | ||
| 26 | + | ||
| 27 | + Timeout::timeout(options[:timeout] || 3) do | ||
| 28 | + recaptcha = http.post_form(URI.parse(Recaptcha.configuration.verify_url), { | ||
| 29 | + "privatekey" => private_key, | ||
| 30 | + "remoteip" => request.remote_ip, | ||
| 31 | + "challenge" => params[:recaptcha_challenge_field], | ||
| 32 | + "response" => params[:recaptcha_response_field] | ||
| 33 | + }) | ||
| 34 | + end | ||
| 35 | + answer, error = recaptcha.body.split.map { |s| s.chomp } | ||
| 36 | + unless answer == 'true' | ||
| 37 | + flash[:recaptcha_error] = error | ||
| 38 | + if model | ||
| 39 | + message = "Word verification response is incorrect, please try again." | ||
| 40 | + message = I18n.translate(:'recaptcha.errors.verification_failed', {:default => message}) if defined?(I18n) | ||
| 41 | + model.errors.add attribute, options[:message] || message | ||
| 42 | + end | ||
| 43 | + return false | ||
| 44 | + else | ||
| 45 | + flash[:recaptcha_error] = nil | ||
| 46 | + return true | ||
| 47 | + end | ||
| 48 | + rescue Timeout::Error | ||
| 49 | + flash[:recaptcha_error] = "recaptcha-not-reachable" | ||
| 50 | + if model | ||
| 51 | + message = "Oops, we failed to validate your word verification response. Please try again." | ||
| 52 | + message = I18n.translate(:'recaptcha.errors.recaptcha_unreachable', :default => message) if defined?(I18n) | ||
| 53 | + model.errors.add attribute, options[:message] || message | ||
| 54 | + end | ||
| 55 | + return false | ||
| 56 | + rescue Exception => e | ||
| 57 | + raise RecaptchaError, e.message, e.backtrace | ||
| 58 | + end | ||
| 59 | + end # verify_recaptcha | ||
| 60 | + end # Verify | ||
| 61 | +end # Recaptcha |
| @@ -0,0 +1,65 @@ | @@ -0,0 +1,65 @@ | ||
| 1 | +# Generated by jeweler | ||
| 2 | +# DO NOT EDIT THIS FILE DIRECTLY | ||
| 3 | +# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' | ||
| 4 | +# -*- encoding: utf-8 -*- | ||
| 5 | + | ||
| 6 | +Gem::Specification.new do |s| | ||
| 7 | + s.name = %q{recaptcha} | ||
| 8 | + s.version = "0.3.2" | ||
| 9 | + | ||
| 10 | + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | ||
| 11 | + s.authors = ["Jason L. Perry"] | ||
| 12 | + s.date = %q{2010-12-20} | ||
| 13 | + s.description = %q{This plugin adds helpers for the reCAPTCHA API } | ||
| 14 | + s.email = %q{jasper@ambethia.com} | ||
| 15 | + s.extra_rdoc_files = [ | ||
| 16 | + "LICENSE", | ||
| 17 | + "README.rdoc" | ||
| 18 | + ] | ||
| 19 | + s.files = [ | ||
| 20 | + "CHANGELOG", | ||
| 21 | + "LICENSE", | ||
| 22 | + "README.rdoc", | ||
| 23 | + "Rakefile", | ||
| 24 | + "VERSION", | ||
| 25 | + "init.rb", | ||
| 26 | + "lib/recaptcha.rb", | ||
| 27 | + "lib/recaptcha/client_helper.rb", | ||
| 28 | + "lib/recaptcha/configuration.rb", | ||
| 29 | + "lib/recaptcha/merb.rb", | ||
| 30 | + "lib/recaptcha/rails.rb", | ||
| 31 | + "lib/recaptcha/verify.rb", | ||
| 32 | + "recaptcha.gemspec", | ||
| 33 | + "tasks/recaptcha_tasks.rake", | ||
| 34 | + "test/recaptcha_test.rb", | ||
| 35 | + "test/verify_recaptcha_test.rb" | ||
| 36 | + ] | ||
| 37 | + s.homepage = %q{http://ambethia.com/recaptcha} | ||
| 38 | + s.require_paths = ["lib"] | ||
| 39 | + s.rubygems_version = %q{1.3.7} | ||
| 40 | + s.summary = %q{Helpers for the reCAPTCHA API} | ||
| 41 | + s.test_files = [ | ||
| 42 | + "test/recaptcha_test.rb", | ||
| 43 | + "test/verify_recaptcha_test.rb" | ||
| 44 | + ] | ||
| 45 | + | ||
| 46 | + if s.respond_to? :specification_version then | ||
| 47 | + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION | ||
| 48 | + s.specification_version = 3 | ||
| 49 | + | ||
| 50 | + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then | ||
| 51 | + s.add_development_dependency(%q<mocha>, [">= 0"]) | ||
| 52 | + s.add_development_dependency(%q<activesupport>, [">= 0"]) | ||
| 53 | + s.add_dependency(%q<i18n>, [">= 0"]) | ||
| 54 | + else | ||
| 55 | + s.add_dependency(%q<mocha>, [">= 0"]) | ||
| 56 | + s.add_dependency(%q<activesupport>, [">= 0"]) | ||
| 57 | + s.add_dependency(%q<i18n>, [">= 0"]) | ||
| 58 | + end | ||
| 59 | + else | ||
| 60 | + s.add_dependency(%q<mocha>, [">= 0"]) | ||
| 61 | + s.add_dependency(%q<activesupport>, [">= 0"]) | ||
| 62 | + s.add_dependency(%q<i18n>, [">= 0"]) | ||
| 63 | + end | ||
| 64 | +end | ||
| 65 | + |
| @@ -0,0 +1,52 @@ | @@ -0,0 +1,52 @@ | ||
| 1 | +require 'test/unit' | ||
| 2 | +require 'cgi' | ||
| 3 | +require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha' | ||
| 4 | + | ||
| 5 | +class RecaptchaClientHelperTest < Test::Unit::TestCase | ||
| 6 | + include Recaptcha | ||
| 7 | + include Recaptcha::ClientHelper | ||
| 8 | + include Recaptcha::Verify | ||
| 9 | + | ||
| 10 | + attr_accessor :session | ||
| 11 | + | ||
| 12 | + def setup | ||
| 13 | + @session = {} | ||
| 14 | + Recaptcha.configure do |config| | ||
| 15 | + config.public_key = '0000000000000000000000000000000000000000' | ||
| 16 | + config.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' | ||
| 17 | + end | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + def test_recaptcha_tags | ||
| 21 | + # Might as well match something... | ||
| 22 | + assert_match /http:\/\/www.google.com\/recaptcha\/api\/challenge/, recaptcha_tags | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | + def test_recaptcha_tags_with_ssl | ||
| 26 | + assert_match /https:\/\/www.google.com\/recaptcha\/api\/challenge/, recaptcha_tags(:ssl => true) | ||
| 27 | + end | ||
| 28 | + | ||
| 29 | + def test_recaptcha_tags_without_noscript | ||
| 30 | + assert_no_match /noscript/, recaptcha_tags(:noscript => false) | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + def test_should_raise_exception_without_public_key | ||
| 34 | + assert_raise RecaptchaError do | ||
| 35 | + Recaptcha.configuration.public_key = nil | ||
| 36 | + recaptcha_tags | ||
| 37 | + end | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + def test_different_configuration_within_with_configuration_block | ||
| 41 | + key = Recaptcha.with_configuration(:public_key => '12345') do | ||
| 42 | + Recaptcha.configuration.public_key | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + assert_equal('12345', key) | ||
| 46 | + end | ||
| 47 | + | ||
| 48 | + def test_reset_configuration_after_with_configuration_block | ||
| 49 | + Recaptcha.with_configuration(:public_key => '12345') | ||
| 50 | + assert_equal('0000000000000000000000000000000000000000', Recaptcha.configuration.public_key) | ||
| 51 | + end | ||
| 52 | +end |
| @@ -0,0 +1,120 @@ | @@ -0,0 +1,120 @@ | ||
| 1 | +# coding: utf-8 | ||
| 2 | + | ||
| 3 | +require 'test/unit' | ||
| 4 | +require 'rubygems' | ||
| 5 | +require 'active_support/core_ext/string' | ||
| 6 | +require 'mocha' | ||
| 7 | +require 'i18n' | ||
| 8 | +require 'net/http' | ||
| 9 | +require File.dirname(File.expand_path(__FILE__)) + '/../lib/recaptcha' | ||
| 10 | + | ||
| 11 | +class RecaptchaVerifyTest < Test::Unit::TestCase | ||
| 12 | + def setup | ||
| 13 | + Recaptcha.configuration.private_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' | ||
| 14 | + @controller = TestController.new | ||
| 15 | + @controller.request = stub(:remote_ip => "1.1.1.1") | ||
| 16 | + @controller.params = {:recaptcha_challenge_field => "challenge", :recaptcha_response_field => "response"} | ||
| 17 | + | ||
| 18 | + @expected_post_data = {} | ||
| 19 | + @expected_post_data["privatekey"] = Recaptcha.configuration.private_key | ||
| 20 | + @expected_post_data["remoteip"] = @controller.request.remote_ip | ||
| 21 | + @expected_post_data["challenge"] = "challenge" | ||
| 22 | + @expected_post_data["response"] = "response" | ||
| 23 | + | ||
| 24 | + @expected_uri = URI.parse(Recaptcha.configuration.verify_url) | ||
| 25 | + end | ||
| 26 | + | ||
| 27 | + def test_should_raise_exception_without_private_key | ||
| 28 | + assert_raise Recaptcha::RecaptchaError do | ||
| 29 | + Recaptcha.configuration.private_key = nil | ||
| 30 | + @controller.verify_recaptcha | ||
| 31 | + end | ||
| 32 | + end | ||
| 33 | + | ||
| 34 | + def test_should_return_false_when_key_is_invalid | ||
| 35 | + expect_http_post(response_with_body("false\ninvalid-site-private-key")) | ||
| 36 | + | ||
| 37 | + assert !@controller.verify_recaptcha | ||
| 38 | + assert_equal "invalid-site-private-key", @controller.flash[:recaptcha_error] | ||
| 39 | + end | ||
| 40 | + | ||
| 41 | + def test_returns_true_on_success | ||
| 42 | + @controller.flash[:recaptcha_error] = "previous error that should be cleared" | ||
| 43 | + expect_http_post(response_with_body("true\n")) | ||
| 44 | + | ||
| 45 | + assert @controller.verify_recaptcha | ||
| 46 | + assert_nil @controller.flash[:recaptcha_error] | ||
| 47 | + end | ||
| 48 | + | ||
| 49 | + def test_errors_should_be_added_to_model | ||
| 50 | + expect_http_post(response_with_body("false\nbad-news")) | ||
| 51 | + | ||
| 52 | + errors = mock | ||
| 53 | + errors.expects(:add).with(:base, "Word verification response is incorrect, please try again.") | ||
| 54 | + model = mock(:errors => errors) | ||
| 55 | + | ||
| 56 | + assert !@controller.verify_recaptcha(:model => model) | ||
| 57 | + assert_equal "bad-news", @controller.flash[:recaptcha_error] | ||
| 58 | + end | ||
| 59 | + | ||
| 60 | + def test_returns_true_on_success_with_optional_key | ||
| 61 | + @controller.flash[:recaptcha_error] = "previous error that should be cleared" | ||
| 62 | + # reset private key | ||
| 63 | + @expected_post_data["privatekey"] = 'ADIFFERENTPRIVATEKEYXXXXXXXXXXXXXX' | ||
| 64 | + expect_http_post(response_with_body("true\n")) | ||
| 65 | + | ||
| 66 | + assert @controller.verify_recaptcha(:private_key => 'ADIFFERENTPRIVATEKEYXXXXXXXXXXXXXX') | ||
| 67 | + assert_nil @controller.flash[:recaptcha_error] | ||
| 68 | + end | ||
| 69 | + | ||
| 70 | + def test_timeout | ||
| 71 | + expect_http_post(Timeout::Error, :exception => true) | ||
| 72 | + assert !@controller.verify_recaptcha() | ||
| 73 | + assert_equal "recaptcha-not-reachable", @controller.flash[:recaptcha_error] | ||
| 74 | + end | ||
| 75 | + | ||
| 76 | + def test_message_should_use_i18n | ||
| 77 | + I18n.locale = :de | ||
| 78 | + verification_failed_translated = "Sicherheitscode konnte nicht verifiziert werden." | ||
| 79 | + verification_failed_default = "Word verification response is incorrect, please try again." | ||
| 80 | + recaptcha_unreachable_translated = "Netzwerkfehler, bitte versuchen Sie es später erneut." | ||
| 81 | + recaptcha_unreachable_default = "Oops, we failed to validate your word verification response. Please try again." | ||
| 82 | + I18n.expects(:translate).with(:'recaptcha.errors.verification_failed', :default => verification_failed_default).returns(verification_failed_translated) | ||
| 83 | + I18n.expects(:translate).with(:'recaptcha.errors.recaptcha_unreachable', :default => recaptcha_unreachable_default).returns(recaptcha_unreachable_translated) | ||
| 84 | + | ||
| 85 | + errors = mock | ||
| 86 | + errors.expects(:add).with(:base, verification_failed_translated) | ||
| 87 | + errors.expects(:add).with(:base, recaptcha_unreachable_translated) | ||
| 88 | + model = mock; model.stubs(:errors => errors) | ||
| 89 | + | ||
| 90 | + expect_http_post(response_with_body("false\nbad-news")) | ||
| 91 | + @controller.verify_recaptcha(:model => model) | ||
| 92 | + | ||
| 93 | + expect_http_post(Timeout::Error, :exception => true) | ||
| 94 | + @controller.verify_recaptcha(:model => model) | ||
| 95 | + | ||
| 96 | + end | ||
| 97 | + | ||
| 98 | + private | ||
| 99 | + | ||
| 100 | + class TestController | ||
| 101 | + include Recaptcha::Verify | ||
| 102 | + attr_accessor :request, :params, :flash | ||
| 103 | + | ||
| 104 | + def initialize | ||
| 105 | + @flash = {} | ||
| 106 | + end | ||
| 107 | + end | ||
| 108 | + | ||
| 109 | + def expect_http_post(response, options = {}) | ||
| 110 | + unless options[:exception] | ||
| 111 | + Net::HTTP.expects(:post_form).with(@expected_uri, @expected_post_data).returns(response) | ||
| 112 | + else | ||
| 113 | + Net::HTTP.expects(:post_form).raises response | ||
| 114 | + end | ||
| 115 | + end | ||
| 116 | + | ||
| 117 | + def response_with_body(body) | ||
| 118 | + stub(:body => body) | ||
| 119 | + end | ||
| 120 | +end |