devise-cloudflare-turnstile 0.9.0 → 0.11.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 95edf74912abe68de902d9a5e3cf58c59f8f44d3a60f0b5cfb3ac6105e981ff6
|
|
4
|
+
data.tar.gz: b01582121ba114a8044e010fcd782e8baca8100a220150c4eb6dc2f85af9ac7d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc8dba667dcec474d7464faa259cccc99abaa45823fcedfe26520098ede8b9fd4c78a0849cf0c0e03b85550e0f7cd2527a55c7d60628ba0f243f17aa7074e0ee
|
|
7
|
+
data.tar.gz: 05ccb44987629b192af3087fcbe463989b30791f31526c3f8c134dc49e45cf5d6e79b7d44dba4de5d948b3ddc23ba55fa6da1ef18a56cfbfdcab9113691860cf
|
data/README.md
CHANGED
|
@@ -85,7 +85,9 @@ That's it — all Devise forms are now protected.
|
|
|
85
85
|
### How It Works
|
|
86
86
|
|
|
87
87
|
* **Controller** — a `before_action` on every Devise controller verifies the Turnstile response on `create` and re-renders the form with an error if it fails.
|
|
88
|
-
* **View** — on Devise form pages, the two layout helpers emit the site key and load the injector JavaScript, which adds a `cf-turnstile` widget before each submit button.
|
|
88
|
+
* **View** — on Devise form pages, the two layout helpers emit the site key and load the injector JavaScript, which adds a `cf-turnstile` widget before each submit button. Rails `button_to` action buttons (e.g. OAuth sign-in or log out) are skipped.
|
|
89
|
+
|
|
90
|
+
The widget appears only on the `create` forms (and their `new` pages) — sign in, sign up, password-reset request, and resend confirmation/unlock. Authenticated and edit pages such as account settings, password-reset completion, and accepting an invitation are left untouched.
|
|
89
91
|
|
|
90
92
|
Widget rendering, script loading, CSP nonces, and Turbo/Turbolinks handling are delegated to [cloudflare-turnstile-rails](https://github.com/vkononov/cloudflare-turnstile-rails).
|
|
91
93
|
|
|
@@ -176,10 +178,11 @@ end
|
|
|
176
178
|
|
|
177
179
|
| Situation | Behavior |
|
|
178
180
|
|-----------|----------|
|
|
179
|
-
| No custom controllers | All Devise controllers are protected automatically |
|
|
181
|
+
| No custom controllers | All Devise controllers are protected automatically on their `create` actions |
|
|
182
|
+
| Edit / authenticated pages (account settings, password-reset completion, accept invitation) | Not protected — the widget only appears on the `create` forms |
|
|
180
183
|
| Custom controller with `skip_turnstile` (or config `skip`) | That controller/action opts out of both widget and verification |
|
|
181
184
|
| No custom views | Devise's default views render; the widget still injects |
|
|
182
|
-
| Custom view without a widget | The widget is
|
|
185
|
+
| Custom view without a widget | The widget is injected before the submit button; Rails `button_to` action buttons are skipped |
|
|
183
186
|
| Custom view with `cloudflare_turnstile_tag` | Your widget is used as-is; nothing is auto-injected |
|
|
184
187
|
| Invisible vs visible widget | Determined by the site key's widget type in the Cloudflare dashboard |
|
|
185
188
|
|
|
@@ -74,7 +74,12 @@
|
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
/*
|
|
78
|
+
* Skip Rails button_to forms (rendered with class "button_to"), such as
|
|
79
|
+
* OAuth sign-in, log out, or delete buttons. They are action buttons, not
|
|
80
|
+
* user-input forms, so they should never get a Turnstile widget.
|
|
81
|
+
*/
|
|
82
|
+
forms = document.querySelectorAll('form[method="post"]:not(.button_to), form[method="POST"]:not(.button_to)');
|
|
78
83
|
|
|
79
84
|
for (i = 0; i < forms.length; i++) {
|
|
80
85
|
form = forms[i];
|
|
@@ -10,7 +10,7 @@ module Devise
|
|
|
10
10
|
class_attribute :_turnstile_skip_rules, instance_accessor: false
|
|
11
11
|
self._turnstile_skip_rules = []
|
|
12
12
|
|
|
13
|
-
before_action :verify_cloudflare_turnstile!,
|
|
13
|
+
before_action :verify_cloudflare_turnstile!, if: :turnstile_verify_action?
|
|
14
14
|
before_action :set_turnstile_page_marker, if: :turnstile_form_action?
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -36,6 +36,8 @@ module Devise
|
|
|
36
36
|
self.resource ||= resource_class.new
|
|
37
37
|
return if valid_turnstile?(model: resource, **turnstile_verify_options)
|
|
38
38
|
|
|
39
|
+
restore_turnstile_submitted_values
|
|
40
|
+
|
|
39
41
|
# Sessions (and some other Devise views) do not render resource errors.
|
|
40
42
|
# Always surface the failure via flash so the user sees feedback.
|
|
41
43
|
flash.now[:alert] = ::Cloudflare::Turnstile::Rails::ErrorMessage.default
|
|
@@ -45,6 +47,34 @@ module Devise
|
|
|
45
47
|
render turnstile_failure_action, status: :unprocessable_entity
|
|
46
48
|
end
|
|
47
49
|
|
|
50
|
+
# Re-populate the resource with the values the user just submitted (minus
|
|
51
|
+
# passwords) so the re-rendered form keeps their input. We fail in a
|
|
52
|
+
# before_action, before Devise builds the resource from params, so
|
|
53
|
+
# without this the form would come back blank. Assigning to the
|
|
54
|
+
# in-memory resource is safe because the request halts here and the
|
|
55
|
+
# record is never saved.
|
|
56
|
+
def restore_turnstile_submitted_values
|
|
57
|
+
return unless respond_to?(:resource_name, true)
|
|
58
|
+
|
|
59
|
+
submitted = params[resource_name]
|
|
60
|
+
return unless submitted.respond_to?(:each_pair)
|
|
61
|
+
|
|
62
|
+
submitted.each_pair do |field, value|
|
|
63
|
+
next if field.to_s.include?('password')
|
|
64
|
+
next unless turnstile_scalar_value?(value)
|
|
65
|
+
|
|
66
|
+
setter = "#{field}="
|
|
67
|
+
resource.public_send(setter, value) if resource.respond_to?(setter)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Limits restoration to simple form values. Nested params (e.g. arrays or
|
|
72
|
+
# *_attributes hashes) are skipped because assigning them to the resource
|
|
73
|
+
# is error-prone, and Devise forms only use scalar fields anyway.
|
|
74
|
+
def turnstile_scalar_value?(value)
|
|
75
|
+
value.is_a?(String) || value.is_a?(Numeric) || [true, false].include?(value)
|
|
76
|
+
end
|
|
77
|
+
|
|
48
78
|
# Extra siteverify parameters forwarded to valid_turnstile?. Override in a
|
|
49
79
|
# custom Devise controller to add e.g. remoteip: request.remote_ip.
|
|
50
80
|
def turnstile_verify_options
|
|
@@ -55,13 +85,21 @@ module Devise
|
|
|
55
85
|
@_devise_turnstile_protected = true
|
|
56
86
|
end
|
|
57
87
|
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
88
|
+
# Verify only on create. Kept as a predicate rather than `only: :create`
|
|
89
|
+
# so the callback is skipped cleanly on controllers without a create
|
|
90
|
+
# action instead of raising.
|
|
91
|
+
def turnstile_verify_action?
|
|
92
|
+
action_name == 'create'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# The widget shows on the create forms (`new`) and on `create` itself, so
|
|
96
|
+
# a failed submission that re-renders still emits the meta tag and scripts
|
|
97
|
+
# that Turbo needs. Edit/update pages are excluded because only `create`
|
|
98
|
+
# is verified.
|
|
61
99
|
def turnstile_form_action?
|
|
62
100
|
return false if turnstile_skipped?
|
|
63
101
|
|
|
64
|
-
action_name.in?(%w[new
|
|
102
|
+
action_name.in?(%w[new create])
|
|
65
103
|
end
|
|
66
104
|
|
|
67
105
|
def turnstile_skipped?
|