cloudflare-turnstile-rails 1.0.2 → 1.2.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 +4 -4
- data/README.md +59 -15
- data/lib/cloudflare/turnstile/rails/configuration.rb +2 -1
- data/lib/cloudflare/turnstile/rails/controller_methods.rb +10 -2
- data/lib/cloudflare/turnstile/rails/helpers.rb +11 -1
- data/lib/cloudflare/turnstile/rails/verification.rb +8 -3
- data/lib/cloudflare/turnstile/rails/version.rb +1 -1
- data/lib/generators/cloudflare_turnstile/templates/cloudflare_turnstile.rb +9 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a86ed02899dc2410a686143de9c188b3d15cfef8e4928bc87cc00bd1741fb58
|
|
4
|
+
data.tar.gz: 566026c1569d205f3a91beec381ec29729e6afe78084b9a6fb60ef4ceb0b3fad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a5a699a90fcb1a704de8a46ec57571c5219794d853d94a0d7bbac05e3e91dfa7ee20ddefaa1245d246a8b64bba082f58800821db4e2d4accc3ac16252eca204
|
|
7
|
+
data.tar.gz: e3655f9b725839b328f3699fd7dfb8def8f91d8011bd10dd4c8e4904cc6a12c61453a85bde4c666cd8d26185cb623da406ec634828785ff27d5833b6e5854594
|
data/README.md
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
# Cloudflare Turnstile Rails
|
|
2
2
|
|
|
3
|
-
[](https://rubygems.org/gems/cloudflare-turnstile-rails)
|
|
4
|
-
[](https://rubygems.org/gems/cloudflare-turnstile-rails)
|
|
4
|
+
[](https://github.com/vkononov/cloudflare-turnstile-rails/blob/main/.github/workflows/test.yml)
|
|
5
|
+
[](https://github.com/vkononov/cloudflare-turnstile-rails/blob/main/Appraisals)
|
|
6
|
+
[](https://github.com/vkononov/cloudflare-turnstile-rails/actions/workflows/test.yml)
|
|
7
|
+
[](https://github.com/vkononov/cloudflare-turnstile-rails/actions/workflows/lint.yml)
|
|
8
|
+
[](https://opensource.org/license/MIT)
|
|
7
9
|
|
|
8
10
|
Cloudflare Turnstile gem for Ruby on Rails with built-in Turbo and Turbolinks support and CSP compliance.
|
|
9
11
|
|
|
10
|
-
Supports
|
|
12
|
+
Supports **Rails 5.0 → latest** and **Ruby 2.6 → latest**, with the full Rails/Ruby matrix tested daily in CI.
|
|
11
13
|
|
|
12
14
|
[](https://www.buymeacoffee.com/vkononov)
|
|
13
15
|
|
|
14
16
|
## Features
|
|
15
17
|
|
|
16
18
|
* **One‑line integration**: `<%= cloudflare_turnstile_tag %>` in views, `valid_turnstile?(model:)` in controllers — no extra wiring.
|
|
17
|
-
* **Turbo & Turbo Streams aware**: Automatically re‑initializes widgets on `turbo:
|
|
19
|
+
* **Turbo & Turbo Streams aware**: Automatically re‑initializes widgets on `turbo:render` and `turbo:before-stream-render`.
|
|
18
20
|
* **Legacy Turbolinks support**: Includes a helper for Turbolinks to handle remote form submissions with validation errors.
|
|
19
21
|
* **CSP nonce support**: Honours Rails' `content_security_policy_nonce` for secure inline scripts.
|
|
20
22
|
* **Rails Engine & Asset pipeline**: Ships a precompiled JS helper via Railtie — no manual asset setup.
|
|
@@ -87,10 +89,35 @@ Supports `Rails >= 5.0` with `Ruby >= 2.6.0`.
|
|
|
87
89
|
<%= cloudflare_turnstile_tag %>
|
|
88
90
|
```
|
|
89
91
|
|
|
90
|
-
That's it!
|
|
92
|
+
That's it! By default the widget auto-detects the visitor's `theme` and `language`.
|
|
93
|
+
|
|
94
|
+
* To match your app's design and locale, set defaults once in the initializer and they'll apply to every `cloudflare_turnstile_tag` automatically:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
Cloudflare::Turnstile::Rails.configure do |config|
|
|
98
|
+
config.default_data = {
|
|
99
|
+
theme: 'light',
|
|
100
|
+
language: 'en'
|
|
101
|
+
}
|
|
102
|
+
end
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Values may also be a proc, evaluated at render time — useful for following the current locale:
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
config.default_data = { language: -> { I18n.locale } }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
* You can still override any default (or add extra options) on an individual tag via the `data:` option. Per-tag values take precedence over the configured defaults:
|
|
91
112
|
|
|
92
113
|
```erb
|
|
93
|
-
<%= cloudflare_turnstile_tag data: { theme: '
|
|
114
|
+
<%= cloudflare_turnstile_tag data: { theme: 'dark' } %>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
* To drop a configured default on a single tag (so its attribute isn't rendered at all), pass `nil` for that key:
|
|
118
|
+
|
|
119
|
+
```erb
|
|
120
|
+
<%= cloudflare_turnstile_tag data: { theme: nil } %>
|
|
94
121
|
```
|
|
95
122
|
|
|
96
123
|
* For all available **data-**\* options (e.g., `action`, `cdata`, `theme`, etc.), refer to the official Cloudflare client-side rendering docs:
|
|
@@ -127,6 +154,22 @@ Supports `Rails >= 5.0` with `Ruby >= 2.6.0`.
|
|
|
127
154
|
end
|
|
128
155
|
```
|
|
129
156
|
|
|
157
|
+
The automatic message is a regular flash, so it survives exactly one redirect. If you **re-render the form** instead of redirecting, pass `flash: :now` to scope the message to that render, so it doesn't also appear on the next page the visitor opens:
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
def create
|
|
161
|
+
if valid_turnstile?(flash: :now)
|
|
162
|
+
# Passed: no message is set either way
|
|
163
|
+
redirect_to dashboard_path, notice: 'Success!'
|
|
164
|
+
else
|
|
165
|
+
# Failed: flash.now[:alert] is automatically set
|
|
166
|
+
render :new, status: :unprocessable_entity
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Passing a `model` is the other option for a re-rendered form: the failure goes to `model.errors` and no flash is set at all.
|
|
172
|
+
|
|
130
173
|
* You may also pass additional **siteverify** parameters (e.g., `secret`, `response`, `remoteip`, `idempotency_key`) supported by Cloudflare's API:
|
|
131
174
|
[Cloudflare Server-Side Validation Parameters](https://developers.cloudflare.com/turnstile/get-started/server-side-validation/#required-parameters)
|
|
132
175
|
|
|
@@ -275,9 +318,9 @@ Cloudflare provides dummy sitekeys and secret keys for development and testing.
|
|
|
275
318
|
| Sitekey | Description | Visibility |
|
|
276
319
|
|----------------------------|---------------------------------|------------|
|
|
277
320
|
| `1x00000000000000000000AA` | Always passes | visible |
|
|
278
|
-
| `2x00000000000000000000AB` | Always
|
|
321
|
+
| `2x00000000000000000000AB` | Always fails | visible |
|
|
279
322
|
| `1x00000000000000000000BB` | Always passes | invisible |
|
|
280
|
-
| `2x00000000000000000000BB` | Always
|
|
323
|
+
| `2x00000000000000000000BB` | Always fails | invisible |
|
|
281
324
|
| `3x00000000000000000000FF` | Forces an interactive challenge | visible |
|
|
282
325
|
|
|
283
326
|
### Dummy Secret Keys
|
|
@@ -366,10 +409,11 @@ If you run into any issues after upgrading Rails, please [open an issue](https:/
|
|
|
366
409
|
|
|
367
410
|
### Setup
|
|
368
411
|
|
|
369
|
-
Install dependencies,
|
|
412
|
+
Install the Ruby dependencies, then the JavaScript dependencies used by the ESLint step:
|
|
370
413
|
|
|
371
414
|
```bash
|
|
372
415
|
bin/setup
|
|
416
|
+
npm install
|
|
373
417
|
```
|
|
374
418
|
|
|
375
419
|
### Running the Test Suite
|
|
@@ -387,13 +431,13 @@ bundle exec appraisal rake test
|
|
|
387
431
|
|
|
388
432
|
### Code Linting
|
|
389
433
|
|
|
390
|
-
|
|
434
|
+
Run RuboCop and ESLint together (autocorrecting by default, or pass `--no-fix` to only report):
|
|
391
435
|
|
|
392
436
|
```bash
|
|
393
|
-
|
|
437
|
+
bin/lint
|
|
394
438
|
```
|
|
395
439
|
|
|
396
|
-
> **CI Note:** We run
|
|
440
|
+
> **CI Note:** We run `bin/lint --no-fix` via [.github/workflows/lint.yml](https://github.com/vkononov/cloudflare-turnstile-rails/blob/main/.github/workflows/lint.yml) on the latest Ruby only.
|
|
397
441
|
|
|
398
442
|
### Generating Rails Apps Locally
|
|
399
443
|
|
|
@@ -434,4 +478,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/vkonon
|
|
|
434
478
|
|
|
435
479
|
## License
|
|
436
480
|
|
|
437
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/
|
|
481
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/license/MIT).
|
|
@@ -3,7 +3,7 @@ module Cloudflare
|
|
|
3
3
|
module Rails
|
|
4
4
|
class Configuration
|
|
5
5
|
attr_writer :script_url
|
|
6
|
-
attr_accessor :site_key, :secret_key, :render, :onload, :auto_populate_response_in_test_env
|
|
6
|
+
attr_accessor :site_key, :secret_key, :render, :onload, :default_data, :auto_populate_response_in_test_env
|
|
7
7
|
|
|
8
8
|
def initialize
|
|
9
9
|
@script_url = Cloudflare::SCRIPT_URL
|
|
@@ -11,6 +11,7 @@ module Cloudflare
|
|
|
11
11
|
@secret_key = nil
|
|
12
12
|
@render = nil
|
|
13
13
|
@onload = nil
|
|
14
|
+
@default_data = {}
|
|
14
15
|
@auto_populate_response_in_test_env = true
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -17,10 +17,18 @@ module Cloudflare
|
|
|
17
17
|
result
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
# flash: :keep carries the automatic failure message into the next request,
|
|
21
|
+
# for a redirect. flash: :now scopes it to the response being rendered. The
|
|
22
|
+
# keyword shadows the controller's own flash method, hence request.flash.
|
|
23
|
+
def valid_turnstile?(model: nil, flash: :keep, **opts)
|
|
21
24
|
response = verify_turnstile(model: model, **opts)
|
|
22
25
|
success = response.is_a?(VerificationResponse) && response.success?
|
|
23
|
-
|
|
26
|
+
|
|
27
|
+
if !success && model.nil?
|
|
28
|
+
store = flash == :now ? request.flash.now : request.flash
|
|
29
|
+
store[:alert] = ErrorMessage.default
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
success
|
|
25
33
|
end
|
|
26
34
|
|
|
@@ -7,7 +7,7 @@ module Cloudflare
|
|
|
7
7
|
def cloudflare_turnstile_tag(site_key: nil, include_script: true, **html_options) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
8
8
|
site_key ||= Rails.configuration.site_key
|
|
9
9
|
html_options[:class] = Cloudflare::WIDGET_CLASS unless html_options.key?(:class)
|
|
10
|
-
html_options[:data]
|
|
10
|
+
html_options[:data] = cloudflare_turnstile_default_data.merge(html_options[:data] || {})
|
|
11
11
|
html_options[:data][:sitekey] ||= site_key
|
|
12
12
|
|
|
13
13
|
script_tag = nil
|
|
@@ -27,6 +27,16 @@ module Cloudflare
|
|
|
27
27
|
widget = content_tag(:div, '', html_options)
|
|
28
28
|
safe_join([script_tag, widget].compact, "\n")
|
|
29
29
|
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# Resolves the configured default data attributes, evaluating any
|
|
34
|
+
# callable values (e.g. a proc bound to I18n.locale) at render time.
|
|
35
|
+
def cloudflare_turnstile_default_data
|
|
36
|
+
(Rails.configuration.default_data || {}).transform_values do |value|
|
|
37
|
+
value.respond_to?(:call) ? value.call : value
|
|
38
|
+
end
|
|
39
|
+
end
|
|
30
40
|
end
|
|
31
41
|
end
|
|
32
42
|
end
|
|
@@ -48,9 +48,7 @@ module Cloudflare
|
|
|
48
48
|
|
|
49
49
|
module Verification
|
|
50
50
|
def self.verify(response: nil, secret: nil, remoteip: nil, idempotency_key: nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
51
|
-
|
|
52
|
-
response = 'dummy-response'
|
|
53
|
-
end
|
|
51
|
+
response = 'dummy-response' if auto_populate_test_response?(response)
|
|
54
52
|
|
|
55
53
|
secret ||= Rails.configuration.secret_key
|
|
56
54
|
if secret.nil? || secret.strip.empty?
|
|
@@ -89,6 +87,13 @@ module Cloudflare
|
|
|
89
87
|
|
|
90
88
|
VerificationResponse.new(json)
|
|
91
89
|
end
|
|
90
|
+
|
|
91
|
+
def self.auto_populate_test_response?(response)
|
|
92
|
+
(response.nil? || response.strip.empty?) &&
|
|
93
|
+
::Rails.env.test? &&
|
|
94
|
+
Rails.configuration.auto_populate_response_in_test_env
|
|
95
|
+
end
|
|
96
|
+
private_class_method :auto_populate_test_response?
|
|
92
97
|
end
|
|
93
98
|
end
|
|
94
99
|
end
|
|
@@ -16,6 +16,15 @@ Cloudflare::Turnstile::Rails.configure do |config|
|
|
|
16
16
|
# config.render = 'explicit'
|
|
17
17
|
# config.onload = 'onloadTurnstileCallback'
|
|
18
18
|
|
|
19
|
+
# Optional: Default data-* attributes applied to every `cloudflare_turnstile_tag`.
|
|
20
|
+
# These are merged into each widget and can be overridden per tag via the `data:` option.
|
|
21
|
+
# See https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#configuration-options
|
|
22
|
+
# Values may be a proc, evaluated at render time (e.g. to follow the current locale).
|
|
23
|
+
# config.default_data = {
|
|
24
|
+
# theme: 'auto',
|
|
25
|
+
# language: -> { I18n.locale }
|
|
26
|
+
# }
|
|
27
|
+
|
|
19
28
|
# In the Rails Test environment, automatically fill in a dummy response if none was provided.
|
|
20
29
|
# This lets you keep existing controller tests without having to add
|
|
21
30
|
# params["cf-turnstile-response"] manually in every test.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cloudflare-turnstile-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vadim Kononov
|
|
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
83
83
|
- !ruby/object:Gem::Version
|
|
84
84
|
version: '0'
|
|
85
85
|
requirements: []
|
|
86
|
-
rubygems_version:
|
|
86
|
+
rubygems_version: 3.7.2
|
|
87
87
|
specification_version: 4
|
|
88
88
|
summary: Cloudflare Turnstile gem for Rails with built-in Turbo and Turbolinks support
|
|
89
89
|
and CSP compliance
|