minfraud 2.7.1 → 2.9.0
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/.rubocop.yml +24 -1
- data/CHANGELOG.md +44 -0
- data/CLAUDE.md +443 -0
- data/README.md +3 -1
- data/Rakefile +2 -2
- data/lib/minfraud/components/base.rb +2 -0
- data/lib/minfraud/components/email.rb +2 -2
- data/lib/minfraud/components/event.rb +20 -3
- data/lib/minfraud/components/payment.rb +25 -0
- data/lib/minfraud/components/report/transaction.rb +3 -3
- data/lib/minfraud/components/shopping_cart.rb +1 -1
- data/lib/minfraud/enum.rb +3 -0
- data/lib/minfraud/http_service/response.rb +2 -0
- data/lib/minfraud/model/email_domain.rb +33 -1
- data/lib/minfraud/model/email_domain_visit.rb +43 -0
- data/lib/minfraud/model/phone.rb +10 -0
- data/lib/minfraud/model/risk_score_reason.rb +2 -2
- data/lib/minfraud/validates.rb +3 -3
- data/lib/minfraud/version.rb +1 -1
- data/lib/minfraud.rb +11 -0
- data/minfraud.gemspec +6 -2
- metadata +64 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7182466f12206a3a2d7639cabb6d7937e10d91dc7bac4684482b38b27dc1237e
|
|
4
|
+
data.tar.gz: 2a304dbe22670677bd3aaa7fbdba6b738ea460652893c351bf686861e63dd56d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 347bc9a5c45f747e1bca1608b6d4c0623d11627cdbca48657b45fd3bf7f04b21d4aae579fe81333935477a6dcd5d6e59a95a0ba5df18560a7969385661aab0ac
|
|
7
|
+
data.tar.gz: 90eeb55ddfc1f93fcf3eb981ed34a79402910e6ca097b7e4cb7098c847e414c01c628dc1f5a3d113d299621596172e2a5adef1affd88c6103e0e8217b37206e2
|
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
plugins:
|
|
2
|
+
- rubocop-performance
|
|
3
|
+
- rubocop-rake
|
|
4
|
+
- rubocop-rspec
|
|
5
|
+
- rubocop-thread_safety
|
|
6
|
+
|
|
1
7
|
AllCops:
|
|
2
|
-
TargetRubyVersion: '3.
|
|
8
|
+
TargetRubyVersion: '3.2'
|
|
3
9
|
NewCops: enable
|
|
4
10
|
|
|
5
11
|
# Metrics.
|
|
@@ -88,3 +94,20 @@ Naming/VariableNumber:
|
|
|
88
94
|
|
|
89
95
|
Gemspec/DevelopmentDependencies:
|
|
90
96
|
Enabled: false
|
|
97
|
+
|
|
98
|
+
# This might make sense, but I don't think it's worth moving things around for.
|
|
99
|
+
RSpec/SpecFilePathFormat:
|
|
100
|
+
Enabled: false
|
|
101
|
+
# Sometimes it makes sense to have lots of assertions.
|
|
102
|
+
RSpec/MultipleExpectations:
|
|
103
|
+
Enabled: false
|
|
104
|
+
# Sometimes it makes sense to have long tests.
|
|
105
|
+
RSpec/ExampleLength:
|
|
106
|
+
Enabled: false
|
|
107
|
+
# This seems okay.
|
|
108
|
+
RSpec/MultipleDescribes:
|
|
109
|
+
Enabled: false
|
|
110
|
+
# This seems to give a bunch of false positives. Specifically it's flagging
|
|
111
|
+
# things where we are creating an object and checking no exception happens.
|
|
112
|
+
RSpec/NoExpectationExample:
|
|
113
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.9.0 (2025-11-20)
|
|
4
|
+
|
|
5
|
+
* Added the processor `:securepay` to `Minfraud::Components::Payment`.
|
|
6
|
+
* Ruby 3.2+ is now required. If you're using Ruby 3.0 or 3.1, please use
|
|
7
|
+
version 2.8.0 of this gem.
|
|
8
|
+
* Added `/event/type` values `:credit_application` and `:fund_transfer` to
|
|
9
|
+
`Minfraud::Components::Event`.
|
|
10
|
+
* Added the `/event/type` value `:sim_swap` to
|
|
11
|
+
`Minfraud::Components::Event`.
|
|
12
|
+
* Added the input `/event/party`. This is the party submitting the
|
|
13
|
+
transaction. You may provide this using the `party` attribute on
|
|
14
|
+
`Minfraud::Components::Event`.
|
|
15
|
+
* Added the input `/payment/method`. This is the payment method associated
|
|
16
|
+
with the transaction. You may provide this using the `method` attribute
|
|
17
|
+
on `Minfraud::Components::Payment`.
|
|
18
|
+
* Added support for new email domain outputs on `Minfraud::Model::EmailDomain`:
|
|
19
|
+
* `/email/domain/classification` - The domain type (e.g., business,
|
|
20
|
+
education, government, isp_email). Available as the `classification`
|
|
21
|
+
attribute.
|
|
22
|
+
* `/email/domain/risk` - A risk score from 0.01 to 99 for the domain.
|
|
23
|
+
Available as the `risk` attribute.
|
|
24
|
+
* `/email/domain/volume` - Activity across the minFraud network expressed
|
|
25
|
+
as sightings per million. Available as the `volume` attribute.
|
|
26
|
+
* `/email/domain/visit` - Information from an automated visit to the
|
|
27
|
+
domain. Available as the `visit` attribute, which returns a
|
|
28
|
+
`Minfraud::Model::EmailDomainVisit` object.
|
|
29
|
+
* Added support for email domain visit outputs on
|
|
30
|
+
`Minfraud::Model::EmailDomainVisit`:
|
|
31
|
+
* `/email/domain/visit/has_redirect` - Whether the domain redirects to
|
|
32
|
+
another URL. Available as the `has_redirect` attribute.
|
|
33
|
+
* `/email/domain/visit/last_visited_on` - The date the automated visit
|
|
34
|
+
was completed. Available as the `last_visited_on` attribute.
|
|
35
|
+
* `/email/domain/visit/status` - The status of the domain (e.g., live,
|
|
36
|
+
dns_error, parked). Available as the `status` attribute.
|
|
37
|
+
* Updated `maxmind-geoip2` to 1.4, which includes new anonymizer and IP
|
|
38
|
+
risk outputs.
|
|
39
|
+
|
|
40
|
+
## v2.8.0 (2025-05-23)
|
|
41
|
+
|
|
42
|
+
* Added support for the `/billing_phone/matches_postal` and
|
|
43
|
+
`/shipping_phone/matches_postal` outputs. These are available as the
|
|
44
|
+
`matches_postal` attribute on `Minfraud::Model::Phone`.
|
|
45
|
+
* Added the processor `:cryptomus` to `Minfraud::Components::Payment`.
|
|
46
|
+
|
|
3
47
|
## v2.7.1 (2025-02-10)
|
|
4
48
|
|
|
5
49
|
* Re-release due to bug in release workflow.
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**minfraud-api-ruby** is MaxMind's official Ruby client library for the minFraud web services:
|
|
8
|
+
- **minFraud Score, Insights, and Factors**: Fraud detection and risk scoring endpoints
|
|
9
|
+
- **minFraud Report Transaction API**: Report fraudulent or legitimate transactions
|
|
10
|
+
|
|
11
|
+
The library provides a request builder pattern through components that are assembled into assessments, then sent to the service endpoints. Responses are returned as strongly-typed model objects.
|
|
12
|
+
|
|
13
|
+
**Key Technologies:**
|
|
14
|
+
- Ruby 3.2+ (uses frozen string literals and modern Ruby features)
|
|
15
|
+
- HTTP gem for web service client functionality and persistent connections
|
|
16
|
+
- ConnectionPool for thread-safe connection management
|
|
17
|
+
- RSpec for testing
|
|
18
|
+
- RuboCop with multiple plugins for code quality
|
|
19
|
+
|
|
20
|
+
## Code Architecture
|
|
21
|
+
|
|
22
|
+
### Package Structure
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
lib/minfraud/
|
|
26
|
+
├── components/ # Request components (Account, Device, Email, etc.)
|
|
27
|
+
│ └── report/ # Report Transaction components
|
|
28
|
+
├── model/ # Response models (Score, Insights, Factors, etc.)
|
|
29
|
+
├── http_service/ # HTTP response wrapper
|
|
30
|
+
├── assessments.rb # Main request builder for Score/Insights/Factors
|
|
31
|
+
├── report.rb # Report Transaction API
|
|
32
|
+
├── resolver.rb # Maps component parameters to component objects
|
|
33
|
+
├── enum.rb # Enum helper for validated attributes
|
|
34
|
+
├── validates.rb # Input validation methods
|
|
35
|
+
├── errors.rb # Custom exceptions
|
|
36
|
+
└── version.rb # Version constant
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Key Design Patterns
|
|
40
|
+
|
|
41
|
+
#### 1. **Component-Based Request Building**
|
|
42
|
+
|
|
43
|
+
Requests are built using component objects that represent different aspects of a transaction:
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
assessment = Minfraud::Assessments.new(
|
|
47
|
+
device: { ip_address: '1.2.3.4' },
|
|
48
|
+
event: { type: :purchase },
|
|
49
|
+
billing: { country: 'US' },
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Component Architecture:**
|
|
54
|
+
- All components extend `Minfraud::Components::Base`
|
|
55
|
+
- Components use `attr_accessor` for attributes
|
|
56
|
+
- Components implement `#to_json` to convert to API request format
|
|
57
|
+
- The `Resolver` module maps hash parameters to component objects
|
|
58
|
+
- Components with enum attributes include `Minfraud::Enum` module
|
|
59
|
+
|
|
60
|
+
**Resolver Pattern:**
|
|
61
|
+
The `Minfraud::Resolver` module handles converting hashes to component objects:
|
|
62
|
+
- Maintains a `MAPPING` constant from keys to component classes
|
|
63
|
+
- The `#assign` method creates components from hashes or uses existing component objects
|
|
64
|
+
- Raises `RequestFormatError` for unknown keys
|
|
65
|
+
- Used by `Minfraud::Assessments` in initialization
|
|
66
|
+
|
|
67
|
+
#### 2. **Enum Attributes with Validation**
|
|
68
|
+
|
|
69
|
+
Components with restricted value sets use the `Enum` module:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
class Event < Base
|
|
73
|
+
include ::Minfraud::Enum
|
|
74
|
+
|
|
75
|
+
enum_accessor :type, %i[
|
|
76
|
+
account_creation
|
|
77
|
+
purchase
|
|
78
|
+
payout
|
|
79
|
+
recurring_purchase
|
|
80
|
+
referral
|
|
81
|
+
account_login
|
|
82
|
+
]
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Key Points:**
|
|
87
|
+
- `enum_accessor` creates getter/setter methods with validation
|
|
88
|
+
- Values are stored as symbols internally
|
|
89
|
+
- Raises `NotEnumValueError` if invalid value assigned
|
|
90
|
+
- The class gets a `{attribute}_values` method returning permitted values
|
|
91
|
+
|
|
92
|
+
#### 3. **Optional Client-Side Validation**
|
|
93
|
+
|
|
94
|
+
Components can optionally include `Minfraud::Validates` for input validation:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
class Device < Base
|
|
98
|
+
include ::Minfraud::Validates
|
|
99
|
+
|
|
100
|
+
def ip_address=(ip_address)
|
|
101
|
+
validate_ip('ip_address', ip_address) if Minfraud.enable_validation
|
|
102
|
+
@ip_address = ip_address
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Key Points:**
|
|
108
|
+
- Validation is disabled by default
|
|
109
|
+
- Enable with `Minfraud.configure { |c| c.enable_validation = true }`
|
|
110
|
+
- Validation happens in setters before assignment
|
|
111
|
+
- Validates types, formats, lengths, ranges, etc.
|
|
112
|
+
- Raises `InvalidInputError` for invalid values
|
|
113
|
+
|
|
114
|
+
#### 4. **Model Inheritance and Composition**
|
|
115
|
+
|
|
116
|
+
Response models follow a clear hierarchy:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Abstract → Score → Insights → Factors
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- `Abstract` provides `#get` method for safe hash access
|
|
123
|
+
- `Score` has basic risk scoring fields
|
|
124
|
+
- `Insights` extends `Score` with detailed fraud data (addresses, phones, device, etc.)
|
|
125
|
+
- `Factors` extends `Insights` with subscores and risk reasons
|
|
126
|
+
|
|
127
|
+
**Model Composition:**
|
|
128
|
+
Models compose smaller model objects representing nested data:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
class Insights < Score
|
|
132
|
+
attr_reader :billing_address
|
|
133
|
+
attr_reader :credit_card
|
|
134
|
+
attr_reader :device
|
|
135
|
+
attr_reader :email
|
|
136
|
+
|
|
137
|
+
def initialize(record, locales)
|
|
138
|
+
super
|
|
139
|
+
@billing_address = Minfraud::Model::BillingAddress.new(get('billing_address'))
|
|
140
|
+
@credit_card = Minfraud::Model::CreditCard.new(get('credit_card'))
|
|
141
|
+
# ...
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### 5. **Connection Pooling for Thread Safety**
|
|
147
|
+
|
|
148
|
+
The library uses ConnectionPool for thread-safe persistent HTTP connections:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
@connection_pool = ConnectionPool.new(size: 5) do
|
|
152
|
+
HTTP.basic_auth(user: @account_id, pass: @license_key)
|
|
153
|
+
.persistent("https://#{host}")
|
|
154
|
+
end
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Key Points:**
|
|
158
|
+
- Pool is created in `Minfraud.configure`
|
|
159
|
+
- Assessments and Reports use `Minfraud.connection_pool.with { |client| ... }`
|
|
160
|
+
- Enables persistent connections without manual management
|
|
161
|
+
- Safe for multi-threaded use
|
|
162
|
+
- Must call `Minfraud.configure` before using from multiple threads
|
|
163
|
+
|
|
164
|
+
## Testing Conventions
|
|
165
|
+
|
|
166
|
+
### Running Tests
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Install dependencies
|
|
170
|
+
bundle install
|
|
171
|
+
|
|
172
|
+
# Run all tests
|
|
173
|
+
bundle exec rake spec
|
|
174
|
+
|
|
175
|
+
# Run tests and RuboCop
|
|
176
|
+
bundle exec rake # default task
|
|
177
|
+
|
|
178
|
+
# Run RuboCop only
|
|
179
|
+
bundle exec rake rubocop
|
|
180
|
+
|
|
181
|
+
# Run specific test file
|
|
182
|
+
bundle exec rspec spec/assessments_spec.rb
|
|
183
|
+
|
|
184
|
+
# Run specific test
|
|
185
|
+
bundle exec rspec spec/assessments_spec.rb:10
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Test Structure
|
|
189
|
+
|
|
190
|
+
Tests use RSpec and are organized by functionality:
|
|
191
|
+
- `spec/assessments_spec.rb` - Main assessment request builder tests
|
|
192
|
+
- `spec/report_spec.rb` - Report Transaction API tests
|
|
193
|
+
- `spec/components/*_spec.rb` - Component tests
|
|
194
|
+
- `spec/model/*_spec.rb` - Response model tests
|
|
195
|
+
- `spec/enum_spec.rb` - Enum validation tests
|
|
196
|
+
- `spec/http_spec.rb` - HTTP integration tests
|
|
197
|
+
|
|
198
|
+
### Test Patterns
|
|
199
|
+
|
|
200
|
+
Tests use RSpec with test data hashes:
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
describe Minfraud::Model::Score do
|
|
204
|
+
let(:raw) do
|
|
205
|
+
{
|
|
206
|
+
'disposition' => { 'action' => 'accept' },
|
|
207
|
+
'funds_remaining' => 10.01,
|
|
208
|
+
'id' => '27d26476-e2bc-11e4-92b8-962e705b4af5',
|
|
209
|
+
'risk_score' => 0.01,
|
|
210
|
+
}
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
let(:model) { described_class.new(raw, ['en']) }
|
|
214
|
+
|
|
215
|
+
it 'has risk_score' do
|
|
216
|
+
expect(model.risk_score).to eq(0.01)
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
When adding new fields:
|
|
222
|
+
1. Add field to test data hash
|
|
223
|
+
2. Add expectation to verify the field is accessible
|
|
224
|
+
3. Test nil handling if field is optional
|
|
225
|
+
4. Test validation if applicable
|
|
226
|
+
|
|
227
|
+
## Working with This Codebase
|
|
228
|
+
|
|
229
|
+
### Adding New Fields to Components
|
|
230
|
+
|
|
231
|
+
For input components (request data):
|
|
232
|
+
|
|
233
|
+
1. **Add an attr_accessor**:
|
|
234
|
+
```ruby
|
|
235
|
+
# A description of the field.
|
|
236
|
+
#
|
|
237
|
+
# @return [String, nil]
|
|
238
|
+
attr_accessor :new_field
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
2. **Add validation if needed**:
|
|
242
|
+
```ruby
|
|
243
|
+
def new_field=(value)
|
|
244
|
+
validate_string('new_field', 255, value) if Minfraud.enable_validation
|
|
245
|
+
@new_field = value
|
|
246
|
+
end
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
3. **Update tests** to include the new field
|
|
250
|
+
|
|
251
|
+
### Adding New Fields to Models
|
|
252
|
+
|
|
253
|
+
For output models (response data):
|
|
254
|
+
|
|
255
|
+
1. **Add an attr_reader** (models are immutable):
|
|
256
|
+
```ruby
|
|
257
|
+
# A description of the field.
|
|
258
|
+
#
|
|
259
|
+
# @return [Type, nil]
|
|
260
|
+
attr_reader :new_field
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
2. **Initialize in constructor**:
|
|
264
|
+
```ruby
|
|
265
|
+
def initialize(record, locales)
|
|
266
|
+
super
|
|
267
|
+
@new_field = get('new_field')
|
|
268
|
+
end
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
3. **For nested objects**, create a model class:
|
|
272
|
+
```ruby
|
|
273
|
+
@new_field = Minfraud::Model::NewField.new(get('new_field'))
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
4. **Update tests** with test data and expectations
|
|
277
|
+
|
|
278
|
+
### Adding New Enum Values
|
|
279
|
+
|
|
280
|
+
When adding new values to an enum attribute:
|
|
281
|
+
|
|
282
|
+
1. **Add to the enum_accessor array**:
|
|
283
|
+
```ruby
|
|
284
|
+
enum_accessor :type, %i[
|
|
285
|
+
existing_value
|
|
286
|
+
new_value
|
|
287
|
+
]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
2. **Update CHANGELOG.md** with the new value
|
|
291
|
+
3. **Add test** to verify the new value is accepted
|
|
292
|
+
|
|
293
|
+
### Adding New Components
|
|
294
|
+
|
|
295
|
+
When creating a new component class:
|
|
296
|
+
|
|
297
|
+
1. **Extend Base** and include Enum/Validates if needed:
|
|
298
|
+
```ruby
|
|
299
|
+
class NewComponent < Base
|
|
300
|
+
include ::Minfraud::Enum
|
|
301
|
+
include ::Minfraud::Validates
|
|
302
|
+
end
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
2. **Add to Resolver::MAPPING** in lib/minfraud/resolver.rb:
|
|
306
|
+
```ruby
|
|
307
|
+
MAPPING = {
|
|
308
|
+
new_component: ::Minfraud::Components::NewComponent,
|
|
309
|
+
# ...
|
|
310
|
+
}.freeze
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
3. **Add attr_accessor** to Assessments or Report
|
|
314
|
+
4. **Require the file** in lib/minfraud.rb
|
|
315
|
+
5. **Add tests** for the component
|
|
316
|
+
|
|
317
|
+
### CHANGELOG.md Format
|
|
318
|
+
|
|
319
|
+
Always update `CHANGELOG.md` for user-facing changes.
|
|
320
|
+
|
|
321
|
+
**Important**: Do not add a date to changelog entries until release time.
|
|
322
|
+
|
|
323
|
+
- If there's an existing version entry without a date (e.g., `v2.9.0`), add your changes there
|
|
324
|
+
- If creating a new version entry, don't include a date - it will be added at release time
|
|
325
|
+
- Use past tense for descriptions
|
|
326
|
+
- Use bullet points starting with `*`
|
|
327
|
+
|
|
328
|
+
```markdown
|
|
329
|
+
## v2.10.0
|
|
330
|
+
|
|
331
|
+
* Added the `new_field` attribute to `Minfraud::Components::Device`. This
|
|
332
|
+
allows you to provide...
|
|
333
|
+
* Added the `/output/path` to the Insights response. This is available
|
|
334
|
+
as the `field_name` attribute on `Minfraud::Model::Insights`.
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Common Pitfalls and Solutions
|
|
338
|
+
|
|
339
|
+
### Problem: Components Not Registering
|
|
340
|
+
|
|
341
|
+
A new component doesn't work when passed to Assessments.
|
|
342
|
+
|
|
343
|
+
**Solution**: Make sure you:
|
|
344
|
+
1. Added the component to `Resolver::MAPPING`
|
|
345
|
+
2. Required the file in lib/minfraud.rb
|
|
346
|
+
3. Added the attr_accessor to Assessments or Report
|
|
347
|
+
|
|
348
|
+
### Problem: Thread Safety Issues
|
|
349
|
+
|
|
350
|
+
Getting connection errors or state issues in multi-threaded code.
|
|
351
|
+
|
|
352
|
+
**Solution**:
|
|
353
|
+
- Always call `Minfraud.configure` before spawning threads
|
|
354
|
+
- Never share `Minfraud::Assessments` or `Minfraud::Report` objects across threads
|
|
355
|
+
- Create new Assessment/Report instances per thread
|
|
356
|
+
|
|
357
|
+
### Problem: Validation Not Working
|
|
358
|
+
|
|
359
|
+
Validation doesn't catch invalid inputs.
|
|
360
|
+
|
|
361
|
+
**Solution**:
|
|
362
|
+
- Validation is disabled by default
|
|
363
|
+
- Enable with `Minfraud.configure { |c| c.enable_validation = true }`
|
|
364
|
+
- Make sure the component setter calls the appropriate `validate_*` method
|
|
365
|
+
|
|
366
|
+
### Problem: Enum Values Rejected
|
|
367
|
+
|
|
368
|
+
A valid enum value raises `NotEnumValueError`.
|
|
369
|
+
|
|
370
|
+
**Solution**:
|
|
371
|
+
- Enum values must be symbols (`:value` not `"value"`)
|
|
372
|
+
- Check the enum_accessor definition includes the value
|
|
373
|
+
- Values are case-sensitive
|
|
374
|
+
|
|
375
|
+
## Code Style Requirements
|
|
376
|
+
|
|
377
|
+
- **RuboCop enforced** with plugins: performance, rake, rspec, thread_safety
|
|
378
|
+
- **Frozen string literals** (`# frozen_string_literal: true`) in all files
|
|
379
|
+
- **Target Ruby 3.2+**
|
|
380
|
+
- **Max line length: 150 characters**
|
|
381
|
+
- **Hash alignment: table style** (aligned rockets and colons)
|
|
382
|
+
- **Trailing commas allowed** in arrays, hashes, and arguments
|
|
383
|
+
- **Use `if !condition`** instead of `unless condition` (NegatedIf disabled)
|
|
384
|
+
- **Metrics cops disabled** - AbcSize, ClassLength, MethodLength, etc.
|
|
385
|
+
|
|
386
|
+
Key RuboCop configurations:
|
|
387
|
+
- Guard clauses not enforced
|
|
388
|
+
- Conditional assignment not enforced
|
|
389
|
+
- Format string token checks disabled
|
|
390
|
+
- Multiple assertions allowed in RSpec tests
|
|
391
|
+
- Extra spacing with force equal sign alignment enabled
|
|
392
|
+
|
|
393
|
+
## Development Workflow
|
|
394
|
+
|
|
395
|
+
### Setup
|
|
396
|
+
```bash
|
|
397
|
+
bundle install
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Before Committing
|
|
401
|
+
```bash
|
|
402
|
+
# Run tests and linting
|
|
403
|
+
bundle exec rake
|
|
404
|
+
|
|
405
|
+
# Or run separately
|
|
406
|
+
bundle exec rake spec
|
|
407
|
+
bundle exec rake rubocop
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Running Single Test
|
|
411
|
+
```bash
|
|
412
|
+
bundle exec rspec spec/assessments_spec.rb
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Testing Against Sandbox
|
|
416
|
+
```ruby
|
|
417
|
+
Minfraud.configure do |c|
|
|
418
|
+
c.account_id = 12345
|
|
419
|
+
c.license_key = 'your_license_key'
|
|
420
|
+
c.host = 'sandbox.maxmind.com'
|
|
421
|
+
end
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Version Requirements
|
|
425
|
+
- **Ruby 3.2+** required
|
|
426
|
+
- Target compatibility should match current supported Ruby versions
|
|
427
|
+
|
|
428
|
+
## API Endpoints
|
|
429
|
+
|
|
430
|
+
The library supports three assessment endpoints:
|
|
431
|
+
- `assessment.score` - Basic risk score (Score model)
|
|
432
|
+
- `assessment.insights` - Score + detailed fraud data (Insights model)
|
|
433
|
+
- `assessment.factors` - Insights + subscores + risk reasons (Factors model)
|
|
434
|
+
|
|
435
|
+
Report Transaction API:
|
|
436
|
+
- `reporter.report_transaction` - Report transaction outcomes
|
|
437
|
+
|
|
438
|
+
## Additional Resources
|
|
439
|
+
|
|
440
|
+
- [API Documentation](https://www.rubydoc.info/gems/minfraud)
|
|
441
|
+
- [minFraud Web Services Docs](https://dev.maxmind.com/minfraud)
|
|
442
|
+
- [Report Transaction API Docs](https://dev.maxmind.com/minfraud/report-a-transaction)
|
|
443
|
+
- GitHub Issues: https://github.com/maxmind/minfraud-api-ruby/issues
|
data/README.md
CHANGED
|
@@ -86,6 +86,7 @@ assessment = Minfraud::Assessments.new(
|
|
|
86
86
|
user_agent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36',
|
|
87
87
|
},
|
|
88
88
|
event: {
|
|
89
|
+
party: :customer,
|
|
89
90
|
transaction_id: 'txn3134133',
|
|
90
91
|
shop_id: 's2123',
|
|
91
92
|
time: '2012-04-12T23:20:50+00:00',
|
|
@@ -127,6 +128,7 @@ assessment = Minfraud::Assessments.new(
|
|
|
127
128
|
delivery_speed: :same_day,
|
|
128
129
|
},
|
|
129
130
|
payment: {
|
|
131
|
+
method: :card,
|
|
130
132
|
processor: :stripe,
|
|
131
133
|
was_authorized: false,
|
|
132
134
|
decline_code: 'invalid number',
|
|
@@ -275,7 +277,7 @@ to the client API, please see
|
|
|
275
277
|
|
|
276
278
|
## Requirements
|
|
277
279
|
|
|
278
|
-
This gem works with Ruby 3.
|
|
280
|
+
This gem works with Ruby 3.2 and above.
|
|
279
281
|
|
|
280
282
|
## Contributing
|
|
281
283
|
|
data/Rakefile
CHANGED
|
@@ -99,7 +99,7 @@ module Minfraud
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
if domain == 'gmail.com'
|
|
102
|
-
local_part.
|
|
102
|
+
local_part.delete!('.')
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
domain_parts = domain.split('.')
|
|
@@ -384,7 +384,7 @@ module Minfraud
|
|
|
384
384
|
|
|
385
385
|
idx = domain.rindex('.')
|
|
386
386
|
if !idx.nil?
|
|
387
|
-
tld = domain[idx + 1..]
|
|
387
|
+
tld = domain[(idx + 1)..]
|
|
388
388
|
if TYPO_TLDS.key?(tld)
|
|
389
389
|
domain = "#{domain[0, idx]}.#{TYPO_TLDS[tld]}"
|
|
390
390
|
end
|
|
@@ -9,6 +9,18 @@ module Minfraud
|
|
|
9
9
|
include ::Minfraud::Enum
|
|
10
10
|
include Minfraud::Validates
|
|
11
11
|
|
|
12
|
+
# The party submitting the transaction. This must be one of +:agent+ or
|
|
13
|
+
# +:customer+.
|
|
14
|
+
#
|
|
15
|
+
# @!attribute party
|
|
16
|
+
#
|
|
17
|
+
# @return [Symbol, nil]
|
|
18
|
+
enum_accessor :party,
|
|
19
|
+
%i[
|
|
20
|
+
agent
|
|
21
|
+
customer
|
|
22
|
+
]
|
|
23
|
+
|
|
12
24
|
# Your internal ID for the transaction. MaxMind can use this to locate a
|
|
13
25
|
# specific transaction in logs, and it will also show up in email alerts
|
|
14
26
|
# and notifications from MaxMind to you. No specific format is required.
|
|
@@ -35,9 +47,10 @@ module Minfraud
|
|
|
35
47
|
attr_accessor :time
|
|
36
48
|
|
|
37
49
|
# The type of event being scored. This must be one of
|
|
38
|
-
# +:account_creation+, +:account_login+, +:
|
|
39
|
-
# +:
|
|
40
|
-
# +:
|
|
50
|
+
# +:account_creation+, +:account_login+, +:credit_application+,
|
|
51
|
+
# +:email_change+, +:fund_transfer+, +:password_reset+,
|
|
52
|
+
# +:payout_change+, +:purchase+, +:recurring_purchase+, +:referral+,
|
|
53
|
+
# +:sim_swap+, or +:survey+.
|
|
41
54
|
#
|
|
42
55
|
# @!attribute type
|
|
43
56
|
#
|
|
@@ -46,18 +59,22 @@ module Minfraud
|
|
|
46
59
|
%i[
|
|
47
60
|
account_creation
|
|
48
61
|
account_login
|
|
62
|
+
credit_application
|
|
49
63
|
email_change
|
|
64
|
+
fund_transfer
|
|
50
65
|
password_reset
|
|
51
66
|
payout_change
|
|
52
67
|
purchase
|
|
53
68
|
recurring_purchase
|
|
54
69
|
referral
|
|
70
|
+
sim_swap
|
|
55
71
|
survey
|
|
56
72
|
]
|
|
57
73
|
|
|
58
74
|
# @param params [Hash] Hash of parameters. Each key/value should
|
|
59
75
|
# correspond to one of the available attributes.
|
|
60
76
|
def initialize(params = {})
|
|
77
|
+
self.party = params[:party]
|
|
61
78
|
@transaction_id = params[:transaction_id]
|
|
62
79
|
@shop_id = params[:shop_id]
|
|
63
80
|
@time = params[:time]
|
|
@@ -9,6 +9,28 @@ module Minfraud
|
|
|
9
9
|
include ::Minfraud::Enum
|
|
10
10
|
include Minfraud::Validates
|
|
11
11
|
|
|
12
|
+
# The payment method associated with the transaction. This must be one of
|
|
13
|
+
# +:bank_debit+, +:bank_redirect+, +:bank_transfer+, +:buy_now_pay_later+,
|
|
14
|
+
# +:card+, +:crypto+, +:digital_wallet+, +:gift_card+,
|
|
15
|
+
# +:real_time_payment+, or +:rewards+.
|
|
16
|
+
#
|
|
17
|
+
# @!attribute method
|
|
18
|
+
#
|
|
19
|
+
# @return [Symbol, nil]
|
|
20
|
+
enum_accessor :method,
|
|
21
|
+
%i[
|
|
22
|
+
bank_debit
|
|
23
|
+
bank_redirect
|
|
24
|
+
bank_transfer
|
|
25
|
+
buy_now_pay_later
|
|
26
|
+
card
|
|
27
|
+
crypto
|
|
28
|
+
digital_wallet
|
|
29
|
+
gift_card
|
|
30
|
+
real_time_payment
|
|
31
|
+
rewards
|
|
32
|
+
]
|
|
33
|
+
|
|
12
34
|
# The payment processor used for the transaction. The value is one
|
|
13
35
|
# listed as a valid value, as a symbol.
|
|
14
36
|
#
|
|
@@ -50,6 +72,7 @@ module Minfraud
|
|
|
50
72
|
coregateway
|
|
51
73
|
creditguard
|
|
52
74
|
credorax
|
|
75
|
+
cryptomus
|
|
53
76
|
ct_payments
|
|
54
77
|
cuentadigital
|
|
55
78
|
curopayments
|
|
@@ -146,6 +169,7 @@ module Minfraud
|
|
|
146
169
|
rewardspay
|
|
147
170
|
safecharge
|
|
148
171
|
sagepay
|
|
172
|
+
securepay
|
|
149
173
|
securetrading
|
|
150
174
|
shopify_payments
|
|
151
175
|
simplify_commerce
|
|
@@ -194,6 +218,7 @@ module Minfraud
|
|
|
194
218
|
def initialize(params = {})
|
|
195
219
|
@was_authorized = params[:was_authorized]
|
|
196
220
|
@decline_code = params[:decline_code]
|
|
221
|
+
self.method = params[:method]
|
|
197
222
|
self.processor = params[:processor]
|
|
198
223
|
|
|
199
224
|
validate
|
|
@@ -95,15 +95,15 @@ module Minfraud
|
|
|
95
95
|
validate_uuid('minfraud_id', @minfraud_id)
|
|
96
96
|
|
|
97
97
|
if ip_address.nil? &&
|
|
98
|
-
(minfraud_id.nil? || empty_uuid(minfraud_id)) &&
|
|
98
|
+
(minfraud_id.nil? || empty_uuid?(minfraud_id)) &&
|
|
99
99
|
(maxmind_id.nil? || maxmind_id.empty?) &&
|
|
100
100
|
(transaction_id.nil? || transaction_id.empty?)
|
|
101
101
|
raise ArgumentError, 'At least one of the following is required: ip_address, minfraud_id, maxmind_id, transaction_id.'
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
def empty_uuid(value)
|
|
106
|
-
stripped_value = value.to_s.
|
|
105
|
+
def empty_uuid?(value)
|
|
106
|
+
stripped_value = value.to_s.delete('-')
|
|
107
107
|
stripped_value == '0' * 32
|
|
108
108
|
end
|
|
109
109
|
end
|
|
@@ -17,7 +17,7 @@ module Minfraud
|
|
|
17
17
|
# to an item's field, or as a Minfraud:::Components::ShoppingCartItem
|
|
18
18
|
# object.
|
|
19
19
|
def initialize(params = [])
|
|
20
|
-
@items = params.map(
|
|
20
|
+
@items = params.map { |param| resolve(param) }
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# A JSON representation of Minfraud::Components::ShoppingCart items.
|
data/lib/minfraud/enum.rb
CHANGED
|
@@ -15,7 +15,10 @@ module Minfraud
|
|
|
15
15
|
#
|
|
16
16
|
# @return [Hash]
|
|
17
17
|
def mapping
|
|
18
|
+
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
19
|
+
# This is a false positive - this is set during class definition and then only read
|
|
18
20
|
@mapping ||= {}
|
|
21
|
+
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
# Create a set of methods for enum-like behavior of the attribute.
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'minfraud/model/abstract'
|
|
4
|
+
require 'minfraud/model/email_domain_visit'
|
|
4
5
|
|
|
5
6
|
module Minfraud
|
|
6
7
|
module Model
|
|
7
8
|
# Model containing information about the email domain.
|
|
8
9
|
class EmailDomain < Abstract
|
|
10
|
+
# A classification of the domain. Possible values are:
|
|
11
|
+
# * business
|
|
12
|
+
# * education
|
|
13
|
+
# * government
|
|
14
|
+
# * isp_email
|
|
15
|
+
#
|
|
16
|
+
# @return [String, nil]
|
|
17
|
+
attr_reader :classification
|
|
18
|
+
|
|
9
19
|
# A date string (e.g. 2017-04-24) to identify the date an email domain
|
|
10
20
|
# was first seen by MaxMind. This is expressed using the ISO 8601 date
|
|
11
21
|
# format.
|
|
@@ -13,11 +23,33 @@ module Minfraud
|
|
|
13
23
|
# @return [String, nil]
|
|
14
24
|
attr_reader :first_seen
|
|
15
25
|
|
|
26
|
+
# A risk score ranging from 0.01 to 99. Higher values indicate greater
|
|
27
|
+
# risk.
|
|
28
|
+
#
|
|
29
|
+
# @return [Float, nil]
|
|
30
|
+
attr_reader :risk
|
|
31
|
+
|
|
32
|
+
# An object containing information about an automated visit to the email
|
|
33
|
+
# domain.
|
|
34
|
+
#
|
|
35
|
+
# @return [Minfraud::Model::EmailDomainVisit, nil]
|
|
36
|
+
attr_reader :visit
|
|
37
|
+
|
|
38
|
+
# Activity across the minFraud network expressed as sightings per
|
|
39
|
+
# million. The value ranges from 0.001 to 1,000,000.
|
|
40
|
+
#
|
|
41
|
+
# @return [Float, nil]
|
|
42
|
+
attr_reader :volume
|
|
43
|
+
|
|
16
44
|
# @!visibility private
|
|
17
45
|
def initialize(record)
|
|
18
46
|
super
|
|
19
47
|
|
|
20
|
-
@
|
|
48
|
+
@classification = get('classification')
|
|
49
|
+
@first_seen = get('first_seen')
|
|
50
|
+
@risk = get('risk')
|
|
51
|
+
@visit = EmailDomainVisit.new(get('visit'))
|
|
52
|
+
@volume = get('volume')
|
|
21
53
|
end
|
|
22
54
|
end
|
|
23
55
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'minfraud/model/abstract'
|
|
4
|
+
|
|
5
|
+
module Minfraud
|
|
6
|
+
module Model
|
|
7
|
+
# Model containing information about an automated visit to the email
|
|
8
|
+
# domain.
|
|
9
|
+
class EmailDomainVisit < Abstract
|
|
10
|
+
# Whether the domain redirects to another URL.
|
|
11
|
+
#
|
|
12
|
+
# @return [Boolean, nil]
|
|
13
|
+
attr_reader :has_redirect
|
|
14
|
+
|
|
15
|
+
# A date string (e.g. 2025-11-15) identifying the date the automated
|
|
16
|
+
# visit was completed. This is expressed using the ISO 8601 date format.
|
|
17
|
+
#
|
|
18
|
+
# @return [String, nil]
|
|
19
|
+
attr_reader :last_visited_on
|
|
20
|
+
|
|
21
|
+
# The status of the domain. Possible values are:
|
|
22
|
+
# * live - The domain is operational and serving content.
|
|
23
|
+
# * dns_error - The domain has missing, expired, or misconfigured DNS.
|
|
24
|
+
# * network_error - The domain is offline or unreachable.
|
|
25
|
+
# * http_error - The domain is reachable, but has an application error.
|
|
26
|
+
# * parked - The domain is reachable and in a parked state.
|
|
27
|
+
# * pre_development - The domain is reachable and in a pre-development
|
|
28
|
+
# state.
|
|
29
|
+
#
|
|
30
|
+
# @return [String, nil]
|
|
31
|
+
attr_reader :status
|
|
32
|
+
|
|
33
|
+
# @!visibility private
|
|
34
|
+
def initialize(record)
|
|
35
|
+
super
|
|
36
|
+
|
|
37
|
+
@has_redirect = get('has_redirect')
|
|
38
|
+
@last_visited_on = get('last_visited_on')
|
|
39
|
+
@status = get('status')
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/minfraud/model/phone.rb
CHANGED
|
@@ -21,6 +21,15 @@ module Minfraud
|
|
|
21
21
|
# @return [Boolean, nil]
|
|
22
22
|
attr_reader :is_voip
|
|
23
23
|
|
|
24
|
+
# This property is true if the phone number's prefix is commonly
|
|
25
|
+
# associated with the postal code. It is false if the prefix is not
|
|
26
|
+
# associated with the postal code. It is non-nil only when the phone
|
|
27
|
+
# number is in the US, the number prefix is in our database, and the
|
|
28
|
+
# postal code and country are provided in the request.
|
|
29
|
+
#
|
|
30
|
+
# @return [Boolean, nil]
|
|
31
|
+
attr_reader :matches_postal
|
|
32
|
+
|
|
24
33
|
# The name of the original network operator associated with the phone
|
|
25
34
|
# number. This attribute does not reflect phone numbers that have been
|
|
26
35
|
# ported from the original operator to another, nor does it identify
|
|
@@ -41,6 +50,7 @@ module Minfraud
|
|
|
41
50
|
|
|
42
51
|
@country = get('country')
|
|
43
52
|
@is_voip = get('is_voip')
|
|
53
|
+
@matches_postal = get('matches_postal')
|
|
44
54
|
@network_operator = get('network_operator')
|
|
45
55
|
@number_type = get('number_type')
|
|
46
56
|
end
|
|
@@ -14,9 +14,9 @@ module Minfraud
|
|
|
14
14
|
# @return [Float]
|
|
15
15
|
attr_reader :multiplier
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Reasons for the multiplier.
|
|
18
18
|
#
|
|
19
|
-
# @return [Array<Minfraud::Model::
|
|
19
|
+
# @return [Array<Minfraud::Model::Reason>]
|
|
20
20
|
attr_reader :reasons
|
|
21
21
|
|
|
22
22
|
# @!visibility private
|
data/lib/minfraud/validates.rb
CHANGED
|
@@ -27,7 +27,7 @@ module Minfraud
|
|
|
27
27
|
def validate_uuid(field, value)
|
|
28
28
|
return if !value
|
|
29
29
|
|
|
30
|
-
stripped_value = value.to_s.
|
|
30
|
+
stripped_value = value.to_s.delete('-')
|
|
31
31
|
|
|
32
32
|
# Define a regex pattern for a valid UUID without dashes
|
|
33
33
|
uuid_regex = /\A[0-9a-f]{32}\z/i
|
|
@@ -78,7 +78,7 @@ module Minfraud
|
|
|
78
78
|
raise InvalidInputError, "The #{field} value is not valid. It must contain only non-space printable ASCII characters."
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
if /\A[0-9]{1,19}\z/.match(s)
|
|
81
|
+
if /\A[0-9]{1,19}\z/.match?(s)
|
|
82
82
|
raise InvalidInputError, "The #{field} value is not valid. If it is all digits, it must be longer than 19 characters."
|
|
83
83
|
end
|
|
84
84
|
end
|
|
@@ -147,7 +147,7 @@ module Minfraud
|
|
|
147
147
|
def validate_email(field, value)
|
|
148
148
|
return if !value
|
|
149
149
|
|
|
150
|
-
if /.@./.match(value)
|
|
150
|
+
if /.@./.match?(value)
|
|
151
151
|
validate_string(field, 255, value)
|
|
152
152
|
return
|
|
153
153
|
end
|
data/lib/minfraud/version.rb
CHANGED
data/lib/minfraud.rb
CHANGED
|
@@ -32,6 +32,9 @@ require 'minfraud/report'
|
|
|
32
32
|
# for the gem's classes.
|
|
33
33
|
module Minfraud
|
|
34
34
|
class << self
|
|
35
|
+
# rubocop:disable ThreadSafety/ClassAndModuleAttributes
|
|
36
|
+
# This is a false positive - these configuration attributes are set during initialization
|
|
37
|
+
|
|
35
38
|
# The MaxMind account ID that is used for authorization.
|
|
36
39
|
#
|
|
37
40
|
# @return [Integer, nil]
|
|
@@ -57,6 +60,8 @@ module Minfraud
|
|
|
57
60
|
# @return [String, nil]
|
|
58
61
|
attr_accessor :license_key
|
|
59
62
|
|
|
63
|
+
# rubocop:enable ThreadSafety/ClassAndModuleAttributes
|
|
64
|
+
|
|
60
65
|
# @!visibility private
|
|
61
66
|
attr_reader :connection_pool
|
|
62
67
|
|
|
@@ -67,8 +72,11 @@ module Minfraud
|
|
|
67
72
|
yield self
|
|
68
73
|
|
|
69
74
|
pool_size = 5
|
|
75
|
+
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
76
|
+
# This is a false positive - this configuration is set during initialization
|
|
70
77
|
host = @host.nil? ? 'minfraud.maxmind.com' : @host
|
|
71
78
|
@connection_pool = ConnectionPool.new(size: pool_size) do
|
|
79
|
+
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
72
80
|
make_http_client.persistent("https://#{host}")
|
|
73
81
|
end
|
|
74
82
|
end
|
|
@@ -76,10 +84,13 @@ module Minfraud
|
|
|
76
84
|
private
|
|
77
85
|
|
|
78
86
|
def make_http_client
|
|
87
|
+
# rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
88
|
+
# This is a false positive - this configuration is set during initialization
|
|
79
89
|
HTTP.basic_auth(
|
|
80
90
|
user: @account_id,
|
|
81
91
|
pass: @license_key,
|
|
82
92
|
).headers(
|
|
93
|
+
# rubocop:enable ThreadSafety/ClassInstanceVariable
|
|
83
94
|
accept: 'application/json',
|
|
84
95
|
user_agent: "minfraud-api-ruby/#{Minfraud::VERSION} ruby/#{RUBY_VERSION} http/#{HTTP::VERSION}",
|
|
85
96
|
)
|
data/minfraud.gemspec
CHANGED
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
|
15
15
|
spec.homepage = 'https://github.com/maxmind/minfraud-api-ruby'
|
|
16
16
|
spec.license = 'MIT'
|
|
17
17
|
|
|
18
|
-
spec.required_ruby_version = '>= 3.
|
|
18
|
+
spec.required_ruby_version = '>= 3.2'
|
|
19
19
|
|
|
20
20
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^.gitignore$|^(?:\.github|dev-bin|spec)/}) }
|
|
21
21
|
spec.bindir = 'exe'
|
|
@@ -24,13 +24,17 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
|
|
25
25
|
spec.add_dependency 'connection_pool', '~> 2.2'
|
|
26
26
|
spec.add_dependency 'http', '>= 4.3', '< 6.0'
|
|
27
|
-
spec.add_dependency 'maxmind-geoip2', '~> 1.
|
|
27
|
+
spec.add_dependency 'maxmind-geoip2', '~> 1.4'
|
|
28
28
|
spec.add_dependency 'simpleidn', '~> 0.1', '>= 0.1.1'
|
|
29
29
|
|
|
30
30
|
spec.add_development_dependency 'bundler', '~> 2.2'
|
|
31
31
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
32
32
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
33
33
|
spec.add_development_dependency 'rubocop', '~> 1.23'
|
|
34
|
+
spec.add_development_dependency 'rubocop-performance'
|
|
35
|
+
spec.add_development_dependency 'rubocop-rake'
|
|
36
|
+
spec.add_development_dependency 'rubocop-rspec'
|
|
37
|
+
spec.add_development_dependency 'rubocop-thread_safety'
|
|
34
38
|
spec.add_development_dependency 'webmock', '~> 3.14'
|
|
35
39
|
spec.metadata = {
|
|
36
40
|
'rubygems_mfa_required' => 'true'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minfraud
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kushnir.yb
|
|
8
8
|
- William Storey
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: connection_pool
|
|
@@ -50,14 +50,14 @@ dependencies:
|
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '1.
|
|
53
|
+
version: '1.4'
|
|
54
54
|
type: :runtime
|
|
55
55
|
prerelease: false
|
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
58
|
- - "~>"
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '1.
|
|
60
|
+
version: '1.4'
|
|
61
61
|
- !ruby/object:Gem::Dependency
|
|
62
62
|
name: simpleidn
|
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -134,6 +134,62 @@ dependencies:
|
|
|
134
134
|
- - "~>"
|
|
135
135
|
- !ruby/object:Gem::Version
|
|
136
136
|
version: '1.23'
|
|
137
|
+
- !ruby/object:Gem::Dependency
|
|
138
|
+
name: rubocop-performance
|
|
139
|
+
requirement: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '0'
|
|
144
|
+
type: :development
|
|
145
|
+
prerelease: false
|
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
147
|
+
requirements:
|
|
148
|
+
- - ">="
|
|
149
|
+
- !ruby/object:Gem::Version
|
|
150
|
+
version: '0'
|
|
151
|
+
- !ruby/object:Gem::Dependency
|
|
152
|
+
name: rubocop-rake
|
|
153
|
+
requirement: !ruby/object:Gem::Requirement
|
|
154
|
+
requirements:
|
|
155
|
+
- - ">="
|
|
156
|
+
- !ruby/object:Gem::Version
|
|
157
|
+
version: '0'
|
|
158
|
+
type: :development
|
|
159
|
+
prerelease: false
|
|
160
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
161
|
+
requirements:
|
|
162
|
+
- - ">="
|
|
163
|
+
- !ruby/object:Gem::Version
|
|
164
|
+
version: '0'
|
|
165
|
+
- !ruby/object:Gem::Dependency
|
|
166
|
+
name: rubocop-rspec
|
|
167
|
+
requirement: !ruby/object:Gem::Requirement
|
|
168
|
+
requirements:
|
|
169
|
+
- - ">="
|
|
170
|
+
- !ruby/object:Gem::Version
|
|
171
|
+
version: '0'
|
|
172
|
+
type: :development
|
|
173
|
+
prerelease: false
|
|
174
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
175
|
+
requirements:
|
|
176
|
+
- - ">="
|
|
177
|
+
- !ruby/object:Gem::Version
|
|
178
|
+
version: '0'
|
|
179
|
+
- !ruby/object:Gem::Dependency
|
|
180
|
+
name: rubocop-thread_safety
|
|
181
|
+
requirement: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '0'
|
|
186
|
+
type: :development
|
|
187
|
+
prerelease: false
|
|
188
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
189
|
+
requirements:
|
|
190
|
+
- - ">="
|
|
191
|
+
- !ruby/object:Gem::Version
|
|
192
|
+
version: '0'
|
|
137
193
|
- !ruby/object:Gem::Dependency
|
|
138
194
|
name: webmock
|
|
139
195
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -157,6 +213,7 @@ files:
|
|
|
157
213
|
- ".rspec"
|
|
158
214
|
- ".rubocop.yml"
|
|
159
215
|
- CHANGELOG.md
|
|
216
|
+
- CLAUDE.md
|
|
160
217
|
- CODE_OF_CONDUCT.md
|
|
161
218
|
- Gemfile
|
|
162
219
|
- LICENSE.txt
|
|
@@ -194,6 +251,7 @@ files:
|
|
|
194
251
|
- lib/minfraud/model/disposition.rb
|
|
195
252
|
- lib/minfraud/model/email.rb
|
|
196
253
|
- lib/minfraud/model/email_domain.rb
|
|
254
|
+
- lib/minfraud/model/email_domain_visit.rb
|
|
197
255
|
- lib/minfraud/model/error.rb
|
|
198
256
|
- lib/minfraud/model/factors.rb
|
|
199
257
|
- lib/minfraud/model/geoip2_location.rb
|
|
@@ -226,14 +284,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
226
284
|
requirements:
|
|
227
285
|
- - ">="
|
|
228
286
|
- !ruby/object:Gem::Version
|
|
229
|
-
version: '3.
|
|
287
|
+
version: '3.2'
|
|
230
288
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
231
289
|
requirements:
|
|
232
290
|
- - ">="
|
|
233
291
|
- !ruby/object:Gem::Version
|
|
234
292
|
version: '0'
|
|
235
293
|
requirements: []
|
|
236
|
-
rubygems_version: 3.6.
|
|
294
|
+
rubygems_version: 3.6.9
|
|
237
295
|
specification_version: 4
|
|
238
296
|
summary: Ruby API for the minFraud Score, Insights, Factors, and Report Transactions
|
|
239
297
|
services
|