rails_cloudflare_turnstile 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7ce536746c6d1d1f449d59496cfa6c8f03473cdce982577ae6972700a9508cc9
4
+ data.tar.gz: 9044b74740d86b7e7b32bb541ea8aff5c91aa316b024fc5a8b273194aea3676d
5
+ SHA512:
6
+ metadata.gz: bc15941cad051ee625472d759b848c69a26a2d0eb2e24d41f49484c9e82421df220f5780ed6978243c7e4983823a6df14a04194dce6e5dfef102a74f43af26e7
7
+ data.tar.gz: e83b60d1b28fdb0b958444f7c20b66dd4e1aef49201b62a66f01883f059229b2dbfde15a99b9b45771af45476044ddfe600117a628800eec24bfcb7b907b3e01
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # RailsCloudflareTurnstile
2
+
3
+ This is a Rails plugin adding support for [Cloudflare Turnstile](https://www.cloudflare.com/products/turnstile/)
4
+
5
+ ## Usage
6
+ How to use my plugin.
7
+
8
+ ## Installation
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'rails_cloudflare_turnstile'
13
+ ```
14
+
15
+ And then execute:
16
+ ```bash
17
+ $ bundle
18
+ ```
19
+
20
+ Or install it yourself as:
21
+ ```bash
22
+ $ gem install rails_cloudflare_turnstile
23
+ ```
24
+
25
+ Next, configure it by creating a `config/initializers/cloudflare_turnstile.rb` with contents like the following:
26
+
27
+ ```ruby
28
+ RailsCloudflareTurnstile.configure do |c|
29
+ c.site_key = "XXXXXX"
30
+ c.secret_key = "XXXXXXXX"
31
+ c.fail_open = true
32
+ end
33
+ ```
34
+
35
+ To totally disable Turnstile, you can set `c.enabled = false` and all other config values are ignored.
36
+
37
+ To use Turnstile for a view:
38
+
39
+ 1. Call `cloudflare_turnstile_script_tag` in your layout
40
+ 2. Call `cloudflare_turnstile` in your form View
41
+ 3. Call `validate_cloudflare_turnstile` as a `before_action` in your controller.
42
+
43
+ If the challenge fails, the exception `RailsCloudflareTurnstile::Forbidden` will be raised; you should handle this with
44
+ a `rescue_from` block.
45
+
46
+ ## License
47
+ The gem is available as open source under the terms of the [ISC License](LICENSE.txt).
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rake/testtask"
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.pattern = "test/**/*_test.rb"
10
+ t.verbose = false
11
+ end
12
+
13
+ task default: :test
@@ -0,0 +1,45 @@
1
+ module RailsCloudflareTurnstile
2
+ class Configuration
3
+ # site key (your public key)
4
+ attr_accessor :site_key
5
+
6
+ # secret key
7
+ attr_accessor :secret_key
8
+
9
+ # if true, then a failure to contact cloudflare will allow all requests
10
+ # if false, then a failure to contact cloudflare will block all requests
11
+ # defaults to true
12
+ attr_accessor :fail_open
13
+
14
+ attr_accessor :validation_url
15
+
16
+ # Timeout for operations with Cloudflare
17
+ attr_accessor :timeout
18
+
19
+ # size for the widget ("regular" or "compact")
20
+ attr_accessor :size
21
+
22
+ attr_accessor :enabled
23
+
24
+ def initialize
25
+ @site_key = nil
26
+ @secret_key = nil
27
+ @fail_open = true
28
+ @enabled = nil
29
+ @timeout = 5.0
30
+ @size = :regular
31
+ @validation_url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
32
+ end
33
+
34
+ def validate!
35
+ raise "Must set site key" if @site_key.nil?
36
+ raise "Must set secret key" if @secret_key.nil?
37
+ @size = @size.to_sym
38
+ raise "Size must be one of ':regular' or ':compact'" unless [:regular, :compact].include? @size
39
+ end
40
+
41
+ def disabled?
42
+ @enabled == false
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+
5
+ module RailsCloudflareTurnstile
6
+ module ControllerHelpers
7
+ def cloudflare_turnstile_ok?
8
+ return true unless RailsCloudflareTurnstile.enabled?
9
+
10
+ config = RailsCloudflareTurnstile.configuration
11
+
12
+ url = URI(config.validation_url)
13
+
14
+ body = {
15
+ secret: config.secret_key,
16
+ response: params["cf-turnstile-response"],
17
+ remoteip: request.remote_ip
18
+ }
19
+
20
+ begin
21
+ resp = Faraday.new(url) { |conn|
22
+ conn.options.timeout = config.timeout
23
+ conn.options.open_timeout = config.timeout
24
+ conn.use Faraday::Response::RaiseError
25
+ conn.request :json
26
+ conn.response :json
27
+ }.post(url, body)
28
+ rescue Faraday::Error => e
29
+ Rails.logger.error "Error response from CloudFlare Turnstile: #{e}"
30
+ if config.fail_open
31
+ return true
32
+ else
33
+ return false
34
+ end
35
+ end
36
+
37
+ json = resp.body
38
+
39
+ success = json["success"]
40
+
41
+ return true if success
42
+
43
+ error = json["error-codes"][0]
44
+
45
+ ActiveSupport::Notifications.instrument(
46
+ "rails_cloudflare_turnstile.failure",
47
+ message: error,
48
+ remote_ip: request.remote_ip,
49
+ user_agent: request.user_agent,
50
+ controller: params[:controller],
51
+ action: params[:action],
52
+ url: request.url
53
+ )
54
+
55
+ false
56
+ end
57
+
58
+ private
59
+
60
+ def validate_cloudflare_turnstile
61
+ return if cloudflare_turnstile_ok?
62
+ raise RailsCloudflareTurnstile::Forbidden
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module RailsCloudflareTurnstile
2
+ class Error < StandardError
3
+ end
4
+
5
+ class Forbidden < Error
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module RailsCloudflareTurnstile
2
+ class Railtie < ::Rails::Railtie
3
+ initializer "rails_cloudflare_turnstile" do
4
+ ActiveSupport.on_load(:action_controller) do
5
+ include RailsCloudflareTurnstile::ControllerHelpers
6
+ end
7
+
8
+ ActiveSupport.on_load(:action_view) do
9
+ include RailsCloudflareTurnstile::ViewHelpers
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module RailsCloudflareTurnstile
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsCloudflareTurnstile
4
+ module ViewHelpers
5
+ def cloudflare_turnstile(action: "other")
6
+ return nil unless RailsCloudflareTurnstile.enabled?
7
+ content_tag(:div, class: "cloudflare-turnstile") do
8
+ concat turnstile_div(action)
9
+ end
10
+ end
11
+
12
+ def cloudflare_turnstile_script_tag
13
+ return nil unless RailsCloudflareTurnstile.enabled?
14
+ content_tag(:script, :src => js_src, "async" => true) do
15
+ ""
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def turnstile_div(action)
22
+ config = RailsCloudflareTurnstile.configuration
23
+ content_tag(:div, :class => "cf-turnstile", "data-sitekey" => site_key, "data-size" => config.size, "data-action" => action) do
24
+ ""
25
+ end
26
+ end
27
+
28
+ def site_key
29
+ RailsCloudflareTurnstile.configuration.site_key
30
+ end
31
+
32
+ def js_src
33
+ "https://challenges.cloudflare.com/turnstile/v0/api.js"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ require "rails_cloudflare_turnstile/version"
2
+ require "rails_cloudflare_turnstile/configuration"
3
+ require "rails_cloudflare_turnstile/errors"
4
+ require "rails_cloudflare_turnstile/controller_helpers"
5
+ require "rails_cloudflare_turnstile/view_helpers"
6
+ require "rails_cloudflare_turnstile/railtie"
7
+
8
+ module RailsCloudflareTurnstile
9
+ LOCK = Mutex.new
10
+
11
+ def self.configure
12
+ yield(configuration) if block_given?
13
+ unless configuration.disabled?
14
+ configuration.validate!
15
+ end
16
+ if configuration.enabled.nil?
17
+ configuration.enabled = true
18
+ end
19
+ end
20
+
21
+ def self.enabled?
22
+ configuration.enabled == true
23
+ end
24
+
25
+ def self.reset_configuration!
26
+ LOCK.synchronize do
27
+ @configuration = nil
28
+ end
29
+ end
30
+
31
+ def self.configuration
32
+ @configuration = nil unless defined?(@configuration)
33
+ @configuration || LOCK.synchronize { @configuration ||= RailsCloudflareTurnstile::Configuration.new }
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_cloudflare_turnstile
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - James Brown
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ - !ruby/object:Gem::Dependency
34
+ name: faraday
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '3.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '1.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '3.0'
53
+ description: |2
54
+ Rails extension for Cloudflare's Turnstile CAPTCHA alternative. This gem should work with
55
+ Rails 5.x, 6.x, and 7.x, and with Faraday 1.x and 2.x.
56
+ email:
57
+ - james@instrumentl.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - README.md
63
+ - Rakefile
64
+ - lib/rails_cloudflare_turnstile.rb
65
+ - lib/rails_cloudflare_turnstile/configuration.rb
66
+ - lib/rails_cloudflare_turnstile/controller_helpers.rb
67
+ - lib/rails_cloudflare_turnstile/errors.rb
68
+ - lib/rails_cloudflare_turnstile/railtie.rb
69
+ - lib/rails_cloudflare_turnstile/version.rb
70
+ - lib/rails_cloudflare_turnstile/view_helpers.rb
71
+ homepage: https://github.com/instrumentl/rails_cloudflare-turnstile
72
+ licenses:
73
+ - ISC
74
+ metadata:
75
+ homepage_uri: https://github.com/instrumentl/rails_cloudflare-turnstile
76
+ source_code_uri: https://github.com/instrumentl/rails_cloudflare-turnstile
77
+ changelog_uri: https://github.com/dotenv-org/cloudflare_turnstile
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 2.7.0
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 3.4.2
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Rails extension for Cloudflare's Turnstile CAPTCHA alternative
97
+ test_files: []