From 179b877c1258a093524aa37b7831954ebe9ba505 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 24 Oct 2023 19:35:09 +0100 Subject: [PATCH] Add support for using an cloudflare turnstile widget during signup --- .rubocop_todo.yml | 2 +- app/controllers/users_controller.rb | 40 ++++++++++++++++++++++++++--- app/views/users/new.html.erb | 10 ++++++++ config/locales/en.yml | 3 +++ config/settings.yml | 3 +++ 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index db94a610b8f..2d8c9d32c51 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -61,7 +61,7 @@ Metrics/BlockNesting: # Offense count: 26 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 285 + Max: 295 # Offense count: 59 # Configuration parameters: AllowedMethods, AllowedPatterns. diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 5ba1b702bf9..549eb068fe8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -17,6 +17,7 @@ class UsersController < ApplicationController before_action :require_cookies, :only => [:new] before_action :lookup_user_by_name, :only => [:set_status, :destroy] before_action :allow_thirdparty_images, :only => [:show] + before_action :set_content_security_policy, :only => [:new, :create] ## # display a list of users matching specified criteria @@ -61,10 +62,6 @@ def new session[:referer] end - append_content_security_policy_directives( - :form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org] - ) - if current_user # The user is logged in already, so don't show them the signup # page, instead send them to the home page @@ -102,6 +99,10 @@ def create if current_user.invalid? # Something is wrong with a new user, so rerender the form render :action => "new" + elsif Settings.turnstile_site_key && !valid_turnstile_response?(params["cf-turnstile-response"]) + # Invalid turnstile response, so rerender the form + flash.now[:error] = t ".not_human" + render :action => "new" elsif current_user.auth_provider.present? # Verify external authenticator before moving on session[:new_user] = current_user @@ -362,4 +363,35 @@ def check_signup_allowed(email = nil) !blocked end + + ## + # add additional CSP rules for signup page + def set_content_security_policy + append_content_security_policy_directives( + :form_action => %w[accounts.google.com *.facebook.com login.live.com github.com meta.wikimedia.org] + ) + + if Settings.turnstile_site_key + append_content_security_policy_directives( + :frame_src => %w[challenges.cloudflare.com], + :script_src => %w[challenges.cloudflare.com] + ) + end + end + + ## + # check if a turnstile response is valid + def valid_turnstile_response?(turnstile_response) + response = OSM.http_client.post("https://challenges.cloudflare.com/turnstile/v0/siteverify", { + :secret => Settings.turnstile_secret_key, + :response => turnstile_response, + :remoteip => request.remote_ip + }) + + return false unless response.success? + + parsed_response = JSON.parse(response.body) + + parsed_response["success"] + end end diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb index 27e98b45b3d..6d4bce07b48 100644 --- a/app/views/users/new.html.erb +++ b/app/views/users/new.html.erb @@ -1,5 +1,8 @@ <% content_for :head do %> <%= javascript_include_tag "user" %> + <% if Settings.turnstile_site_key -%> + <%= javascript_include_tag "https://challenges.cloudflare.com/turnstile/v0/api.js", :async => true, :defer => true %> + <% end -%> <% end %> <% content_for :heading_class, "pb-0" %> @@ -42,6 +45,13 @@ <%= f.password_field :pass_crypt, :tabindex => 6 %> <%= f.password_field :pass_crypt_confirmation, :tabindex => 7 %> + <% if Settings.turnstile_site_key -%> +
+ +
+
+ <% end %> +

<%= link_to t(".use external auth"), "#", :id => "auth_enable" %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index cd7d67947b7..feea33e69c0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2666,6 +2666,9 @@ en: privacy_policy: privacy policy privacy_policy_url: https://wiki.osmfoundation.org/wiki/Privacy_Policy privacy_policy_title: OSMF privacy policy including section on email addresses + verify_human: Verify you're a human + create: + not_human: Human verification failed terms: title: "Terms" heading: "Terms" diff --git a/config/settings.yml b/config/settings.yml index cffd3bd316e..4dbf9e81529 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -159,3 +159,6 @@ smtp_password: null # -----BEGIN PRIVATE KEY----- # ... # -----END PRIVATE KEY----- +# Credentials for optional cloudflare turnstile widget +#turnstile_site_key: +#turnstile_secret_key: