Skip to content

Commit d0e5db8

Browse files
oschwaldclaude
andcommitted
Add anonymizer property to IpAddress model
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c1bec0b commit d0e5db8

5 files changed

Lines changed: 99 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ CHANGELOG
44
4.1.0
55
------------------
66

7+
* Added `anonymizer` property to `IpAddress` response model. This contains
8+
information about whether the IP address is an anonymous network, including
9+
confidence score, VPN provider name, and various anonymizer flags.
710
* Added `BANQUEST`, `SUMMIT_PAYMENTS`, and `YAADPAY` to the
811
`Payment.Processor` enum.
912

src/main/java/com/maxmind/minfraud/response/IpAddress.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.maxmind.minfraud.response;
22

33
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.maxmind.geoip2.record.Anonymizer;
45
import com.maxmind.geoip2.record.City;
56
import com.maxmind.geoip2.record.Continent;
67
import com.maxmind.geoip2.record.Country;
@@ -14,6 +15,8 @@
1415
/**
1516
* This class contains minFraud response data related to the IP location.
1617
*
18+
* @param anonymizer Anonymizer record for the requested IP address. This contains
19+
* information about whether the IP address is an anonymous network.
1720
* @param city City record for the requested IP address.
1821
* @param continent Continent record for the requested IP address.
1922
* @param country Country record for the requested IP address.
@@ -29,6 +32,8 @@
2932
* @param traits Traits record for the requested IP address.
3033
*/
3134
public record IpAddress(
35+
@JsonProperty("anonymizer")
36+
Anonymizer anonymizer,
3237
@JsonProperty("city")
3338
City city,
3439

@@ -67,6 +72,7 @@ public record IpAddress(
6772
* Compact canonical constructor that sets defaults for null values.
6873
*/
6974
public IpAddress {
75+
anonymizer = anonymizer != null ? anonymizer : new Anonymizer();
7076
location = location != null ? location : new GeoIp2Location();
7177
riskReasons = riskReasons != null ? List.copyOf(riskReasons) : List.of();
7278
subdivisions = subdivisions != null ? List.copyOf(subdivisions) : List.of();
@@ -77,7 +83,42 @@ public record IpAddress(
7783
*/
7884
public IpAddress() {
7985
this(null, null, null, null, null, null,
80-
null, null, null, null, null);
86+
null, null, null, null, null, null);
87+
}
88+
89+
/**
90+
* Constructs an instance of {@code IpAddress}.
91+
*
92+
* @param city City record for the requested IP address.
93+
* @param continent Continent record for the requested IP address.
94+
* @param country Country record for the requested IP address.
95+
* @param location Location record for the requested IP address.
96+
* @param postal Postal record for the requested IP address.
97+
* @param registeredCountry Registered country record for the requested IP address.
98+
* @param representedCountry Represented country record for the requested IP address.
99+
* @param risk The risk associated with the IP address.
100+
* @param riskReasons List of risk reason objects.
101+
* @param subdivisions List of subdivision records for the requested IP address.
102+
* @param traits Traits record for the requested IP address.
103+
* @deprecated Use the canonical constructor instead. This constructor will be removed in 5.0.0.
104+
*/
105+
@Deprecated(since = "4.1.0", forRemoval = true)
106+
public IpAddress(
107+
City city,
108+
Continent continent,
109+
Country country,
110+
GeoIp2Location location,
111+
Postal postal,
112+
Country registeredCountry,
113+
RepresentedCountry representedCountry,
114+
Double risk,
115+
List<IpRiskReason> riskReasons,
116+
List<Subdivision> subdivisions,
117+
Traits traits
118+
) {
119+
this(null, city, continent, country, location, postal,
120+
registeredCountry, representedCountry, risk, riskReasons,
121+
subdivisions, traits);
81122
}
82123

83124
/**

src/test/java/com/maxmind/minfraud/response/InsightsResponseTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertNotNull;
56
import static org.junit.jupiter.api.Assertions.assertTrue;
67

78
import com.fasterxml.jackson.jr.ob.JSON;
@@ -28,6 +29,17 @@ public void testInsights() throws Exception {
2829
.end()
2930
.end()
3031
.startObjectField("ip_address")
32+
.startObjectField("anonymizer")
33+
.put("confidence", 99)
34+
.put("is_anonymous", true)
35+
.put("is_anonymous_vpn", true)
36+
.put("is_hosting_provider", true)
37+
.put("is_public_proxy", true)
38+
.put("is_residential_proxy", true)
39+
.put("is_tor_exit_node", true)
40+
.put("network_last_seen", "2025-01-15")
41+
.put("provider_name", "TestVPN")
42+
.end()
3143
.startObjectField("country")
3244
.put("iso_code", "US")
3345
.end()
@@ -120,5 +132,25 @@ public void testInsights() throws Exception {
120132
);
121133
assertEquals("152.216.7.110", insights.ipAddress().traits().ipAddress().getHostAddress());
122134
assertEquals("81.2.69.0/24", insights.ipAddress().traits().network().toString());
135+
136+
// Test anonymizer
137+
assertNotNull(insights.ipAddress().anonymizer(), "anonymizer should not be null");
138+
assertEquals(
139+
Integer.valueOf(99),
140+
insights.ipAddress().anonymizer().confidence(),
141+
"correct anonymizer confidence"
142+
);
143+
assertTrue(insights.ipAddress().anonymizer().isAnonymous(), "correct isAnonymous");
144+
assertTrue(insights.ipAddress().anonymizer().isAnonymousVpn(), "correct isAnonymousVpn");
145+
assertTrue(insights.ipAddress().anonymizer().isHostingProvider(), "correct isHostingProvider");
146+
assertTrue(insights.ipAddress().anonymizer().isPublicProxy(), "correct isPublicProxy");
147+
assertTrue(insights.ipAddress().anonymizer().isResidentialProxy(), "correct isResidentialProxy");
148+
assertTrue(insights.ipAddress().anonymizer().isTorExitNode(), "correct isTorExitNode");
149+
assertEquals(
150+
LocalDate.parse("2025-01-15"),
151+
insights.ipAddress().anonymizer().networkLastSeen(),
152+
"correct networkLastSeen"
153+
);
154+
assertEquals("TestVPN", insights.ipAddress().anonymizer().providerName(), "correct providerName");
123155
}
124156
}

src/test/resources/test-data/factors-response.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@
1515
"reason": "Suspicious activity has been seen on this IP address across minFraud customers."
1616
}
1717
],
18+
"anonymizer": {
19+
"confidence": 99,
20+
"is_anonymous": true,
21+
"is_anonymous_vpn": true,
22+
"is_hosting_provider": true,
23+
"is_public_proxy": true,
24+
"is_residential_proxy": true,
25+
"is_tor_exit_node": true,
26+
"network_last_seen": "2025-01-15",
27+
"provider_name": "TestVPN"
28+
},
1829
"city": {
1930
"confidence": 42,
2031
"geoname_id": 2643743,

src/test/resources/test-data/insights-response.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@
1515
"reason": "Suspicious activity has been seen on this IP address across minFraud customers."
1616
}
1717
],
18+
"anonymizer": {
19+
"confidence": 99,
20+
"is_anonymous": true,
21+
"is_anonymous_vpn": true,
22+
"is_hosting_provider": true,
23+
"is_public_proxy": true,
24+
"is_residential_proxy": true,
25+
"is_tor_exit_node": true,
26+
"network_last_seen": "2025-01-15",
27+
"provider_name": "TestVPN"
28+
},
1829
"city": {
1930
"confidence": 42,
2031
"geoname_id": 2643743,

0 commit comments

Comments
 (0)