From 6ee92c839be4496ddf72307cd82adc41292daf1a Mon Sep 17 00:00:00 2001
From: Ahmad Farhat <ahmad.af.farhat@gmail.com>
Date: Tue, 26 Jan 2021 19:44:23 -0500
Subject: [PATCH] Added recaptcha to reset password if enabled (#2475)

---
 app/controllers/password_resets_controller.rb | 28 ++++++++------
 app/views/password_resets/new.html.erb        |  6 +++
 config/locales/en.yml                         |  1 +
 .../password_resets_controller_spec.rb        | 37 +++++++++++++++++++
 4 files changed, 61 insertions(+), 11 deletions(-)

diff --git a/app/controllers/password_resets_controller.rb b/app/controllers/password_resets_controller.rb
index 73ea364a..cd95b13c 100644
--- a/app/controllers/password_resets_controller.rb
+++ b/app/controllers/password_resets_controller.rb
@@ -23,22 +23,22 @@ class PasswordResetsController < ApplicationController
   before_action :find_user, only: [:edit, :update]
   before_action :check_expiration, only: [:edit, :update]
 
-  # POST /password_resets/new
+  # GET /password_resets/new
   def new
   end
 
   # POST /password_resets
   def create
-    begin
-      # Check if user exists and throw an error if he doesn't
-      @user = User.find_by!(email: params[:password_reset][:email].downcase, provider: @user_domain)
-
-      send_password_reset_email(@user, @user.create_reset_digest)
-      redirect_to root_path
-    rescue
-      # User doesn't exist
-      redirect_to root_path, flash: { success: I18n.t("email_sent", email_type: t("reset_password.subtitle")) }
-    end
+    return redirect_to new_password_reset_path, flash: { alert: I18n.t("reset_password.captcha") } unless valid_captcha
+
+    # Check if user exists and throw an error if he doesn't
+    @user = User.find_by!(email: params[:password_reset][:email].downcase, provider: @user_domain)
+
+    send_password_reset_email(@user, @user.create_reset_digest)
+    redirect_to root_path
+  rescue
+    # User doesn't exist
+    redirect_to root_path, flash: { success: I18n.t("email_sent", email_type: t("reset_password.subtitle")) }
   end
 
   # GET /password_resets/:id/edit
@@ -84,4 +84,10 @@ class PasswordResetsController < ApplicationController
   def disable_password_reset
     redirect_to '/404'
   end
+
+  # Checks that the captcha passed is valid
+  def valid_captcha
+    return true unless Rails.configuration.recaptcha_enabled
+    verify_recaptcha
+  end
 end
diff --git a/app/views/password_resets/new.html.erb b/app/views/password_resets/new.html.erb
index 69a703a8..285d9d34 100644
--- a/app/views/password_resets/new.html.erb
+++ b/app/views/password_resets/new.html.erb
@@ -25,6 +25,12 @@
             <%= f.label :email, t("forgot_password.email"), class: "form-label" %>
             <%= f.email_field :email, class: "form-control" %>
             <br>
+
+            <% if recaptcha_enabled? %>
+              <div class="form-group">
+                <%= recaptcha_tags %>
+              </div>
+            <% end %>
       
             <%= f.submit t("forgot_password.submit"), class: "btn btn-primary" %>
           <% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index bfc1ae18..81bbc13c 100755
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -526,6 +526,7 @@ en:
   remove: Remove
   rename: Rename
   reset_password:
+    captcha: reCAPTCHA verification failed, please try again.
     invalid_token: Password reset token is invalid. Please try resetting your password again.
     subtitle: Reset Password
     password: New Password
diff --git a/spec/controllers/password_resets_controller_spec.rb b/spec/controllers/password_resets_controller_spec.rb
index 429b993b..e18dc1db 100644
--- a/spec/controllers/password_resets_controller_spec.rb
+++ b/spec/controllers/password_resets_controller_spec.rb
@@ -71,6 +71,43 @@ describe PasswordResetsController, type: :controller do
         expect(response).to redirect_to("/404")
       end
     end
+
+    context "reCAPTCHA enabled" do
+      before do
+        allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
+        allow(Rails.configuration).to receive(:recaptcha_enabled).and_return(true)
+      end
+
+      it "sends a reset email if the recaptcha was passed" do
+        allow(controller).to receive(:valid_captcha).and_return(true)
+
+        user = create(:user, provider: "greenlight")
+
+        params = {
+          password_reset: {
+            email: user.email,
+          },
+        }
+
+        expect { post :create, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
+      end
+
+      it "doesn't send an email if the recaptcha was failed" do
+        allow(controller).to receive(:valid_captcha).and_return(false)
+
+        user = create(:user)
+
+        params = {
+          password_reset: {
+            email: user.email,
+          },
+        }
+
+        post :create, params: params
+        expect(response).to redirect_to(new_password_reset_path)
+        expect(flash[:alert]).to be_present
+      end
+    end
   end
 
   describe "PATCH #update" do
-- 
GitLab