rails_cloudflare_turnstile 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +47 -0
- data/Rakefile +13 -0
- data/lib/rails_cloudflare_turnstile/configuration.rb +45 -0
- data/lib/rails_cloudflare_turnstile/controller_helpers.rb +65 -0
- data/lib/rails_cloudflare_turnstile/errors.rb +7 -0
- data/lib/rails_cloudflare_turnstile/railtie.rb +13 -0
- data/lib/rails_cloudflare_turnstile/version.rb +3 -0
- data/lib/rails_cloudflare_turnstile/view_helpers.rb +36 -0
- data/lib/rails_cloudflare_turnstile.rb +35 -0
- metadata +97 -0
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,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,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,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: []
|