diff options
author | Claire <claire.github-309c@sitedethib.com> | 2022-01-24 19:06:19 +0100 |
---|---|---|
committer | Claire <claire.github-309c@sitedethib.com> | 2022-01-24 21:22:13 +0100 |
commit | 1b493c9fee954b5bd4c4b00f9f945a5d97e2d699 (patch) | |
tree | 902087cb4c658f83570db7aa7ae08d324e1a94ef /app/controllers/concerns | |
parent | e58e0eb9aa375b1107b207e8229a2142c4edc0b8 (diff) |
Add optional hCaptcha support
Fixes #1649 This requires setting `HCAPTCHA_SECRET_KEY` and `HCAPTCHA_SITE_KEY`, then enabling the admin setting at `/admin/settings/edit#form_admin_settings_captcha_enabled` Subsequently, a hCaptcha widget will be displayed on `/about` and `/auth/sign_up` unless: - the user is already signed-up already - the user has used an invite link - the user has already solved the captcha (and registration failed for another reason) The Content-Security-Policy headers are altered automatically to allow the third-party hCaptcha scripts on `/about` and `/auth/sign_up` following the same rules as above.
Diffstat (limited to 'app/controllers/concerns')
-rw-r--r-- | app/controllers/concerns/captcha_concern.rb | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/app/controllers/concerns/captcha_concern.rb b/app/controllers/concerns/captcha_concern.rb new file mode 100644 index 000000000..5a23e59e3 --- /dev/null +++ b/app/controllers/concerns/captcha_concern.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module CaptchaConcern + extend ActiveSupport::Concern + include Hcaptcha::Adapters::ViewMethods + + CAPTCHA_TIMEOUT = 2.hours.freeze + + included do + helper_method :render_captcha_if_needed + end + + def captcha_available? + ENV['HCAPTCHA_SECRET_KEY'].present? && ENV['HCAPTCHA_SITE_KEY'].present? + end + + def captcha_enabled? + captcha_available? && Setting.captcha_enabled + end + + def captcha_recently_passed? + session[:captcha_passed_at].present? && session[:captcha_passed_at] >= CAPTCHA_TIMEOUT.ago + end + + def captcha_required? + captcha_enabled? && !current_user && !(@invite.present? && @invite.valid_for_use? && !@invite.max_uses.nil?) && !captcha_recently_passed? + end + + def clear_captcha! + session.delete(:captcha_passed_at) + end + + def check_captcha! + return true unless captcha_required? + + if verify_hcaptcha + session[:captcha_passed_at] = Time.now.utc + return true + else + if block_given? + message = flash[:hcaptcha_error] + flash.delete(:hcaptcha_error) + yield message + end + return false + end + end + + def extend_csp_for_captcha! + policy = request.content_security_policy + return unless captcha_required? && policy.present? + + %w(script_src frame_src style_src connect_src).each do |directive| + values = policy.send(directive) + values << 'https://hcaptcha.com' unless values.include?('https://hcaptcha.com') || values.include?('https:') + values << 'https://*.hcaptcha.com' unless values.include?('https://*.hcaptcha.com') || values.include?('https:') + policy.send(directive, *values) + end + end + + def render_captcha_if_needed + return unless captcha_required? + + hcaptcha_tags + end +end |