Turnstile Wiki - OregonDigital/OD2 GitHub Wiki

Turnstile Overview

Turnstile is a library made by Cloudflare which acts as a pragmatic turnstile, which counts and lets certain types of user into the application. This can be added to any page by simply telling the controller to redirect to the challenge page before it processes any request.

By utilizing turnstile in an application, we have successfully slowed the bot problem that is plaguing the internet. Continuing to add it to more pages as needed will be done when the needs arise.

The controllers that contain this code are in app/controllers/catalog_controller.rb and all the models contained in app/controllers/hyrax/ such as the generics_controller, audios_controller, etc.

Key Code Snippets

# Redirect for Bot Detection
  before_action except: :oai do |controller|
    BotDetectionController.bot_detection_enforce_filter(controller) unless valid_bot?
  end

The code snippet above is what redirects a user to the bot detection code. This can be added to any controller. We detect certain 'Good Bots' using the valid bot method that can be added to a page as well

def valid_bot?
  ENV.fetch('URI_TURNSTILE_BYPASS', '').split(',').include?(request.domain) || allow_listed_ip_addr?
end

The snippet above looks at the environment variables stored in URI_TURNSTILE_BYPASS which is delimited using commas. We can then detect certain allow listed IP addresses as well.

  def allow_listed_ip_addr?
    ips = ENV.fetch('IP_TURNSTILE_BYPASS', '')
    ranges = ips.split(',')
    ranges.each do |range|
      range = range.split('-')
      range = (IPAddr.new(range[0]).to_i..IPAddr.new(range[1]).to_i)
      return true if range.include?(IPAddr.new(request.remote_ip).to_i)
    end
    false
  end

You can express an IP range utilizing a dash (i.e 127.0.0.1-127.0.0.2) and these are delimited by using a comma as well.

By utilizing the above code snippets it is configured to block all bots that aren't in the list of allowed bots and allowed IP addresses.

Bot Detection Controller

The bulk of the bot detection happens in this controller. This controller is what drives the challenge page which will be discussed later. It sets more environment variables specifically for cloudflare to store and issue challenges. It contains a site key, secret key, validation url, timeout duration, enabled/disabled, and the javascript url.

CF_TURNSTILE_SITE_KEY and CF_TURNSTILE_SECRET_KEY can be found in the list of ENV variables on our production server.

This controller issues the challenge, checks whether the challenge was passed properly, then renders or redirects depending on whether the test was passed. This code shouldn't need to be altered much.

Challenge Page

The site renders a challenge page which is found in app/views/bot_detection/challenge.html.erb

This page shouldn't be needed to be altered much either. It does an ajax request to the controller after it runs the javascript. It takes the destination someone was going to and puts it as the new href and will go there when the ajax comes back as success.

The important piece here is the destination. This is clipped from the URL and held onto. We need to know where the user was going, specifically for things like searches.