rails_cloudflare_turnstile 0.1.2 → 0.1.4

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: 213b9ea35b854fa37d8fc8b18e62f37a55d594a23df7d8b4717ed6d528a164a3
4
- data.tar.gz: 1182162d69f5a507075de7c9e5a9ba30a5661fa08587b95399078e37f5ab021d
3
+ metadata.gz: 74e8c3cd9c2aa0d7b6efc991fe4ab26d5e4386b308a391ab38b611857df26bde
4
+ data.tar.gz: 1dae15eaf445e80b32cbd507fddee58cbc34f1c71b9ff5f5487ceb04873593a5
5
5
  SHA512:
6
- metadata.gz: 49f8cfbf351ac4a46258dadc8d21751849fe345519919053e30bf01f3a7972d2265548822423a18e9c5d2e956db8ffbcdc192aa5467de871b44e98989b076223
7
- data.tar.gz: 534896363c9408f0f6c145c6f4b14599631dc77ea507d113bbb24f8d2d81f17bf47a8fc97e866cebe83f42b1dface02f3b2193bc3d47db86ef99995e56e5b593
6
+ metadata.gz: a1c3a53ed7a4dc9291aa5eb5acc1895dfd06eeaae8ee213faaee5236f4d4e5222e71f3bc8752f55864ca6637d8bde92c846c4d15eb52002c6dbabf6f28132074
7
+ data.tar.gz: e502bd59212eeec1372f927f2c70206ebe6d7ea37a2c9947ce510d723038d1a049f9c724b3f530c37010d0ac2f9ef97cb2113f1af7c7ed92f454fc91b7273a18
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  ChangeLog
2
2
  =========
3
3
 
4
+ 0.1.4
5
+ -----
6
+ - add data-callback support; mock javascript
7
+
8
+ 0.1.3
9
+ -----
10
+ - Add mocked functionality in dev/test
11
+
4
12
  0.1.2
5
13
  -----
6
14
  - Fix URIs in gemspec
data/README.md CHANGED
@@ -34,7 +34,6 @@ RailsCloudflareTurnstile.configure do |c|
34
34
  c.fail_open = true
35
35
  end
36
36
  ```
37
-
38
37
  To totally disable Turnstile, you can set `c.enabled = false` and all other config values are ignored.
39
38
 
40
39
  To use Turnstile for a view:
@@ -46,5 +45,8 @@ To use Turnstile for a view:
46
45
  If the challenge fails, the exception `RailsCloudflareTurnstile::Forbidden` will be raised; you should handle this with
47
46
  a `rescue_from` block.
48
47
 
48
+ By default, in development and test mode, a special mock view will be inserted if real credentials are not present. To
49
+ disable this, set the `mock_enable` property of the configuration to false.
50
+
49
51
  ## License
50
52
  The gem is available as open source under the terms of the [ISC License](LICENSE.txt).
@@ -0,0 +1 @@
1
+ <svg width="54" height="54" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M27.3146 7.26134C22.346 7.11258 17.5089 8.87182 13.7968 12.1778l1.2307-6.74308-3.1939-.58208L9.67207 16.6889 21.5124 18.8498 22.0945 15.6559l-6.0801-1.1096c2.9126-2.5542 6.6454-3.9781 10.5192-4.0126C30.4073 10.4993 34.1648 11.8565 37.1224 14.3585s4.9188 5.9826 5.5269 9.8085C43.2573 27.9929 42.4718 31.91 40.4356 35.2057c-2.0362 3.2956-5.1877 5.7509-8.8813 6.9191S23.8704 43.0965 20.3094 41.5711c-3.5609-1.5254-6.456-4.2784-8.1586-7.7582-1.7026-3.4797-2.0995-7.455-1.1185-11.2027L7.89023 21.7861c-1.02566 3.9081-.81053 8.0386.61559 11.8191C9.93194 37.3856 12.4985 40.629 15.8498 42.8861c3.3514 2.257 7.3217 3.4159 11.361 3.3162C31.2501 46.1025 35.1584 44.7491 38.3943 42.3294c3.2359-2.4196 5.6393-5.7858 6.8771-9.632C46.5092 28.8511 46.5202 24.7151 45.3029 20.8623s-3.6026-7.2317-6.8256-9.6685c-3.2229-2.43693-7.124-3.81119-11.1627-3.93246z" style="fill: rgb(243, 128, 32)"></path><path clip-rule="evenodd" d="M38.8474 21.9189 35.9285 19 24.4761 30.4524l-4.5531-4.553L17 28.8224l7.4833 7.4832 2.923-2.923L27.3949 33.3713 38.8474 21.9189z" fill-rule="evenodd" style="fill: rgb(243, 128, 32);"></path></svg>
@@ -0,0 +1,20 @@
1
+ (function() {
2
+ function mock_cloudflare_turnstile_response() {
3
+ setTimeout(function() {
4
+ console.log("setting mock cloudflare turnstile to ✓");
5
+ for (let elem of document.getElementsByClassName("cf-turnstile")) {
6
+ elem.getElementsByTagName("p")[0].style.color = 'green';
7
+ elem.getElementsByTagName("p").innerHTML = "Mocked CAPTCHA succeeded"
8
+ if (elem.dataset.callback !== undefined) {
9
+ eval(elem.dataset.callback).call("mocked");
10
+ }
11
+ }
12
+ }, 1500);
13
+ }
14
+
15
+ if (document.readyState !== 'loading') {
16
+ mock_cloudflare_turnstile_response()
17
+ } else {
18
+ document.addEventListener('DOMContentLoaded', mock_cloudflare_turnstile_response);
19
+ }
20
+ })();
@@ -16,18 +16,25 @@ module RailsCloudflareTurnstile
16
16
  # Timeout for operations with Cloudflare
17
17
  attr_accessor :timeout
18
18
 
19
- # size for the widget ("regular" or "compact")
19
+ # size for the widget (:regular or :compact)
20
20
  attr_accessor :size
21
21
 
22
+ # theme for the widget (:auto, :light, or :dark)
23
+ attr_accessor :theme
24
+
22
25
  attr_accessor :enabled
23
26
 
27
+ attr_accessor :mock_enabled
28
+
24
29
  def initialize
25
30
  @site_key = nil
26
31
  @secret_key = nil
27
32
  @fail_open = true
28
33
  @enabled = nil
34
+ @mock_enabled = nil
29
35
  @timeout = 5.0
30
36
  @size = :regular
37
+ @theme = :auto
31
38
  @validation_url = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
32
39
  end
33
40
 
@@ -36,6 +43,7 @@ module RailsCloudflareTurnstile
36
43
  raise "Must set secret key" if @secret_key.nil?
37
44
  @size = @size.to_sym
38
45
  raise "Size must be one of ':regular' or ':compact'" unless [:regular, :compact].include? @size
46
+ raise "Theme must be one of :auto, :light, or :dark" unless [:auto, :light, :dark].include? @theme
39
47
  end
40
48
 
41
49
  def disabled?
@@ -5,54 +5,58 @@ require "faraday"
5
5
  module RailsCloudflareTurnstile
6
6
  module ControllerHelpers
7
7
  def cloudflare_turnstile_ok?
8
- return true unless RailsCloudflareTurnstile.enabled?
8
+ if RailsCloudflareTurnstile.enabled?
9
+ config = RailsCloudflareTurnstile.configuration
9
10
 
10
- config = RailsCloudflareTurnstile.configuration
11
+ url = URI(config.validation_url)
11
12
 
12
- url = URI(config.validation_url)
13
+ body = {
14
+ secret: config.secret_key,
15
+ response: params["cf-turnstile-response"],
16
+ remoteip: request.remote_ip
17
+ }
13
18
 
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
19
+ begin
20
+ resp = Faraday.new(url) { |conn|
21
+ conn.options.timeout = config.timeout
22
+ conn.options.open_timeout = config.timeout
23
+ conn.use Faraday::Response::RaiseError
24
+ conn.request :json
25
+ conn.response :json
26
+ }.post(url, body)
27
+ rescue Faraday::Error => e
28
+ Rails.logger.error "Error response from CloudFlare Turnstile: #{e}"
29
+ if config.fail_open
30
+ return true
31
+ else
32
+ return false
33
+ end
34
34
  end
35
- end
36
35
 
37
- json = resp.body
36
+ json = resp.body
38
37
 
39
- success = json["success"]
38
+ success = json["success"]
40
39
 
41
- return true if success
40
+ return true if success
42
41
 
43
- error = json["error-codes"][0]
42
+ error = json["error-codes"][0]
44
43
 
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
- )
44
+ ActiveSupport::Notifications.instrument(
45
+ "rails_cloudflare_turnstile.failure",
46
+ message: error,
47
+ remote_ip: request.remote_ip,
48
+ user_agent: request.user_agent,
49
+ controller: params[:controller],
50
+ action: params[:action],
51
+ url: request.url
52
+ )
54
53
 
55
- false
54
+ false
55
+ elsif RailsCloudflareTurnstile.mock_enabled?
56
+ params["cf-turnstile-response"] == "mocked"
57
+ else
58
+ true
59
+ end
56
60
  end
57
61
 
58
62
  private
@@ -0,0 +1,9 @@
1
+ module RailsCloudflareTurnstile
2
+ class Engine < ::Rails::Engine
3
+ initializer "rails_cloudflare_turnstile.precompile" do |app|
4
+ %w[javascripts images].each do |sub|
5
+ app.config.assets.paths << root.join("assets", sub).to_s
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,6 +1,6 @@
1
1
  module RailsCloudflareTurnstile
2
2
  class Railtie < ::Rails::Railtie
3
- initializer "rails_cloudflare_turnstile" do
3
+ initializer "rails_cloudflare_turnstile" do |app|
4
4
  ActiveSupport.on_load(:action_controller) do
5
5
  include RailsCloudflareTurnstile::ControllerHelpers
6
6
  end
@@ -8,6 +8,8 @@ module RailsCloudflareTurnstile
8
8
  ActiveSupport.on_load(:action_view) do
9
9
  include RailsCloudflareTurnstile::ViewHelpers
10
10
  end
11
+
12
+ app.config.assets.precompile += %w[mock_cloudflare_turnstile_api.js turnstile-logo.svg]
11
13
  end
12
14
  end
13
15
  end
@@ -1,3 +1,3 @@
1
1
  module RailsCloudflareTurnstile
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -2,29 +2,51 @@
2
2
 
3
3
  module RailsCloudflareTurnstile
4
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)
5
+ def cloudflare_turnstile(action: "other", data_callback: nil)
6
+ if RailsCloudflareTurnstile.enabled?
7
+ content_tag(:div, class: "cloudflare-turnstile") do
8
+ concat turnstile_div(action, data_callback: data_callback)
9
+ end
10
+ elsif RailsCloudflareTurnstile.mock_enabled?
11
+ content_tag(:div, class: "cloudflare-turnstile") do
12
+ concat mock_turnstile_div(action, data_callback: data_callback)
13
+ end
9
14
  end
10
15
  end
11
16
 
12
17
  def cloudflare_turnstile_script_tag
13
- return nil unless RailsCloudflareTurnstile.enabled?
14
- content_tag(:script, :src => js_src, "async" => true) do
15
- ""
18
+ if RailsCloudflareTurnstile.enabled?
19
+ content_tag(:script, :src => js_src, "async" => true) do
20
+ ""
21
+ end
22
+ elsif RailsCloudflareTurnstile.mock_enabled?
23
+ content_tag(:script, :src => mock_js, "async" => true) do
24
+ ""
25
+ end
16
26
  end
17
27
  end
18
28
 
19
29
  private
20
30
 
21
- def turnstile_div(action)
31
+ def turnstile_div(action, data_callback: nil)
22
32
  config = RailsCloudflareTurnstile.configuration
23
- content_tag(:div, :class => "cf-turnstile", "data-sitekey" => site_key, "data-size" => config.size, "data-action" => action) do
33
+ content_tag(:div, :class => "cf-turnstile", "data-sitekey" => site_key, "data-size" => config.size, "data-action" => action, "data-callback" => data_callback, "data-theme" => config.theme) do
24
34
  ""
25
35
  end
26
36
  end
27
37
 
38
+ def mock_turnstile_div(action, data_callback: nil)
39
+ content_tag(:div, :class => "cf-turnstile", :style => "width: 300px; height: 65px; border: 1px solid gray; display: flex; flex-direction: row; justify-content: center; align-items: center; margin: 10px;", "data-callback" => data_callback) do
40
+ [
41
+ tag.input(type: "hidden", name: "cf-turnstile-response", value: "mocked"),
42
+ image_tag("turnstile-logo.svg"),
43
+ content_tag(:p, style: "margin: 0") do
44
+ "CAPTCHA goes here in production"
45
+ end
46
+ ].reduce(:<<)
47
+ end
48
+ end
49
+
28
50
  def site_key
29
51
  RailsCloudflareTurnstile.configuration.site_key
30
52
  end
@@ -32,5 +54,9 @@ module RailsCloudflareTurnstile
32
54
  def js_src
33
55
  "https://challenges.cloudflare.com/turnstile/v0/api.js"
34
56
  end
57
+
58
+ def mock_js
59
+ javascript_path "mock_cloudflare_turnstile_api.js"
60
+ end
35
61
  end
36
62
  end
@@ -1,4 +1,5 @@
1
1
  require "rails_cloudflare_turnstile/version"
2
+ require "rails_cloudflare_turnstile/engine"
2
3
  require "rails_cloudflare_turnstile/configuration"
3
4
  require "rails_cloudflare_turnstile/errors"
4
5
  require "rails_cloudflare_turnstile/controller_helpers"
@@ -16,12 +17,19 @@ module RailsCloudflareTurnstile
16
17
  if configuration.enabled.nil?
17
18
  configuration.enabled = true
18
19
  end
20
+ if configuration.mock_enabled.nil?
21
+ configuration.mock_enabled = Rails.env.development? || Rails.env.test?
22
+ end
19
23
  end
20
24
 
21
25
  def self.enabled?
22
26
  configuration.enabled == true
23
27
  end
24
28
 
29
+ def self.mock_enabled?
30
+ configuration.mock_enabled == true
31
+ end
32
+
25
33
  def self.reset_configuration!
26
34
  LOCK.synchronize do
27
35
  @configuration = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_cloudflare_turnstile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Brown
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-09 00:00:00.000000000 Z
11
+ date: 2023-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -62,9 +62,12 @@ files:
62
62
  - CHANGELOG.md
63
63
  - README.md
64
64
  - Rakefile
65
+ - app/assets/images/turnstile-logo.svg
66
+ - app/assets/javascripts/mock_cloudflare_turnstile_api.js
65
67
  - lib/rails_cloudflare_turnstile.rb
66
68
  - lib/rails_cloudflare_turnstile/configuration.rb
67
69
  - lib/rails_cloudflare_turnstile/controller_helpers.rb
70
+ - lib/rails_cloudflare_turnstile/engine.rb
68
71
  - lib/rails_cloudflare_turnstile/errors.rb
69
72
  - lib/rails_cloudflare_turnstile/railtie.rb
70
73
  - lib/rails_cloudflare_turnstile/version.rb