reputable 0.1.15 → 0.1.17

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: 46a14f8686b7e3ad1aa8a8c2e22f5c14f13a3d6667ad9bb4ca1e088024989f7d
4
- data.tar.gz: 6b6e95c46a329214b02279c23d02b55067f8a86f74cc6f17159b35dd43d08ef6
3
+ metadata.gz: 8767ca87c7fdd5abc6584e738599020cbd6977bc6193371caeef1425eedb8dfd
4
+ data.tar.gz: 5196f00349ec3b380bec72db3b98c5f09d08965d297e7f43a8c639b9d1eed3dd
5
5
  SHA512:
6
- metadata.gz: 542429b9c9716d69889873b9212b4500669a074c24595f8f933f64568161ca6a562de7b6aa307ede64252b35599d5e768279abee078724d358ab2a2bc14f6f90
7
- data.tar.gz: e3978a1b8e21332bd1a7e1ef26a719398c478762f74a5959bdc8c85c720de7fe97a03b4c525df7c892273329f8c1d02c1fe38163fcdee21d92479dfc81b735a2
6
+ metadata.gz: 36285df97965903af8e913d3f0937969ae4e48399f0468fd2e00b22d3b0e7c6d50d51682d9ec82a31483729ca7f0d69d4d0ec47115b12dce62ff01948d18b3ec
7
+ data.tar.gz: 6aea15486988795b5ce444581be796e33d15906c871f5cc28208d876b0604053603f455f8d16536b4879773991905f85882f56b4fed47d85b71b1ea9abb34a42
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reputable (0.1.15)
4
+ reputable (0.1.17)
5
5
  connection_pool (~> 2.2)
6
6
  redis (>= 4.0, < 6.0)
7
7
 
data/README.md CHANGED
@@ -275,6 +275,10 @@ config.middleware.use Reputable::Middleware,
275
275
  # Falls back to ENV REPUTABLE_TRACK_REQUEST if not set
276
276
  track_request: true,
277
277
 
278
+ # Ignore XHR requests (default: false)
279
+ # Useful for suppressing tracking of background widgets or polling
280
+ ignore_xhr: true,
281
+
278
282
  # Expose reputation flags in request env for views/controllers (default: true)
279
283
  # Sets request.env['reputable.ignore_analytics'] for any untrusted_* status
280
284
  expose_reputation: true
@@ -301,6 +305,33 @@ Notes:
301
305
  - Use `blocked_page_path` only for local blocked pages (or to build a custom `failure_url`).
302
306
  - Override `challenge_redirect_status` (default `302`) or `verification_force_challenge` if needed.
303
307
 
308
+ ### Server/JS Request Reconciliation
309
+
310
+ When using both server-side tracking (Rack middleware) and client-side JavaScript tracking, requests can be double-counted. The reconciliation system prevents this by correlating requests using a unique `request_id`.
311
+
312
+ **Automatic Request ID**: The middleware automatically generates a UUID for each request and stores it in `env['reputable.request_id']`. This ID is included when pushing to the Redis buffer.
313
+
314
+ **Exposing to JavaScript**: To enable reconciliation, expose the request_id in your views:
315
+
316
+ ```erb
317
+ <%# In your layout (app/views/layouts/application.html.erb) %>
318
+ <meta name="reputable-request-id" content="<%= request.env['reputable.request_id'] %>">
319
+
320
+ <%# Or via JavaScript variable %>
321
+ <script>
322
+ window.reputableConfig = {
323
+ requestId: '<%= request.env['reputable.request_id'] %>'
324
+ };
325
+ </script>
326
+ ```
327
+
328
+ The JavaScript snippet will automatically read the request_id from:
329
+ 1. `data-reputable-request-id` attribute on the script tag
330
+ 2. `window.reputableConfig.requestId`
331
+ 3. `<meta name="reputable-request-id">` tag
332
+
333
+ **Bot Detection Signal**: If the middleware tracks a request but JavaScript never fires (after a 10-second grace period), the request is flagged with `risk:no_js`. This is a strong bot signal—bots and crawlers typically don't render JavaScript.
334
+
304
335
  ### Default Skipped Paths
305
336
 
306
337
  The middleware automatically skips:
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "blocked_page"
4
+ require "securerandom"
4
5
 
5
6
  module Reputable
6
7
  # Rack middleware for automatic request tracking
@@ -58,9 +59,14 @@ module Reputable
58
59
  @verified_session_keys = Array(options.fetch(:verified_session_keys, [:reputable_verified_at, :reputable_verified]))
59
60
  @blocked_page_options = options.fetch(:blocked_page, {})
60
61
  @blocked_page_path = options[:blocked_page_path]
62
+ @ignore_xhr = options.fetch(:ignore_xhr, false)
61
63
  end
62
64
 
63
65
  def call(env)
66
+ # Generate a unique request ID for reconciliation with JS tracking
67
+ # This ID is exposed to views so it can be included in the JS snippet
68
+ env['reputable.request_id'] = SecureRandom.uuid
69
+
64
70
  # Check for verification return parameters and verify signature if present
65
71
  handle_verification_return(env)
66
72
 
@@ -351,6 +357,7 @@ module Reputable
351
357
 
352
358
  def skip_request?(env)
353
359
  return true if @skip_if&.call(env)
360
+ return true if @ignore_xhr && xhr_request?(env)
354
361
 
355
362
  path = env["PATH_INFO"] || "/"
356
363
 
@@ -390,7 +397,8 @@ module Reputable
390
397
  method: request.request_method,
391
398
  user_agent: env["HTTP_USER_AGENT"],
392
399
  referer: env["HTTP_REFERER"],
393
- tags: build_tags(env)
400
+ tags: build_tags(env),
401
+ request_id: env["reputable.request_id"]
394
402
  }.compact
395
403
  rescue StandardError => e
396
404
  Reputable.logger&.debug("Reputable build_params: #{e.class} - #{e.message}")
@@ -516,5 +524,9 @@ module Reputable
516
524
  rescue StandardError
517
525
  nil
518
526
  end
527
+
528
+ def xhr_request?(env)
529
+ env["HTTP_X_REQUESTED_WITH"].to_s.downcase == "xmlhttprequest"
530
+ end
519
531
  end
520
532
  end
@@ -24,6 +24,7 @@ module Reputable
24
24
  # @option options [String] :country Country code (ISO 3166-1 alpha-2)
25
25
  # @option options [Array<String>] :tags Custom classification tags
26
26
  # @option options [Hash] :metadata Additional metadata
27
+ # @option options [String] :request_id Unique request ID for reconciliation with JS tracking
27
28
  # @return [Boolean] true if successfully pushed to buffer, false otherwise
28
29
  #
29
30
  # @example Basic usage
@@ -32,7 +33,7 @@ module Reputable
32
33
  # path: "/products/123"
33
34
  # )
34
35
  #
35
- # @example Full usage
36
+ # @example Full usage with request_id for JS reconciliation
36
37
  # Reputable::Tracker.track_request(
37
38
  # ip: request.ip,
38
39
  # path: request.path,
@@ -40,6 +41,7 @@ module Reputable
40
41
  # method: request.request_method,
41
42
  # user_agent: request.user_agent,
42
43
  # referer: request.referer,
44
+ # request_id: env['reputable.request_id'],
43
45
  # tags: ["view:page:product", "trust:channel:organic"]
44
46
  # )
45
47
  def track_request(ip:, path:, **options)
@@ -80,7 +82,8 @@ module Reputable
80
82
  referer: options[:referer],
81
83
  country: options[:country],
82
84
  tags: options[:tags] || [],
83
- metadata: options[:metadata]
85
+ metadata: options[:metadata],
86
+ request_id: options[:request_id]
84
87
  }.compact
85
88
  end
86
89
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reputable
4
- VERSION = "0.1.15"
4
+ VERSION = "0.1.17"
5
5
  end
data/reputable.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/reputable/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "reputable"
7
+ spec.version = Reputable::VERSION
8
+ spec.authors = ["Reputable"]
9
+ spec.email = ["support@reputable.click"]
10
+
11
+ spec.summary = "Ruby client for Reputable - bot detection and reputation scoring"
12
+ spec.description = "Track requests and manage IP reputation through Redis/Dragonfly integration with Reputable"
13
+ spec.homepage = "https://github.com/reputable-click/reputable-rb"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.7.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
20
+
21
+ spec.files = Dir.chdir(__dir__) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) || f.end_with?(".gem")
24
+ end
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "redis", ">= 4.0", "< 6.0"
31
+ spec.add_dependency "connection_pool", "~> 2.2"
32
+
33
+ spec.add_development_dependency "bundler", "~> 2.0"
34
+ spec.add_development_dependency "rake", "~> 13.0"
35
+ spec.add_development_dependency "rspec", "~> 3.12"
36
+ spec.add_development_dependency "rack", "~> 2.0"
37
+ spec.add_development_dependency "rubocop", "~> 1.0"
38
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reputable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.15
4
+ version: 0.1.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reputable
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-28 00:00:00.000000000 Z
11
+ date: 2026-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -137,6 +137,7 @@ files:
137
137
  - lib/reputable/reputation.rb
138
138
  - lib/reputable/tracker.rb
139
139
  - lib/reputable/version.rb
140
+ - reputable.gemspec
140
141
  homepage: https://github.com/reputable-click/reputable-rb
141
142
  licenses:
142
143
  - MIT