Skip to content

Commit

Permalink
Merge pull request #14266 from opf/fix/hcaptcha-configuration
Browse files Browse the repository at this point in the history
Fix hcaptcha usage and provide as a setting
  • Loading branch information
machisuji committed Nov 28, 2023
2 parents 2840cf0 + 2772945 commit 908c922
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 37 deletions.
Expand Up @@ -32,7 +32,7 @@ def validate_settings
end

def permitted_params
params.permit(:recaptcha_type, :website_key, :secret_key)
params.permit(:recaptcha_type, :website_key, :secret_key, :response_limit)
end

def default_breadcrumb
Expand Down
21 changes: 19 additions & 2 deletions modules/recaptcha/app/controllers/recaptcha/request_controller.rb
Expand Up @@ -20,10 +20,17 @@ class RequestController < ApplicationController
# Skip if user has confirmed already
before_action :skip_if_user_verified

# Ensure we set the correct configuration for rendering/verifying the captcha
around_action :set_captcha_settings

##
# Request verification form
def perform
use_content_security_policy_named_append(:recaptcha)
if OpenProject::Recaptcha::Configuration.use_hcaptcha?
use_content_security_policy_named_append(:hcaptcha)
else
use_content_security_policy_named_append(:recaptcha)
end
end

def verify
Expand All @@ -37,6 +44,16 @@ def verify

private

def set_captcha_settings(&block)
if OpenProject::Recaptcha::Configuration.use_hcaptcha?
Recaptcha.with_configuration(verify_url: OpenProject::Recaptcha.hcaptcha_verify_url,
api_server_url: OpenProject::Recaptcha.hcaptcha_api_server_url,
&block)
else
block.call
end
end

##
# Insert that the account was verified
def save_recaptcha_verification_success!
Expand All @@ -49,7 +66,7 @@ def recaptcha_version
case recaptcha_settings['recaptcha_type']
when ::OpenProject::Recaptcha::TYPE_DISABLED
0
when ::OpenProject::Recaptcha::TYPE_V2
when ::OpenProject::Recaptcha::TYPE_V2, ::OpenProject::Recaptcha::TYPE_HCAPTCHA
2
when ::OpenProject::Recaptcha::TYPE_V3
3
Expand Down
3 changes: 2 additions & 1 deletion modules/recaptcha/app/helpers/recaptcha_helper.rb
Expand Up @@ -3,7 +3,8 @@ def recaptcha_available_options
[
[I18n.t('recaptcha.settings.type_disabled'), ::OpenProject::Recaptcha::TYPE_DISABLED],
[I18n.t('recaptcha.settings.type_v2'), ::OpenProject::Recaptcha::TYPE_V2],
[I18n.t('recaptcha.settings.type_v3'), ::OpenProject::Recaptcha::TYPE_V3]
[I18n.t('recaptcha.settings.type_v3'), ::OpenProject::Recaptcha::TYPE_V3],
[I18n.t('recaptcha.settings.type_hcaptcha'), ::OpenProject::Recaptcha::TYPE_HCAPTCHA]
]
end

Expand Down
11 changes: 11 additions & 0 deletions modules/recaptcha/app/views/recaptcha/admin/show.html.erb
Expand Up @@ -17,6 +17,7 @@
</div>
<div class="form--field-instructions">
<%= I18n.t('recaptcha.settings.recaptcha_description_html',
hcaptcha_link: link_to('https://docs.hcaptcha.com/switch/', 'https://docs.hcaptcha.com/switch/', target: '_blan'),
recaptcha_link: link_to('https://www.google.com/recaptcha', 'https://www.google.com/recaptcha', target: '_blank')).html_safe %>
</div>
</div>
Expand All @@ -40,6 +41,16 @@
<%= I18n.t('recaptcha.settings.secret_key_text') %>
</div>
</div>
<div class="form--field">
<label class="form--label" for='secret_key'><%= t('recaptcha.settings.response_limit') %></label>
<div class="form--field-container">
<%= styled_text_field_tag 'response_limit',
Setting.plugin_openproject_recaptcha['response_limit'] %>
</div>
<div class="form--field-instructions">
<%= I18n.t('recaptcha.settings.response_limit_text') %>
</div>
</div>
</fieldset>
<%= styled_submit_tag t(:button_apply), class: '-highlight' %>
<% end %>
Expand Down
Expand Up @@ -3,13 +3,13 @@
<div id="login-form" class="form -bordered">
<%= styled_form_tag({ action: :verify }, { :autocomplete => "off", :id => 'submit_captcha' }) do %>
<h2><%= t 'recaptcha.verify_account' %></h2>
<% if recaptcha_settings['recaptcha_type'] == ::OpenProject::Recaptcha::TYPE_V2 %>
<% if [OpenProject::Recaptcha::TYPE_V2, OpenProject::Recaptcha::TYPE_HCAPTCHA].include?(recaptcha_settings['recaptcha_type']) %>
<% input_name = "g-recaptcha-response" %>
<input type="hidden" name="<%= input_name %>" />
<%= recaptcha_tags(
nonce: content_security_policy_script_nonce,
callback: 'submitRecaptchaForm',
site_key: recaptcha_settings['website_key']
site_key: recaptcha_settings['website_key'],
) %>
<%= nonced_javascript_tag do %>
Expand Down
7 changes: 0 additions & 7 deletions modules/recaptcha/config/initializers/recaptcha.rb
@@ -1,10 +1,3 @@
Recaptcha.configure do |config|
# site_key and secret_key are defined via ENV already (RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY)

config.verify_url = OpenProject::Recaptcha.verify_url_override || config.verify_url
config.api_server_url = OpenProject::Recaptcha.api_server_url_override || config.api_server_url
end

module RecaptchaLimitOverride
def invalid_response?(resp)
return super unless OpenProject::Recaptcha::use_hcaptcha?
Expand Down
6 changes: 6 additions & 0 deletions modules/recaptcha/config/locales/en.yml
Expand Up @@ -10,16 +10,22 @@ en:
error_captcha: "Your account could not be verified. Please contact an administrator."
settings:
website_key: 'Website key'
response_limit: 'Response limit for HCaptcha'
response_limit_text: 'The maximum number of characters to treat the HCaptcha response as valid.'
website_key_text: 'Enter the website key you created on the reCAPTCHA admin console for this domain.'
secret_key: 'Secret key'
secret_key_text: 'Enter the secret key you created on the reCAPTCHA admin console.'
type: 'Use reCAPTCHA'
type_disabled: 'Disable reCAPTCHA'
type_v2: 'reCAPTCHA v2'
type_v3: 'reCAPTCHA v3'
type_hcaptcha: 'HCaptcha'
recaptcha_description_html: >
reCAPTCHA is a free service by Google that can be enabled for your OpenProject instance.
If enabled, a captcha form will be rendered upon login for all users that have not verified a captcha yet.
<br/>
Please see the following link for more details on reCAPTCHA and their versions, and how
to create the website and secret keys: %{recaptcha_link}
<br/>
HCaptcha is a Google-free alternative that you can use if you do not want to use reCAPTCHA.
See this link for more information: %{hcaptcha_link}
1 change: 1 addition & 0 deletions modules/recaptcha/lib/open_project/recaptcha.rb
Expand Up @@ -3,6 +3,7 @@ module Recaptcha
TYPE_DISABLED ||= 'disabled'
TYPE_V2 ||= 'v2'
TYPE_V3 ||= 'v3'
TYPE_HCAPTCHA ||= 'hcaptcha'

require "open_project/recaptcha/engine"
require "open_project/recaptcha/configuration"
Expand Down
16 changes: 8 additions & 8 deletions modules/recaptcha/lib/open_project/recaptcha/configuration.rb
Expand Up @@ -5,20 +5,20 @@ module Configuration

extend self

def use_hcaptcha?
OpenProject::Configuration[CONFIG_KEY]
def enabled?
type.present? && type != ::OpenProject::Recaptcha::TYPE_DISABLED
end

def hcaptcha_response_limit
@hcaptcha_response_limit ||= (ENV["RECAPTCHA_RESPONSE_LIMIT"].presence || 5000).to_i
def use_hcaptcha?
type == ::OpenProject::Recaptcha::TYPE_HCAPTCHA
end

def api_server_url_override
ENV["RECAPTCHA_API_SERVER_URL"].presence || ((use_hcaptcha? || nil) && hcaptcha_api_server_url)
def type
@type ||= ::Setting.plugin_openproject_recaptcha['recaptcha_type']
end

def verify_url_override
ENV["RECAPTCHA_VERIFY_URL"].presence || ((use_hcaptcha? || nil) && hcaptcha_verify_url)
def hcaptcha_response_limit
(::Setting.plugin_openproject_recaptcha['response_limit'] || '5000').to_i
end

def hcaptcha_verify_url
Expand Down
29 changes: 13 additions & 16 deletions modules/recaptcha/lib/open_project/recaptcha/engine.rb
Expand Up @@ -11,7 +11,8 @@ class Engine < ::Rails::Engine
author_url: 'https://www.openproject.org',
settings: {
default: {
recaptcha_type: ::OpenProject::Recaptcha::TYPE_DISABLED
recaptcha_type: ::OpenProject::Recaptcha::TYPE_DISABLED,
response_limit: 5000,
}
},
bundled: true do
Expand All @@ -28,27 +29,23 @@ class Engine < ::Rails::Engine

config.after_initialize do
SecureHeaders::Configuration.named_append(:recaptcha) do
if OpenProject::Recaptcha.use_hcaptcha?
value = %w(https://*.hcaptcha.com)
keys = %i(frame_src script_src style_src connect_src)

keys.index_with value
else
{
frame_src: %w[https://www.recaptcha.net/recaptcha/ https://www.gstatic.com/recaptcha/]
}
end
{
frame_src: %w[https://www.recaptcha.net/recaptcha/ https://www.gstatic.com/recaptcha/]
}
end

SecureHeaders::Configuration.named_append(:hcaptcha) do
value = %w(https://*.hcaptcha.com)
keys = %i(frame_src script_src style_src connect_src)

keys.index_with value
end

OpenProject::Authentication::Stage.register(
:recaptcha,
nil,
run_after_activation: true,
active: -> {
type = Setting.plugin_openproject_recaptcha['recaptcha_type']

type.present? && type.to_s != ::OpenProject::Recaptcha::TYPE_DISABLED
}
active: -> { OpenProject::Recaptcha.enabled? }
) do
recaptcha_request_path
end
Expand Down

0 comments on commit 908c922

Please sign in to comment.