reputable 0.1.16 → 0.1.18
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/Gemfile.lock +1 -1
- data/README.md +69 -0
- data/lib/reputable/configuration.rb +21 -1
- data/lib/reputable/middleware.rb +40 -0
- data/lib/reputable/reputation.rb +105 -0
- data/lib/reputable/version.rb +1 -1
- data/lib/reputable.rb +33 -0
- data/reputable.gemspec +38 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 40be87edb5494144f499f263572e00d98331cd07913239fca32b5ce71450df26
|
|
4
|
+
data.tar.gz: 63cfe644b94396a6d72b05a75a45076e8bc41196f6c4970307992e6260d6f86f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ed8aee9a76c98611718621fde0c1dada4aff7449092c9fc6cd1990d545b91ee1641c169d841eea12b2b0eeb56edc399e2f8db612041565a2d90dbf76bad34d92
|
|
7
|
+
data.tar.gz: 5b2eeb4fb8ddbf12beeb989b0a33aa5f42352c6a131ca1211ad5475b19978ba8244dbf52504555256aa0d79eb58935ab23be05cd503405d11d35b835bca506c0
|
data/Gemfile.lock
CHANGED
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,44 @@ 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
|
+
### ASN Fallback
|
|
309
|
+
|
|
310
|
+
When an IP has no reputation, the middleware can fall back to checking ASN reputation. This is useful for blocking/challenging entire ASNs (e.g., datacenter ASNs known for abuse).
|
|
311
|
+
|
|
312
|
+
**Enable via environment variable:**
|
|
313
|
+
```bash
|
|
314
|
+
REPUTABLE_ASN_FALLBACK=true
|
|
315
|
+
REPUTABLE_ASN_HEADER=HTTP_X_ASN # Optional, defaults to HTTP_X_ASN
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Enable via configuration:**
|
|
319
|
+
```ruby
|
|
320
|
+
Reputable.configure do |config|
|
|
321
|
+
config.asn_fallback = true
|
|
322
|
+
config.asn_header = "HTTP_X_ASN" # Or HTTP_CF_ASN for Cloudflare, etc.
|
|
323
|
+
end
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Enable via middleware option:**
|
|
327
|
+
```ruby
|
|
328
|
+
config.middleware.use Reputable::Middleware,
|
|
329
|
+
reputation_gate: true,
|
|
330
|
+
asn_fallback: true
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**How it works:**
|
|
334
|
+
1. Middleware looks up IP reputation first
|
|
335
|
+
2. If IP has no reputation and ASN fallback is enabled, it extracts ASN from the configured header
|
|
336
|
+
3. If ASN has a reputation (blocked, challenged), that decision is applied
|
|
337
|
+
4. The `env['reputable.reputation_source']` is set to `'asn'` when using ASN-based decision
|
|
338
|
+
|
|
339
|
+
**Providing ASN from your app:**
|
|
340
|
+
If your app has its own GeoIP lookup, set the ASN directly:
|
|
341
|
+
```ruby
|
|
342
|
+
# In a before_action or middleware
|
|
343
|
+
request.env['reputable.asn'] = lookup_asn_for_ip(request.remote_ip)
|
|
344
|
+
```
|
|
345
|
+
|
|
304
346
|
### Server/JS Request Reconciliation
|
|
305
347
|
|
|
306
348
|
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`.
|
|
@@ -497,6 +539,33 @@ Reputable.lookup_reputation(:ip, request.ip)
|
|
|
497
539
|
# expires_at: 0, metadata: { order_id: "123" } }
|
|
498
540
|
```
|
|
499
541
|
|
|
542
|
+
### ASN Reputation
|
|
543
|
+
|
|
544
|
+
Apply and lookup reputations for entire ASNs (Autonomous System Numbers). Useful for blocking datacenter traffic or known-bad networks.
|
|
545
|
+
|
|
546
|
+
```ruby
|
|
547
|
+
# Apply reputation to an ASN
|
|
548
|
+
Reputable.block_asn("15169", reason: "datacenter_abuse")
|
|
549
|
+
Reputable.challenge_asn("7922", reason: "suspicious_traffic")
|
|
550
|
+
Reputable.trust_asn("16509", reason: "known_partner")
|
|
551
|
+
Reputable.ignore_asn("32934", reason: "internal_monitoring")
|
|
552
|
+
|
|
553
|
+
# Quick boolean checks
|
|
554
|
+
Reputable.blocked_asn?("15169") # => true/false
|
|
555
|
+
Reputable.challenged_asn?("7922") # => true/false
|
|
556
|
+
Reputable.trusted_asn?("16509") # => true/false
|
|
557
|
+
|
|
558
|
+
# Get status string
|
|
559
|
+
Reputable.lookup_asn("15169")
|
|
560
|
+
# => "untrusted_block" or nil
|
|
561
|
+
|
|
562
|
+
# Full lookup with metadata
|
|
563
|
+
Reputable.lookup_reputation(:asn, "15169")
|
|
564
|
+
# => { status: "untrusted_block", reason: "datacenter_abuse", ... }
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Note:** ASNs are normalized automatically - both `"15169"` and `"AS15169"` work.
|
|
568
|
+
|
|
500
569
|
---
|
|
501
570
|
|
|
502
571
|
## User Verification & Trust Flow
|
|
@@ -15,7 +15,8 @@ module Reputable
|
|
|
15
15
|
:connect_timeout, :read_timeout, :write_timeout,
|
|
16
16
|
:ssl_params, :trusted_proxies, :ip_header_priority,
|
|
17
17
|
:on_error, :trusted_keys, :base_url,
|
|
18
|
-
:site_name, :support_email, :support_url
|
|
18
|
+
:site_name, :support_email, :support_url,
|
|
19
|
+
:asn_fallback, :asn_header
|
|
19
20
|
|
|
20
21
|
# Alias for backward compatibility
|
|
21
22
|
alias_method :verification_base_url, :base_url
|
|
@@ -82,6 +83,10 @@ module Reputable
|
|
|
82
83
|
@site_name = ENV["REPUTABLE_SITE_NAME"]
|
|
83
84
|
@support_email = ENV["REPUTABLE_SUPPORT_EMAIL"]
|
|
84
85
|
@support_url = ENV["REPUTABLE_SUPPORT_URL"]
|
|
86
|
+
|
|
87
|
+
# ASN fallback: when IP has no reputation, check ASN reputation
|
|
88
|
+
@asn_fallback = env_truthy?("REPUTABLE_ASN_FALLBACK")
|
|
89
|
+
@asn_header = ENV.fetch("REPUTABLE_ASN_HEADER", "HTTP_X_ASN")
|
|
85
90
|
end
|
|
86
91
|
|
|
87
92
|
# Alias for backward compatibility
|
|
@@ -158,5 +163,20 @@ module Reputable
|
|
|
158
163
|
rescue IPAddr::InvalidAddressError
|
|
159
164
|
false
|
|
160
165
|
end
|
|
166
|
+
|
|
167
|
+
# Check if ASN fallback is enabled
|
|
168
|
+
def asn_fallback?
|
|
169
|
+
@asn_fallback
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
# Helper to check if an environment variable is truthy
|
|
175
|
+
def env_truthy?(name)
|
|
176
|
+
value = ENV[name]
|
|
177
|
+
return false if value.nil?
|
|
178
|
+
|
|
179
|
+
%w[1 true yes on enabled].include?(value.to_s.downcase)
|
|
180
|
+
end
|
|
161
181
|
end
|
|
162
182
|
end
|
data/lib/reputable/middleware.rb
CHANGED
|
@@ -59,6 +59,8 @@ module Reputable
|
|
|
59
59
|
@verified_session_keys = Array(options.fetch(:verified_session_keys, [:reputable_verified_at, :reputable_verified]))
|
|
60
60
|
@blocked_page_options = options.fetch(:blocked_page, {})
|
|
61
61
|
@blocked_page_path = options[:blocked_page_path]
|
|
62
|
+
@ignore_xhr = options.fetch(:ignore_xhr, false)
|
|
63
|
+
@asn_fallback = options.key?(:asn_fallback) ? options[:asn_fallback] : nil
|
|
62
64
|
end
|
|
63
65
|
|
|
64
66
|
def call(env)
|
|
@@ -317,6 +319,17 @@ module Reputable
|
|
|
317
319
|
ip = extract_ip(env)
|
|
318
320
|
env["reputable.ip"] = ip
|
|
319
321
|
status = Reputable::Reputation.lookup_ip(ip)
|
|
322
|
+
|
|
323
|
+
# Fallback to ASN reputation if IP has no status and ASN fallback is enabled
|
|
324
|
+
if status.nil? && asn_fallback_enabled?
|
|
325
|
+
asn = extract_asn(env)
|
|
326
|
+
if asn
|
|
327
|
+
env["reputable.asn"] = asn
|
|
328
|
+
status = Reputable::Reputation.lookup_asn(asn)
|
|
329
|
+
env["reputable.reputation_source"] = "asn" if status
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
320
333
|
env["reputable.reputation_status"] = status
|
|
321
334
|
env["reputable.ignore_analytics"] = status.to_s.start_with?("untrusted")
|
|
322
335
|
status
|
|
@@ -326,6 +339,28 @@ module Reputable
|
|
|
326
339
|
nil
|
|
327
340
|
end
|
|
328
341
|
|
|
342
|
+
def asn_fallback_enabled?
|
|
343
|
+
# Middleware option takes precedence, then config
|
|
344
|
+
return @asn_fallback unless @asn_fallback.nil?
|
|
345
|
+
|
|
346
|
+
Reputable.configuration.asn_fallback?
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def extract_asn(env)
|
|
350
|
+
# First check if app explicitly set it
|
|
351
|
+
return env["reputable.asn"] if env["reputable.asn"]
|
|
352
|
+
|
|
353
|
+
# Then check the configured header
|
|
354
|
+
header = Reputable.configuration.asn_header
|
|
355
|
+
value = env[header]
|
|
356
|
+
return nil if value.nil? || value.empty?
|
|
357
|
+
|
|
358
|
+
# Normalize: strip "AS" prefix if present
|
|
359
|
+
value.to_s.strip.sub(/^AS/i, "")
|
|
360
|
+
rescue StandardError
|
|
361
|
+
nil
|
|
362
|
+
end
|
|
363
|
+
|
|
329
364
|
def blocked_page_options
|
|
330
365
|
config = Reputable.configuration
|
|
331
366
|
defaults = {
|
|
@@ -356,6 +391,7 @@ module Reputable
|
|
|
356
391
|
|
|
357
392
|
def skip_request?(env)
|
|
358
393
|
return true if @skip_if&.call(env)
|
|
394
|
+
return true if @ignore_xhr && xhr_request?(env)
|
|
359
395
|
|
|
360
396
|
path = env["PATH_INFO"] || "/"
|
|
361
397
|
|
|
@@ -522,5 +558,9 @@ module Reputable
|
|
|
522
558
|
rescue StandardError
|
|
523
559
|
nil
|
|
524
560
|
end
|
|
561
|
+
|
|
562
|
+
def xhr_request?(env)
|
|
563
|
+
env["HTTP_X_REQUESTED_WITH"].to_s.downcase == "xmlhttprequest"
|
|
564
|
+
end
|
|
525
565
|
end
|
|
526
566
|
end
|
data/lib/reputable/reputation.rb
CHANGED
|
@@ -205,8 +205,113 @@ module Reputable
|
|
|
205
205
|
lookup_ip(ip) == "untrusted_challenge"
|
|
206
206
|
end
|
|
207
207
|
|
|
208
|
+
# ========================================================================
|
|
209
|
+
# ASN LOOKUP METHODS
|
|
210
|
+
# ========================================================================
|
|
211
|
+
|
|
212
|
+
# Quick lookup for ASN reputation status
|
|
213
|
+
# Returns just the status string (or nil)
|
|
214
|
+
# ASN is normalized (strips "AS" prefix if present)
|
|
215
|
+
#
|
|
216
|
+
# @param asn [String] ASN (e.g., "15169" or "AS15169")
|
|
217
|
+
# @return [String, nil] Status string or nil
|
|
218
|
+
#
|
|
219
|
+
# @example
|
|
220
|
+
# status = Reputable::Reputation.lookup_asn("15169")
|
|
221
|
+
# # => "untrusted_block" or nil
|
|
222
|
+
def lookup_asn(asn)
|
|
223
|
+
result = lookup(:asn, normalize_asn(asn))
|
|
224
|
+
result&.dig(:status)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Check if an ASN is trusted (any trusted_* status)
|
|
228
|
+
#
|
|
229
|
+
# @param asn [String] ASN
|
|
230
|
+
# @return [Boolean] Returns false if disabled, nil lookup, or not trusted
|
|
231
|
+
def trusted_asn?(asn)
|
|
232
|
+
status = lookup_asn(asn)
|
|
233
|
+
return false if status.nil?
|
|
234
|
+
|
|
235
|
+
status.start_with?("trusted")
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Check if an ASN should be blocked
|
|
239
|
+
#
|
|
240
|
+
# @param asn [String] ASN
|
|
241
|
+
# @return [Boolean]
|
|
242
|
+
def blocked_asn?(asn)
|
|
243
|
+
lookup_asn(asn) == "untrusted_block"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Check if an ASN should be challenged
|
|
247
|
+
#
|
|
248
|
+
# @param asn [String] ASN
|
|
249
|
+
# @return [Boolean]
|
|
250
|
+
def challenged_asn?(asn)
|
|
251
|
+
lookup_asn(asn) == "untrusted_challenge"
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# ========================================================================
|
|
255
|
+
# ASN APPLY CONVENIENCE METHODS
|
|
256
|
+
# ========================================================================
|
|
257
|
+
|
|
258
|
+
# Convenience method: Trust an ASN (behavioral by default)
|
|
259
|
+
def trust_asn(asn, reason: "manual_trust", status: :trusted_behavior, ttl: nil, **metadata)
|
|
260
|
+
apply(
|
|
261
|
+
entity_type: :asn,
|
|
262
|
+
entity_id: normalize_asn(asn),
|
|
263
|
+
status: status,
|
|
264
|
+
reason: reason,
|
|
265
|
+
ttl: ttl,
|
|
266
|
+
metadata: metadata
|
|
267
|
+
)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Convenience method: Block an ASN
|
|
271
|
+
def block_asn(asn, reason: "manual_block", ttl: nil, **metadata)
|
|
272
|
+
apply(
|
|
273
|
+
entity_type: :asn,
|
|
274
|
+
entity_id: normalize_asn(asn),
|
|
275
|
+
status: :untrusted_block,
|
|
276
|
+
reason: reason,
|
|
277
|
+
ttl: ttl,
|
|
278
|
+
metadata: metadata
|
|
279
|
+
)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Convenience method: Challenge an ASN (CAPTCHA, etc.)
|
|
283
|
+
def challenge_asn(asn, reason: "suspicious_traffic", ttl: nil, **metadata)
|
|
284
|
+
apply(
|
|
285
|
+
entity_type: :asn,
|
|
286
|
+
entity_id: normalize_asn(asn),
|
|
287
|
+
status: :untrusted_challenge,
|
|
288
|
+
reason: reason,
|
|
289
|
+
ttl: ttl,
|
|
290
|
+
metadata: metadata
|
|
291
|
+
)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Convenience method: Mark ASN to be ignored in analytics
|
|
295
|
+
def ignore_asn(asn, reason: "datacenter_traffic", ttl: nil, **metadata)
|
|
296
|
+
apply(
|
|
297
|
+
entity_type: :asn,
|
|
298
|
+
entity_id: normalize_asn(asn),
|
|
299
|
+
status: :untrusted_ignore,
|
|
300
|
+
reason: reason,
|
|
301
|
+
ttl: ttl,
|
|
302
|
+
metadata: metadata
|
|
303
|
+
)
|
|
304
|
+
end
|
|
305
|
+
|
|
208
306
|
private
|
|
209
307
|
|
|
308
|
+
# Normalize ASN by stripping "AS" prefix if present
|
|
309
|
+
# @param asn [String] ASN with or without prefix
|
|
310
|
+
# @return [String] ASN without prefix
|
|
311
|
+
def normalize_asn(asn)
|
|
312
|
+
asn.to_s.sub(/^AS/i, "")
|
|
313
|
+
end
|
|
314
|
+
|
|
210
315
|
def valid_entity_type?(entity_type)
|
|
211
316
|
VALID_ENTITY_TYPES.include?(entity_type.to_sym)
|
|
212
317
|
end
|
data/lib/reputable/version.rb
CHANGED
data/lib/reputable.rb
CHANGED
|
@@ -126,6 +126,39 @@ module Reputable
|
|
|
126
126
|
Reputation.challenged_ip?(ip)
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
+
# Delegate ASN reputation methods to Reputation module
|
|
130
|
+
def lookup_asn(asn)
|
|
131
|
+
Reputation.lookup_asn(asn)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def trusted_asn?(asn)
|
|
135
|
+
Reputation.trusted_asn?(asn)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def blocked_asn?(asn)
|
|
139
|
+
Reputation.blocked_asn?(asn)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def challenged_asn?(asn)
|
|
143
|
+
Reputation.challenged_asn?(asn)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def trust_asn(asn, reason: "manual_trust", status: :trusted_behavior, ttl: nil, **metadata)
|
|
147
|
+
Reputation.trust_asn(asn, reason: reason, status: status, ttl: ttl, **metadata)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def block_asn(asn, reason: "manual_block", ttl: nil, **metadata)
|
|
151
|
+
Reputation.block_asn(asn, reason: reason, ttl: ttl, **metadata)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def challenge_asn(asn, reason: "suspicious_traffic", ttl: nil, **metadata)
|
|
155
|
+
Reputation.challenge_asn(asn, reason: reason, ttl: ttl, **metadata)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def ignore_asn(asn, reason: "datacenter_traffic", ttl: nil, **metadata)
|
|
159
|
+
Reputation.ignore_asn(asn, reason: reason, ttl: ttl, **metadata)
|
|
160
|
+
end
|
|
161
|
+
|
|
129
162
|
# Generate a signed verification URL
|
|
130
163
|
# @param return_url [String] URL to redirect to after successful verification
|
|
131
164
|
# @param failure_url [String, nil] URL to redirect to on failure (optional)
|
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.
|
|
4
|
+
version: 0.1.18
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Reputable
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-02-03 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
|