-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a Cloudflare Turnstill captcha to the signup form
In the Postmark activity I've noticed a lot of "verify your email" messages being sent and not actioned. Many of these are bouncing, which hurts our email deliverability. Anecdotally more legitimate emails from jam.coop are going to spam than before. To mitigate this I've added a Cloudflare Turnstile[1] "captcha" to the registration form to hopefully prevent these non-genuine signups (which I assume are from scripts) from occuring. I decided to use the rails-cloudflare-turnstile[2] gem to do the heavy lifting here, primarily to avoid having to write the code that makes the verfication request to the cloudflare API[3]. I've mostly followed the setup instructions for that gem with a couple of changes: 1. I've disabled the gem-provided mock in favour of using Cloudflare's development/testing tokens so that we can see the real capture locally. 2. Because we use turbo I've had to do ensure that the cloudflare script is always loaded and reloaded when the signup page is visited or re-rendered after a validation error. Setting `data-turbo=false` on the signup form ensures that it is submitted without turbo and therefore releads the cloudflare JS widget on re-render. Including the cloudflare script with the `data-turbo-track` and `data-turbo-temporary` options ensures that it is reloaded if the user navigates away from signup and back again. I've also set the two new ENV variables using the credentials provided by Cloudflare[4]. [1] https://developers.cloudflare.com/turnstile/ [2] https://github.com/instrumentl/rails-cloudflare-turnstile [3] https://github.com/instrumentl/rails-cloudflare-turnstile/blob/main/lib/rails_cloudflare_turnstile/controller_helpers.rb [4] https://dash.cloudflare.com/
- Loading branch information
Showing
9 changed files
with
62 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,14 @@ | ||
<% content_for :head do %> | ||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer data-turbo-track="reload" data-turbo-temporary="true"></script> | ||
<% end %> | ||
|
||
<%= render 'shared/page_header', text: 'Sign up' %> | ||
|
||
<%= form_with(url: sign_up_path, builder: TailwindFormBuilder) do |form| %> | ||
<%= form_with(url: sign_up_path, builder: TailwindFormBuilder, data: { turbo: false }) do |form| %> | ||
<%= render('shared/errors', model: @user) %> | ||
<%= form.email_field :email, value: @user.email, required: true, autofocus: true, autocomplete: "email", class: 'w-full mb-3' %> | ||
<%= form.password_field :password, required: true, autocomplete: "new-password", class: 'w-full mb-3' %> | ||
<%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", class: 'w-full mb-3' %> | ||
<%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", class: 'w-full mb-6' %> | ||
<%= cloudflare_turnstile %> | ||
<%= form.submit "Sign up", class: 'w-full mt-6' %> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
RailsCloudflareTurnstile.configure do |c| | ||
c.site_key = ENV.fetch('CLOUDFLARE_TURNSTILE_SITE_KEY') | ||
c.secret_key = ENV.fetch('CLOUDFLARE_TURNSTILE_SECRET_KEY') | ||
c.fail_open = true | ||
c.mock_enabled = false | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,9 @@ | |
|
||
class RegistrationsControllerTest < ActionDispatch::IntegrationTest | ||
def setup | ||
stub_request(:post, 'https://challenges.cloudflare.com/turnstile/v0/siteverify') | ||
.to_return(status: 200, body: { success: true }.to_json) | ||
|
||
@album = create(:album) | ||
log_in_as(create(:user, admin: true)) | ||
end | ||
|
@@ -58,4 +61,14 @@ def setup | |
assert_response :unprocessable_entity | ||
assert_select 'h2', text: /errors prohibited this user from being saved/ | ||
end | ||
|
||
test '#create makes a call to the cloudflare turnstile API to validate the request' do | ||
post sign_up_url, params: { | ||
email: '[email protected]', | ||
password: 'Secret1*3*5*', | ||
password_confirmation: 'Secret1*3*5*' | ||
} | ||
|
||
assert_requested :post, 'https://challenges.cloudflare.com/turnstile/v0/siteverify' | ||
end | ||
end |