Class: BotChallengePage::BotChallengePageController

Inherits:
ApplicationController
  • Object
show all
Includes:
GuardAction
Defined in:
app/controllers/bot_challenge_page/bot_challenge_page_controller.rb

Constant Summary collapse

SESSION_DATETIME_KEY =
"t"
SESSION_FINGERPRINT_KEY =
"f"

Instance Method Summary collapse

Instance Method Details

#challengeObject

only used if config.redirect_for_challenge is true



27
28
29
30
31
32
33
34
35
# File 'app/controllers/bot_challenge_page/bot_challenge_page_controller.rb', line 27

def challenge
  # possible custom render to choose layouts or templates, but
  # default is what would be default template for this action
  #
  # We put it in instancevar as a hacky way of passing to template that can be fulfilled
  # both here and in arbitrary controllers for direct render.
  @bot_challenge_config = bot_challenge_config
  instance_exec &self.bot_challenge_config.challenge_renderer
end

#verify_challengeObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'app/controllers/bot_challenge_page/bot_challenge_page_controller.rb', line 37

def verify_challenge
  body = {
    secret: self.bot_challenge_config.cf_turnstile_secret_key,
    response: params["cf_turnstile_response"],
    remoteip: request.remote_ip,
  }

  http = HTTP.timeout(self.bot_challenge_config.cf_timeout)
  response = http.post(self.bot_challenge_config.cf_turnstile_validation_url,
    json: body)

  result = response.parse
  # {"success"=>true, "error-codes"=>[], "challenge_ts"=>"2025-01-06T17:44:28.544Z", "hostname"=>"example.com", "metadata"=>{"result_with_testing_key"=>true}}
  # {"success"=>false, "error-codes"=>["invalid-input-response"], "messages"=>[], "metadata"=>{"result_with_testing_key"=>true}}

  if result["success"]
    # mark it as succesful in session, and record time. They do need a session/cookies
    # to get through the challenge.
    Rails.logger.info("#{self.class.name}: Cloudflare Turnstile validation passed api (#{request.remote_ip}, #{request.user_agent}): #{params["dest"]}")
    session[self.bot_challenge_config.session_passed_key] = {
      SESSION_DATETIME_KEY => Time.now.utc.iso8601,
      SESSION_FINGERPRINT_KEY   => self.bot_challenge_config.session_valid_fingerprint.call(request)
    }
  else
    Rails.logger.warn("#{self.class.name}: Cloudflare Turnstile validation failed (#{request.remote_ip}, #{request.user_agent}): #{result}: #{params["dest"]}")
  end

  # add config needed by JS to result
  result["redirect_for_challenge"] = self.bot_challenge_config.redirect_for_challenge

  # and let's just return the whole thing to client? Is there anything confidential there?
  render json: result
rescue HTTP::Error, JSON::ParserError => e
  # probably an http timeout? or something weird.
  Rails.logger.warn("#{self.class.name}: Cloudflare turnstile validation error (#{request.remote_ip}, #{request.user_agent}): #{e}: #{response&.body}")
  render json: {
    success: false,
    http_exception: e
  }
end