From b19131202fd4f535845b84cf2bd7ba2a5184fa1c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 23 Jul 2025 03:55:54 -0400 Subject: [PATCH] Extract constants for captcha directives/sources (#35439) --- .../concerns/auth/captcha_concern.rb | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/app/controllers/concerns/auth/captcha_concern.rb b/app/controllers/concerns/auth/captcha_concern.rb index c01da21249..a6232db943 100644 --- a/app/controllers/concerns/auth/captcha_concern.rb +++ b/app/controllers/concerns/auth/captcha_concern.rb @@ -5,6 +5,18 @@ module Auth::CaptchaConcern include Hcaptcha::Adapters::ViewMethods + CAPTCHA_DIRECTIVES = %w( + connect_src + frame_src + script_src + style_src + ).freeze + + CAPTCHA_SOURCES = %w( + https://*.hcaptcha.com + https://hcaptcha.com + ).freeze + included do helper_method :render_captcha end @@ -42,20 +54,9 @@ module Auth::CaptchaConcern end def extend_csp_for_captcha! - policy = request.content_security_policy&.clone + return unless captcha_required? && request.content_security_policy.present? - 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 - - request.content_security_policy = policy + request.content_security_policy = captcha_adjusted_policy end def render_captcha @@ -63,4 +64,24 @@ module Auth::CaptchaConcern hcaptcha_tags end + + private + + def captcha_adjusted_policy + request.content_security_policy.clone.tap do |policy| + populate_captcha_policy(policy) + end + end + + def populate_captcha_policy(policy) + CAPTCHA_DIRECTIVES.each do |directive| + values = policy.send(directive) + + CAPTCHA_SOURCES.each do |source| + values << source unless values.include?(source) || values.include?('https:') + end + + policy.send(directive, *values) + end + end end