reputable 0.1.9 → 0.1.11
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 +22 -4
- data/RELEASING.md +26 -0
- data/lib/reputable/blocked_page.rb +171 -0
- data/lib/reputable/configuration.rb +1 -1
- data/lib/reputable/middleware.rb +34 -2
- data/lib/reputable/rails.rb +16 -3
- data/lib/reputable/reputation.rb +6 -4
- data/lib/reputable/version.rb +1 -1
- data/lib/reputable.rb +4 -4
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 342aa90209deb951c9e527396dfc48b1609603ac305bac088c6d20846c1a6dee
|
|
4
|
+
data.tar.gz: 65a4a67057b29ee2c787788393e7803302e958397974b53685a792cdc668718a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f410554eaf31c3386094003f72665d9b7b6020b68c91d67ef4626589708ea1fe47bb01f975971a282f0e7e08dadc9384ae8babf816dec1ee1a8febbc0668ecc9
|
|
7
|
+
data.tar.gz: 244d984492e5a91987e17ceadfe5e67e88beba0280c5a56057cf112768f9c981738ae72b63c91da93dce80c92c56c86a7ad9af220f914a791c6dc86844915af6
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -129,7 +129,7 @@ Reputable.configure do |config|
|
|
|
129
129
|
# Customize TTLs (in seconds, 0 = forever)
|
|
130
130
|
config.default_ttls = {
|
|
131
131
|
trusted_verified: 0, # Forever
|
|
132
|
-
trusted_behavior:
|
|
132
|
+
trusted_behavior: 365 * 24 * 3600, # 1 year
|
|
133
133
|
untrusted_challenge: 7 * 24 * 3600,
|
|
134
134
|
untrusted_block: 7 * 24 * 3600,
|
|
135
135
|
untrusted_ignore: 7 * 24 * 3600
|
|
@@ -269,7 +269,11 @@ config.middleware.use Reputable::Middleware,
|
|
|
269
269
|
},
|
|
270
270
|
|
|
271
271
|
# Async mode (default: true) - tracking runs in background thread
|
|
272
|
-
async: true
|
|
272
|
+
async: true,
|
|
273
|
+
|
|
274
|
+
# Expose reputation flags in request env for views/controllers (default: true)
|
|
275
|
+
# Sets request.env['reputable.ignore_analytics'] when status is untrusted_ignore
|
|
276
|
+
expose_reputation: true
|
|
273
277
|
```
|
|
274
278
|
|
|
275
279
|
### Optional Reputation Gate
|
|
@@ -328,6 +332,11 @@ if current_ip_trusted?
|
|
|
328
332
|
# Skip CAPTCHA, higher rate limits
|
|
329
333
|
end
|
|
330
334
|
|
|
335
|
+
# View/helper flag for untrusted_ignore
|
|
336
|
+
if reputable_ignore_analytics?
|
|
337
|
+
# Skip analytics / tracking in views
|
|
338
|
+
end
|
|
339
|
+
|
|
331
340
|
if current_ip_blocked?
|
|
332
341
|
render status: 403
|
|
333
342
|
return
|
|
@@ -416,8 +425,17 @@ Reputable.track_request_async(
|
|
|
416
425
|
### Reputation Management
|
|
417
426
|
|
|
418
427
|
```ruby
|
|
419
|
-
# Trust IP
|
|
420
|
-
Reputable.trust_ip(request.ip, reason: '
|
|
428
|
+
# Trust IP (behavioral by default, uses default TTL)
|
|
429
|
+
Reputable.trust_ip(request.ip, reason: 'behavior_trust', order_id: order.id)
|
|
430
|
+
|
|
431
|
+
# Trust IP as verified (forever, explicitly)
|
|
432
|
+
Reputable.trust_ip(
|
|
433
|
+
request.ip,
|
|
434
|
+
reason: 'payment_completed',
|
|
435
|
+
status: :trusted_verified,
|
|
436
|
+
ttl: 0,
|
|
437
|
+
order_id: order.id
|
|
438
|
+
)
|
|
421
439
|
|
|
422
440
|
# Challenge (require CAPTCHA, etc.)
|
|
423
441
|
Reputable.challenge_ip(request.ip, reason: 'unusual_activity')
|
data/RELEASING.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Releasing the Ruby Gem
|
|
2
|
+
|
|
3
|
+
## Update version + changelog
|
|
4
|
+
|
|
5
|
+
1. Bump the version in `clients/ruby/lib/reputable/version.rb`.
|
|
6
|
+
2. Add a matching entry in `CHANGELOG.md` (repo root).
|
|
7
|
+
|
|
8
|
+
## Build the gem (optional local check)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
cd clients/ruby
|
|
12
|
+
bundle exec rake build
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Build + push from repo root (npm script)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run release:gem
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Publish (if applicable)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd clients/ruby
|
|
25
|
+
gem push pkg/reputable-<version>.gem
|
|
26
|
+
```
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Reputable
|
|
4
|
+
# Simple HTML blocked page renderer for Rack/Rails usage.
|
|
5
|
+
module BlockedPage
|
|
6
|
+
class << self
|
|
7
|
+
def response(
|
|
8
|
+
site_name: nil,
|
|
9
|
+
support_email: nil,
|
|
10
|
+
support_url: nil,
|
|
11
|
+
client_ip: nil,
|
|
12
|
+
heading: "Access blocked",
|
|
13
|
+
message: nil,
|
|
14
|
+
status: 403,
|
|
15
|
+
show_ip: true
|
|
16
|
+
)
|
|
17
|
+
html = build_html(
|
|
18
|
+
site_name: site_name,
|
|
19
|
+
support_email: support_email,
|
|
20
|
+
support_url: support_url,
|
|
21
|
+
client_ip: client_ip,
|
|
22
|
+
heading: heading,
|
|
23
|
+
message: message,
|
|
24
|
+
show_ip: show_ip
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
headers = {
|
|
28
|
+
"Content-Type" => "text/html; charset=utf-8",
|
|
29
|
+
"Cache-Control" => "no-store"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[status, headers, [html]]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def html(**options)
|
|
36
|
+
build_html(**options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def build_html(site_name:, support_email:, support_url:, client_ip:, heading:, message:, show_ip:)
|
|
42
|
+
display_name = escape_html(site_name || "this site")
|
|
43
|
+
safe_support_email = support_email ? escape_html(support_email) : nil
|
|
44
|
+
safe_support_url = support_url ? escape_html(support_url) : nil
|
|
45
|
+
safe_heading = escape_html(heading || "Access blocked")
|
|
46
|
+
safe_message = escape_html(
|
|
47
|
+
message || "We cannot allow this request for #{display_name}. Your connection was blocked by a security policy."
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
contact_line = if safe_support_email || safe_support_url
|
|
51
|
+
parts = []
|
|
52
|
+
parts << if safe_support_email
|
|
53
|
+
%(at <a href="mailto:#{safe_support_email}">#{safe_support_email}</a>)
|
|
54
|
+
else
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
parts << if safe_support_url
|
|
58
|
+
%(via <a href="#{safe_support_url}">support</a>)
|
|
59
|
+
else
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
parts.compact.join(" or ")
|
|
63
|
+
else
|
|
64
|
+
"by contacting the site owner"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
ip_line = if show_ip && client_ip && !client_ip.to_s.empty?
|
|
68
|
+
%(<div class="ip-text">Your IP: #{escape_html(client_ip.to_s)}</div>)
|
|
69
|
+
else
|
|
70
|
+
""
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
<<~HTML
|
|
74
|
+
<!DOCTYPE html>
|
|
75
|
+
<html lang="en">
|
|
76
|
+
<head>
|
|
77
|
+
<meta charset="UTF-8">
|
|
78
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
79
|
+
<title>Access blocked</title>
|
|
80
|
+
<style>
|
|
81
|
+
:root {
|
|
82
|
+
--bg-color: #fafafa;
|
|
83
|
+
--card-bg: #ffffff;
|
|
84
|
+
--text-color: #333333;
|
|
85
|
+
--text-muted: #6b7280;
|
|
86
|
+
--border-color: #e5e7eb;
|
|
87
|
+
--link-color: #2563eb;
|
|
88
|
+
}
|
|
89
|
+
@media (prefers-color-scheme: dark) {
|
|
90
|
+
:root {
|
|
91
|
+
--bg-color: #0f0f0f;
|
|
92
|
+
--card-bg: #1a1a1a;
|
|
93
|
+
--text-color: #f3f4f6;
|
|
94
|
+
--text-muted: #9ca3af;
|
|
95
|
+
--border-color: #374151;
|
|
96
|
+
--link-color: #60a5fa;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
* { box-sizing: border-box; }
|
|
100
|
+
body {
|
|
101
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
|
|
102
|
+
background: var(--bg-color);
|
|
103
|
+
color: var(--text-color);
|
|
104
|
+
display: flex;
|
|
105
|
+
align-items: center;
|
|
106
|
+
justify-content: center;
|
|
107
|
+
min-height: 100vh;
|
|
108
|
+
margin: 0;
|
|
109
|
+
padding: 20px;
|
|
110
|
+
}
|
|
111
|
+
.card {
|
|
112
|
+
max-width: 520px;
|
|
113
|
+
width: 100%;
|
|
114
|
+
padding: 40px;
|
|
115
|
+
background: var(--card-bg);
|
|
116
|
+
border: 1px solid var(--border-color);
|
|
117
|
+
border-radius: 12px;
|
|
118
|
+
text-align: center;
|
|
119
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
|
|
120
|
+
}
|
|
121
|
+
h1 { margin: 0 0 12px; font-size: 22px; font-weight: 600; }
|
|
122
|
+
p { margin: 0 0 20px; line-height: 1.5; color: var(--text-muted); }
|
|
123
|
+
a { color: var(--link-color); text-decoration: none; }
|
|
124
|
+
a:hover { text-decoration: underline; }
|
|
125
|
+
.muted { font-size: 13px; color: var(--text-muted); }
|
|
126
|
+
.branding {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
justify-content: center;
|
|
130
|
+
gap: 8px;
|
|
131
|
+
margin-top: 24px;
|
|
132
|
+
padding-top: 20px;
|
|
133
|
+
border-top: 1px solid var(--border-color);
|
|
134
|
+
}
|
|
135
|
+
.branding-text {
|
|
136
|
+
font-size: 12px;
|
|
137
|
+
color: var(--text-muted);
|
|
138
|
+
}
|
|
139
|
+
.ip-text {
|
|
140
|
+
margin-top: 12px;
|
|
141
|
+
font-size: 11px;
|
|
142
|
+
color: var(--text-muted);
|
|
143
|
+
}
|
|
144
|
+
</style>
|
|
145
|
+
</head>
|
|
146
|
+
<body>
|
|
147
|
+
<div class="card">
|
|
148
|
+
<h1>#{safe_heading}</h1>
|
|
149
|
+
<p>#{safe_message}</p>
|
|
150
|
+
<p class="muted">If you believe this is a mistake, you can reach #{display_name} #{contact_line}.</p>
|
|
151
|
+
<div class="branding">
|
|
152
|
+
<span class="branding-text">Protected by Reputable</span>
|
|
153
|
+
</div>
|
|
154
|
+
#{ip_line}
|
|
155
|
+
</div>
|
|
156
|
+
</body>
|
|
157
|
+
</html>
|
|
158
|
+
HTML
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def escape_html(text)
|
|
162
|
+
text.to_s
|
|
163
|
+
.gsub("&", "&")
|
|
164
|
+
.gsub("<", "<")
|
|
165
|
+
.gsub(">", ">")
|
|
166
|
+
.gsub('"', """)
|
|
167
|
+
.gsub("'", "'")
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
@@ -24,7 +24,7 @@ module Reputable
|
|
|
24
24
|
# Default TTLs in seconds (0 = forever)
|
|
25
25
|
DEFAULT_TTLS = {
|
|
26
26
|
trusted_verified: 0, # Forever
|
|
27
|
-
trusted_behavior:
|
|
27
|
+
trusted_behavior: 365 * 24 * 3600, # 1 year
|
|
28
28
|
untrusted_challenge: 7 * 24 * 3600, # 7 days
|
|
29
29
|
untrusted_block: 7 * 24 * 3600, # 7 days
|
|
30
30
|
untrusted_ignore: 7 * 24 * 3600 # 7 days
|
data/lib/reputable/middleware.rb
CHANGED
|
@@ -45,6 +45,7 @@ module Reputable
|
|
|
45
45
|
@tag_builder = options[:tag_builder]
|
|
46
46
|
@async = options.fetch(:async, true)
|
|
47
47
|
@reputation_gate = options.fetch(:reputation_gate, false)
|
|
48
|
+
@expose_reputation = options.fetch(:expose_reputation, true)
|
|
48
49
|
@challenge_action = options.fetch(:challenge_action, :verify)
|
|
49
50
|
@block_action = options.fetch(:block_action, :blocked_page_remote)
|
|
50
51
|
@challenge_redirect_status = options.fetch(:challenge_redirect_status, 302)
|
|
@@ -72,6 +73,9 @@ module Reputable
|
|
|
72
73
|
return gate_response
|
|
73
74
|
end
|
|
74
75
|
|
|
76
|
+
# Optional: expose reputation context for views/controllers
|
|
77
|
+
safe_apply_reputation_context(env) if @expose_reputation
|
|
78
|
+
|
|
75
79
|
# ALWAYS process the request first - tracking must never block
|
|
76
80
|
status, headers, response = @app.call(env)
|
|
77
81
|
|
|
@@ -96,9 +100,9 @@ module Reputable
|
|
|
96
100
|
end
|
|
97
101
|
|
|
98
102
|
def enforce_reputation_gate(env)
|
|
99
|
-
|
|
100
|
-
status = Reputable::Reputation.lookup_ip(ip)
|
|
103
|
+
status = reputation_status(env)
|
|
101
104
|
return nil if status.nil?
|
|
105
|
+
ip = env["reputable.ip"] || extract_ip(env)
|
|
102
106
|
|
|
103
107
|
case status
|
|
104
108
|
when "untrusted_block"
|
|
@@ -133,6 +137,10 @@ module Reputable
|
|
|
133
137
|
|
|
134
138
|
if Reputable.verify_redirect_return(request.params)
|
|
135
139
|
env["reputable.verified"] = true
|
|
140
|
+
ignore_analytics = request.params["reputable_ignore_analytics"]
|
|
141
|
+
unless ignore_analytics.nil?
|
|
142
|
+
env["reputable.ignore_analytics"] = ignore_analytics.to_s == "true"
|
|
143
|
+
end
|
|
136
144
|
|
|
137
145
|
# Store in session if available
|
|
138
146
|
if env["rack.session"]
|
|
@@ -255,6 +263,30 @@ module Reputable
|
|
|
255
263
|
Reputable::BlockedPage.response(**options)
|
|
256
264
|
end
|
|
257
265
|
|
|
266
|
+
def safe_apply_reputation_context(env)
|
|
267
|
+
return unless Reputable.enabled?
|
|
268
|
+
return if skip_request?(env)
|
|
269
|
+
|
|
270
|
+
reputation_status(env)
|
|
271
|
+
rescue StandardError => e
|
|
272
|
+
Reputable.logger&.debug("Reputable reputation context: #{e.class} - #{e.message}")
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def reputation_status(env)
|
|
276
|
+
return env["reputable.reputation_status"] if env.key?("reputable.reputation_status")
|
|
277
|
+
|
|
278
|
+
ip = extract_ip(env)
|
|
279
|
+
env["reputable.ip"] = ip
|
|
280
|
+
status = Reputable::Reputation.lookup_ip(ip)
|
|
281
|
+
env["reputable.reputation_status"] = status
|
|
282
|
+
env["reputable.ignore_analytics"] = (status == "untrusted_ignore")
|
|
283
|
+
status
|
|
284
|
+
rescue StandardError
|
|
285
|
+
env["reputable.reputation_status"] = nil
|
|
286
|
+
env["reputable.ignore_analytics"] = false
|
|
287
|
+
nil
|
|
288
|
+
end
|
|
289
|
+
|
|
258
290
|
def blocked_page_options
|
|
259
291
|
config = Reputable.configuration
|
|
260
292
|
defaults = {
|
data/lib/reputable/rails.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Reputable
|
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
9
|
|
|
10
10
|
included do
|
|
11
|
-
helper_method :reputable_verified? if respond_to?(:helper_method)
|
|
11
|
+
helper_method :reputable_verified?, :reputable_ignore_analytics? if respond_to?(:helper_method)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Track the current request with optional extra tags
|
|
@@ -25,11 +25,13 @@ module Reputable
|
|
|
25
25
|
)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
# Trust the current user's IP (
|
|
29
|
-
def trust_current_ip(reason:, **metadata)
|
|
28
|
+
# Trust the current user's IP (behavioral by default, verified optional)
|
|
29
|
+
def trust_current_ip(reason:, status: :trusted_behavior, ttl: nil, **metadata)
|
|
30
30
|
Reputable::Reputation.trust_ip(
|
|
31
31
|
request.remote_ip,
|
|
32
32
|
reason: reason,
|
|
33
|
+
status: status,
|
|
34
|
+
ttl: ttl,
|
|
33
35
|
**metadata
|
|
34
36
|
)
|
|
35
37
|
end
|
|
@@ -86,6 +88,17 @@ module Reputable
|
|
|
86
88
|
Reputable::Reputation.lookup_ip(request.remote_ip)
|
|
87
89
|
end
|
|
88
90
|
|
|
91
|
+
# Check if analytics should be ignored for this request
|
|
92
|
+
# Uses middleware-populated flag when available, falls back to lookup.
|
|
93
|
+
def reputable_ignore_analytics?
|
|
94
|
+
value = request.env["reputable.ignore_analytics"]
|
|
95
|
+
return value unless value.nil?
|
|
96
|
+
|
|
97
|
+
current_ip_status == "untrusted_ignore"
|
|
98
|
+
rescue StandardError
|
|
99
|
+
false
|
|
100
|
+
end
|
|
101
|
+
|
|
89
102
|
# ========================================
|
|
90
103
|
# Verification redirect helpers
|
|
91
104
|
# ========================================
|
data/lib/reputable/reputation.rb
CHANGED
|
@@ -62,14 +62,16 @@ module Reputable
|
|
|
62
62
|
false
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
# Convenience method: Trust an IP (
|
|
66
|
-
|
|
65
|
+
# Convenience method: Trust an IP (behavioral by default)
|
|
66
|
+
# @param status [Symbol] :trusted_behavior or :trusted_verified
|
|
67
|
+
# @param ttl [Integer, nil] TTL in seconds (0 = forever, nil = use default)
|
|
68
|
+
def trust_ip(ip, reason: "manual_trust", status: :trusted_behavior, ttl: nil, **metadata)
|
|
67
69
|
apply(
|
|
68
70
|
entity_type: :ip,
|
|
69
71
|
entity_id: ip,
|
|
70
|
-
status:
|
|
72
|
+
status: status,
|
|
71
73
|
reason: reason,
|
|
72
|
-
ttl:
|
|
74
|
+
ttl: ttl,
|
|
73
75
|
metadata: metadata
|
|
74
76
|
)
|
|
75
77
|
end
|
data/lib/reputable/version.rb
CHANGED
data/lib/reputable.rb
CHANGED
|
@@ -34,8 +34,8 @@ end
|
|
|
34
34
|
# path: "/products/123"
|
|
35
35
|
# )
|
|
36
36
|
#
|
|
37
|
-
# @example Apply reputation after payment
|
|
38
|
-
# Reputable.trust_ip("203.0.113.45", reason: "payment_completed")
|
|
37
|
+
# @example Apply verified reputation after payment
|
|
38
|
+
# Reputable.trust_ip("203.0.113.45", reason: "payment_completed", status: :trusted_verified, ttl: 0)
|
|
39
39
|
#
|
|
40
40
|
# @example Disable completely via ENV
|
|
41
41
|
# # In your environment: REPUTABLE_ENABLED=false
|
|
@@ -89,8 +89,8 @@ module Reputable
|
|
|
89
89
|
Reputation.apply(entity_type: entity_type, entity_id: entity_id, status: status, **options)
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
def trust_ip(ip, reason: "manual_trust", **metadata)
|
|
93
|
-
Reputation.trust_ip(ip, reason: reason, **metadata)
|
|
92
|
+
def trust_ip(ip, reason: "manual_trust", status: :trusted_behavior, ttl: nil, **metadata)
|
|
93
|
+
Reputation.trust_ip(ip, reason: reason, status: status, ttl: ttl, **metadata)
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def block_ip(ip, reason: "manual_block", **metadata)
|
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.11
|
|
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-
|
|
11
|
+
date: 2025-12-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: redis
|
|
@@ -126,8 +126,10 @@ files:
|
|
|
126
126
|
- Gemfile
|
|
127
127
|
- Gemfile.lock
|
|
128
128
|
- README.md
|
|
129
|
+
- RELEASING.md
|
|
129
130
|
- Rakefile
|
|
130
131
|
- lib/reputable.rb
|
|
132
|
+
- lib/reputable/blocked_page.rb
|
|
131
133
|
- lib/reputable/configuration.rb
|
|
132
134
|
- lib/reputable/connection.rb
|
|
133
135
|
- lib/reputable/middleware.rb
|