reputable 0.1.2 → 0.1.3

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: 5cfe6bbd421f190d87e5f0be242142988e269d8df74186f85f66c8f5996f115f
4
- data.tar.gz: 4db1343a290ef95d775b0694a50d84d48c861af293bf0d3e4d388e44c031c9d0
3
+ metadata.gz: ca78832e420ad0cacad0c44bbfbf2a682f1b9f702bbaf8aa07a44e4e04d7d53b
4
+ data.tar.gz: 9e15f534984a4e3d67560a98cbede0c596d02d30fb7f7171b380b043b0781384
5
5
  SHA512:
6
- metadata.gz: 211cb949190c13bd0f3d8f6c4f0296a84c92653e64c2971d5866e0606cc777ebfe356a8a73d10e5a269f6701105372f9c4c8203f90bf75f279958b385874c3ad
7
- data.tar.gz: 14dbcf3338f725de441618100e0b57e99314974e0ff89b787c45141dcec56fa6c230c9acaa69feaed42233a87cf10add2cc2ccca2e80883eddb656779821ace6
6
+ metadata.gz: 23832e31d409bb3316c33c931e6207f24eb2ea078c2fa79d3d0c4618e4ffd3359f525d0c6b090344bb5d8e79cf9fdc714752ae09180ce973dd353d93015afb6c
7
+ data.tar.gz: 9eb4a989b111a493e7555672057946c2928251a1112e7b75e011bf7183c329ee3b9c6c6cb0e34a163d3803cb5956321b443b25f2d9fcbfca5c90ad16b73cd766
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reputable (0.1.2)
4
+ reputable (0.1.3)
5
5
  connection_pool (~> 2.2)
6
6
  redis (>= 4.0, < 6.0)
7
7
 
data/README.md CHANGED
@@ -135,6 +135,11 @@ Reputable.configure do |config|
135
135
  REMOTE_ADDR
136
136
  ]
137
137
 
138
+ # Verification Configuration
139
+ # Supports comma-separated list in REPUTABLE_TRUSTED_KEYS or single key in REPUTABLE_TRUSTED_KEY
140
+ config.trusted_keys = ENV['REPUTABLE_TRUSTED_KEYS']&.split(',') || ENV['REPUTABLE_TRUSTED_KEY']
141
+ config.verification_base_url = ENV['REPUTABLE_VERIFY_URL'] # URL of your Reputable API verify endpoint
142
+
138
143
  # Error callback (optional)
139
144
  config.on_error = ->(error, context) {
140
145
  # Report to your error tracking service
@@ -359,6 +364,78 @@ Reputable.lookup_reputation(:ip, request.ip)
359
364
 
360
365
  ---
361
366
 
367
+ ## User Verification & Trust Flow
368
+
369
+ When you identify a suspicious user (e.g., high risk score or specific tag), you can redirect them to the Reputable verification page. This page performs advanced browser checks and challenges (CAPTCHA) if necessary.
370
+
371
+ ### 1. Generating a Signed Redirect URL
372
+
373
+ To effectively hand off verification handling to Reputable, generate a signed verification URL:
374
+
375
+ ```ruby
376
+ # In your controller
377
+ if suspicious_activity_detected?
378
+ redirect_url = Reputable.verification_url(
379
+ return_url: request.original_url, # Where to send them back after verification
380
+ failure_url: root_url, # Optional: where to send if they fail/garbage token
381
+ session_id: session.id # Optional: link specific session
382
+ )
383
+
384
+ redirect_to redirect_url
385
+ end
386
+ ```
387
+
388
+ ### 2. Handling the Return Redirect
389
+
390
+ When the user passes verification (or is determined to be already trusted/clean), they are immediately redirected back to your `return_url` with signed parameters.
391
+
392
+ **Middleware (Automatic Handling):**
393
+ If you are using `Reputable::Middleware` (recommended), this is handled automatically. The middleware detects the return parameters, verifies the signature, and sets `env['reputable.verified'] = true`.
394
+
395
+ ```ruby
396
+ # In your controller
397
+ if request.env['reputable.verified']
398
+ # User just passed verification!
399
+ # You might want to graduate them to trusted status locally
400
+ trust_current_ip(reason: 'interactive_verification')
401
+ end
402
+ ```
403
+
404
+ **Manual Verification:**
405
+ If you need to verify manually (e.g., custom controller logic):
406
+
407
+ ```ruby
408
+ # In your controller action (the return_url target)
409
+ if params[:reputable_signature]
410
+ if Reputable.verify_redirect_return(params)
411
+ # Signature is VALID. Meaning Reputable actually sent this user back.
412
+
413
+ # Inspect outcomes
414
+ status = params[:reputable_status] # 'pass', 'fail'
415
+ outcome = params[:reputable_outcome] # 'trusted_verified', 'trusted_behavior', 'unknown'
416
+ country = params[:reputable_country] # 'US', 'DE', etc.
417
+
418
+ if status == 'pass'
419
+ # Grant access
420
+ end
421
+ else
422
+ # Invalid signature - potential tampering attempt!
423
+ render plain: "Verification failed", status: 403
424
+ end
425
+ end
426
+ ```
427
+
428
+ **Return Parameters:**
429
+ The return URL will contain:
430
+ - `reputable_status`: `pass` or `fail`
431
+ - `reputable_session_id`: The session ID you provided
432
+ - `reputable_outcome`: The specific reputation outcome (e.g., `trusted_verified`)
433
+ - `reputable_ignore_analytics`: 'true'/'false' flag
434
+ - `reputable_country`: ISO country code
435
+ - `reputable_signature`: HMAC-SHA256 signature of the above
436
+
437
+ ---
438
+
362
439
  ## Resilience & Failsafe Features
363
440
 
364
441
  ### Never Breaks Your App
@@ -14,7 +14,7 @@ module Reputable
14
14
  :default_ttls, :pool_size, :pool_timeout,
15
15
  :connect_timeout, :read_timeout, :write_timeout,
16
16
  :ssl_params, :trusted_proxies, :ip_header_priority,
17
- :on_error, :secret_key, :verification_base_url
17
+ :on_error, :trusted_keys, :verification_base_url
18
18
 
19
19
  # Default TTLs in seconds (0 = forever)
20
20
  DEFAULT_TTLS = {
@@ -63,10 +63,36 @@ module Reputable
63
63
  @trusted_proxies = nil # Additional trusted proxy IPs/ranges
64
64
  @ip_header_priority = DEFAULT_IP_HEADERS.dup
65
65
  @on_error = nil # Optional error callback: ->(error, context) { ... }
66
- @secret_key = ENV["REPUTABLE_SECRET_KEY"]
66
+
67
+ # Support multiple trusted keys (comma-separated), fallback to old secret key env var
68
+ @trusted_keys = []
69
+ if ENV["REPUTABLE_TRUSTED_KEYS"]
70
+ @trusted_keys = ENV["REPUTABLE_TRUSTED_KEYS"].split(",").map(&:strip)
71
+ elsif ENV["REPUTABLE_TRUSTED_KEY"]
72
+ @trusted_keys = [ENV["REPUTABLE_TRUSTED_KEY"]]
73
+ elsif ENV["REPUTABLE_SECRET_KEY"]
74
+ @trusted_keys = [ENV["REPUTABLE_SECRET_KEY"]]
75
+ end
67
76
  @verification_base_url = ENV.fetch("REPUTABLE_VERIFY_URL", "https://api.reputable.click/_reputable/verify")
68
77
  end
69
78
 
79
+ # Alias for backward compatibility
80
+ def secret_key
81
+ @trusted_keys.first
82
+ end
83
+
84
+ def secret_key=(key)
85
+ @trusted_keys = [key]
86
+ end
87
+
88
+ def trusted_keys=(keys)
89
+ @trusted_keys = Array(keys)
90
+ end
91
+
92
+ def trusted_keys
93
+ @trusted_keys
94
+ end
95
+
70
96
  # Check if Reputable is enabled (can be disabled via ENV)
71
97
  def enabled?
72
98
  env_value = ENV["REPUTABLE_ENABLED"]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Reputable
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/reputable.rb CHANGED
@@ -127,12 +127,15 @@ module Reputable
127
127
 
128
128
  # Generate a signed verification URL
129
129
  def verification_url(return_url:, failure_url: nil, session_id: nil)
130
- secret = configuration.secret_key
131
- unless secret
132
- logger&.warn "Reputable: Missing secret_key, cannot generate verification URL"
130
+ keys = configuration.trusted_keys
131
+ if keys.nil? || keys.empty?
132
+ logger&.warn "Reputable: Missing trusted_keys, cannot generate verification URL"
133
133
  return return_url
134
134
  end
135
135
 
136
+ # Use the first key for signing new requests
137
+ secret = keys.first
138
+
136
139
  base_url = configuration.verification_base_url
137
140
 
138
141
  # JWT Header
@@ -165,19 +168,35 @@ module Reputable
165
168
  status = params["reputable_status"]
166
169
  session_id = params["reputable_session_id"]
167
170
  signature = params["reputable_signature"]
171
+ outcome = params["reputable_outcome"]
172
+ ignore_analytics = params["reputable_ignore_analytics"]
173
+ country = params["reputable_country"] || ""
168
174
 
169
175
  return false unless status && session_id && signature
170
176
 
171
- secret = configuration.secret_key
172
- unless secret
173
- logger&.warn "Reputable: Missing secret_key, cannot verify redirect"
177
+ keys = configuration.trusted_keys
178
+ if keys.nil? || keys.empty?
179
+ logger&.warn "Reputable: Missing trusted_keys, cannot verify redirect"
174
180
  return false
175
181
  end
176
182
 
177
- data = "#{status}:#{session_id}"
178
- expected_signature = OpenSSL::HMAC.hexdigest("SHA256", secret, data)
183
+ # Reconstruct data string: status:sessionId:outcome:ignoreAnalytics:country
184
+ # Note: optional params default to empty strings if missing in reconstruction logic on server
185
+ data_parts = [
186
+ status,
187
+ session_id,
188
+ outcome || "",
189
+ ignore_analytics.nil? ? "" : ignore_analytics,
190
+ country
191
+ ]
192
+
193
+ data = data_parts.join(":")
179
194
 
180
- secure_compare(expected_signature, signature)
195
+ # Iterate through all trusted keys to find a match
196
+ keys.any? do |key|
197
+ expected_signature = OpenSSL::HMAC.hexdigest("SHA256", key, data)
198
+ secure_compare(expected_signature, signature)
199
+ end
181
200
  end
182
201
 
183
202
  private
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.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reputable
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-25 00:00:00.000000000 Z
11
+ date: 2025-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis