ruby-on-railsdevisehumanizer

Humanizer human validation not working on Devise user seperate actions, Rails 4


I have Rails 4 app with Devise.

Recently, I discovered that for some actions Humanizer function is not working.

Problem: Basically it doesn't check my input regarding security question and allows to move forward with action(But it shouldn't.) No error messages are displayed.

Note: Humanizer works perfectly in user registration process, but doesn't work at all in actions like edit, password recovery etc.

My code:

User.rb:

class User < ActiveRecord::Base

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :lockable, :confirmable
  include Humanizer

  attr_accessor :bypass_humanizer
  require_human_on :create, :unless => :bypass_humanizer


...

end

routes.rb

 devise_for :users,  :controllers => {:registrations=> "registrations", :confirmations=> "confirmations", :passwords => "passwords", :sessions => "sessions"}

Registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController 

    clear_respond_to   
    respond_to :json

   def sign_up_params
    params.require(:user).permit( :email, :password, :country_id, :password_confirmation,:name, :not_a_robot,:current_password,:bypass_humanizer,:role, :humanizer_question_id, :humanizer_answer)
  end

  def account_update_params
    params.require(:user).permit(:name, :email, :password, :country_id,:humanizer_answer, :password_confirmation, :current_password, :not_a_robot, :bypass_humanizer,:confirmation_token, :humanizer_question_id)
  end


  def destroy
    #@p = current_user.id

     @user = User.find(current_user.id)
     @user.destroy

    if @user.destroy
        redirect_to root_path, notice: "User deleted."
    end

  end 

  private :sign_up_params
  private :account_update_params


  protected

  def update_resource(resource, params)
    resource.update_without_password(params)
  end

end

Passwords_controller.rb

class PasswordsController < Devise::PasswordsController

    respond_to :json, only: [:create]
    skip_before_filter :age_check


  def create
              user = resource_class.send_reset_password_instructions(resource_params)

              if successfully_sent?(user)
                   render json: { data: "something" }, status: 200
              else
                   render json: { data: "something bad" }, status: 400
              end
  end

   def update
    self.resource = resource_class.reset_password_by_token(resource_params)
    yield resource if block_given?

    if resource.errors.empty?
      resource.unlock_access! if unlockable?(resource)
      if Devise.sign_in_after_reset_password
        flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
       # set_flash_message!(:notice, flash_message)
        sign_in(resource_name, resource)
      else
    #    set_flash_message!(:notice, :updated_not_active)
      end
     # respond_with resource, location: after_resetting_password_path_for(resource)
     redirect_to root_path
    else
      set_minimum_password_length
      respond_with resource
    end
  end

end

Password recovery form (Humanizer doesn't work):

<%= form_for(@user,:html => {"data-parsley-validate" => true,:id=>"password-recover-modal",:class=>"password-recover-modal"},:remote=> true,format: :json,as: @user, url: password_path(@user)) do |f| %>                                                  
    <div class="form-group">            
        <%= f.email_field :email, autofocus: true ,:class=> "user-input form-control", :id=>"email",:placeholder=>t('email'),required: true%>                                                       
    </div>

    <div class="question-content" style="position:relative;top:1px;">
        <span class="question"><%= t('question') %>:</span>
        <%=   f.hidden_field :humanizer_question_id %> 
            <span class="answer">
                <%= f.label :humanizer_answer, @user.humanizer_question %>  
            </span>

    <div class="form-group" style="margin-bottom:21px;">
        <span class="question" style="margin-top:8px;"><%= t('answer') %>: *</span>
        <%= f.text_field :humanizer_answer ,:class=> "form-control",:required => true, :id=>"answer"%>
    </div>         
</div>

<%= f.submit t('recover_pass'),:class=> "blue-button btn btn-default"%>            
<%end%>

User registration form(Humanizer works perfectly):

<%= form_for(@user, :html => {:id=>"sign_up_user" ,:class=>"registration-form-modalc","data-parsley-validate" => true},remote: true, format: :json,as: @user, url: registration_path(@user)) do |f| %>
    <div class="form-group">                                    
        <%= f.text_field :name,:class=> "user-input form-control", :id=>"user-name",autofocus: true ,:placeholder=> t('username_2'),:required => true,:'data-parsley-minlength'=>"3"%>                                 
    </div>

    <div class="form-group">                         
        <%= f.password_field :password,:id=>"passwordis",:class=> "user-input form-control", autocomplete: "off" ,:placeholder=> t('new_password'),:required => true,:'data-parsley-minlength'=>"8" %>                                  
    </div>

    <div class="form-group">
        <%= f.password_field :password_confirmation, :id=>"password-again",:class=> "user-input form-control", autocomplete: "off" ,:'data-parsley-equalto'=>"input#passwordis",:placeholder=> t('new_password_2'),:required => true,:'data-parsley-minlength'=>"8"%>
        <%= f.hidden_field :role, :value => "user"%>
        <%= f.hidden_field :country_id, :value => @location.id%>                                                            
    </div>

    <div class="form-group">
        <%= f.email_field :email ,:class=>"user-input form-control" ,:'data-validatess' => '/blocked/checkemail',:id=>"emailito",:placeholder=> t('email'),:required => true%> 
        <h3 id="email-taken-message" style="display:none;margin-left:140px;color:red;padding-top:7px;"> <%= t('email_not_available') %> </h3>                                                                                                                 
    </div>

    <%= f.hidden_field :humanizer_question_id %> 

    <div class="question-content" style="position:relative;top:1px;">                               
        <span class="question"><%= t('question') %>:</span>
        <span class="answer">
            <%= f.label :humanizer_answer, @user.humanizer_question %>  
        </span>

        <div class="form-group" style="margin-bottom:21px;">
            <span class="question" style="margin-top:8px;"><%= t('answer') %>: *</span>                             
            <%= f.text_field :humanizer_answer ,:class=> "form-control",:required => true, :id=>"answer"%>
        </div>                                          
    </div>

    <%= f.submit t('confirm'),:class=> "blue-button btn btn-default"%>

    <%end%>

Extraction from my logs when I try to use password recovery:

Started POST "/lv/users/password" for 85.254.76.76 at 2016-09-25 14:14:59 +0300
Processing by PasswordsController#create as JS
  Parameters: {"utf8"=>"✓", "user"=>{"email"=>"myemail@gmail.com", "humanizer_question_id"=>"1", "humanizer_answer"=>"155"}, "commit"=>"ATGŪT PAROLI", "locale"=>"lv"}
  [1m[36mCountry Load (0.4ms)[0m  [1mSELECT  `countries`.* FROM `countries`  WHERE `countries`.`id` = 1 LIMIT 1[0m
  [1m[35mRegion Load (0.5ms)[0m  SELECT `regions`.* FROM `regions`  WHERE `regions`.`country_id` = 1
  [1m[36mPartner Load (0.4ms)[0m  [1mSELECT  `partners`.* FROM `partners`  WHERE `partners`.`id` = 1 LIMIT 1[0m
  [1m[35mUser Load (0.5ms)[0m  SELECT  `users`.* FROM `users`  WHERE `users`.`email` = 'edgars.rworks@gmail.com'  ORDER BY `users`.`id` ASC LIMIT 1
  [1m[36mUser Load (247.6ms)[0m  [1mSELECT  `users`.* FROM `users`  WHERE `users`.`reset_password_token` = '8ffe8d2b729cd77dd8f3b3df061e19076b87784edb5d4c10ee1466ee978257f7'  ORDER BY `users`.`id` ASC LIMIT 1[0m
  [1m[35m (0.3ms)[0m  BEGIN
  [1m[36mSQL (0.5ms)[0m  [1mUPDATE `users` SET `reset_password_sent_at` = '2016-09-25 14:15:00', `reset_password_token` = '8ffe8d2b729cd77dd8f3b3df061e19076b87784edb5d4c10ee1466ee978257f7', `updated_at` = '2016-09-25 14:15:00' WHERE `users`.`id` = 169[0m
  [1m[35m (0.3ms)[0m  COMMIT
  Rendered devise/mailer/reset_password_instructions.html.erb (4.5ms)

Devise::Mailer#reset_password_instructions: processed outbound mail in 268.7ms

Sent mail to myemail@gmail.com (129.2ms)
Date: Sun, 25 Sep 2016 14:15:00 +0300
From: support@.eu
Reply-To: support@.eu
To: @gmail.com
Message-ID: <57e7b1b4edb10_c48e740a6dc92516@if36.nano.lv.mail>
Subject: Reset password instructions
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<html>
  <head>
    <meta content=3D'text/html; charset=3DUTF-8' http-equiv=3D'Content-Ty=
pe' />
  </head>
  <body>
        <h3> Sveicin=C4=81ti, admins !</h3>
    =

        <p> K=C4=81ds ir piepras=C4=ABjis saiti, lai main=C4=ABtu paroli. To=
 var izdar=C4=ABt, izmantojot zem=C4=81k nor=C4=81d=C4=ABto saiti.</p>
    =

        <p><a href=3D"http://www.individualki.eu/users/password/edit?reset_p=
assword_token=3Dpq9s-yq74P1mwRFui13L">Main=C4=ABt savu paroli</a></p>
         <p></p>
        <p>Ja J=C5=ABs neesat piepras=C4=ABjis =C5=A1o, l=C5=ABdzu, ne=C5=86=
emiet v=C4=93r=C4=81 =C5=A1o e-pasta zi=C5=86ojumu.</p>
    =

       <p></p>
       <p>Parole nemain=C4=ABsies, ja J=C5=ABs nespied=C4=ABsiet uz saites a=
ug=C5=A1=C4=81 un nemain=C4=ABsiet to.</p>
  </body>
</html>

Completed 200 OK in 1616ms (Views: 0.7ms | ActiveRecord: 260.9ms)

Solution

  • As I couldn't find out the reason why humanizer didn't work by default behavior so I forced Humanizer validation like in this example

     def create
    
         ad = User.new
         ad.humanizer_question_id = params[:user][:humanizer_question_id]
         ad.humanizer_answer = params[:user][:humanizer_answer]
    
        if ad.humanizer_answer.present? && ad.humanizer_question_id.present?
    
            if ad.humanizer_correct_answer?
    
               usero = resource_class.send_reset_password_instructions(resource_params)       
                    if successfully_sent?(usero)
                         render json: { data: "something good" }, status: 200
                    else
                         render json: { data: "something bad successfully_sent?(usero)" }, status: 400
                    end    
    
            else
              render json: { data: "Humanizer wrong ad.humanizer_correct_answer?" }, status: 400
            end
    
         else
            render json: { data: "ad.humanizer_answer.present? || ad.humanizer_question_id.present?" }, status: 400
         end
    
    
    end