Skip to content

Commit 8d28546

Browse files
authored
Merge pull request #1481 from maxmind/greg/eng-1814
Add support for Anonymous Plus database
2 parents 1f88de9 + d3293d9 commit 8d28546

File tree

7 files changed

+119
-45
lines changed

7 files changed

+119
-45
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
CHANGELOG
22
=========
33

4+
6.1.0
5+
------------------
6+
7+
* Support for the GeoIP Anonymous Plus database has been added. To do a
8+
lookup in this database, use the `anonymousPlus` method on the
9+
database reader.
10+
411
6.0.0 (2025-02-18)
512
------------------
613

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,29 @@ Reader.open('/usr/local/share/GeoIP/GeoIP2-Anonymous-IP.mmdb').then(reader => {
205205
});
206206
```
207207

208+
### Anonymous Plus Database Example
209+
210+
```js
211+
const Reader = require('@maxmind/geoip2-node').Reader;
212+
// Typescript:
213+
// import { Reader } from '@maxmind/geoip2-node';
214+
215+
Reader.open('/usr/local/share/GeoIP/GeoIP-Anonymous-Plus.mmdb').then(reader => {
216+
const response = reader.anonymousPlus('85.25.43.84');
217+
218+
console.log(response.anonymizerConfidence); // 30
219+
console.log(response.isAnonymous); // true
220+
console.log(response.isAnonymousVpn); // false
221+
console.log(response.isHostingProvider); // true
222+
console.log(response.isPublicProxy); // false
223+
console.log(response.isResidentialProxy); // false
224+
console.log(response.isTorExitNode); // false
225+
console.log(response.ipAddress); // '85.25.43.84'
226+
console.log(response.networkLastSeen); // '2025-04-14'
227+
console.log(response.providerName); // 'FooBar VPN'
228+
});
229+
```
230+
208231
### ASN Example
209232

210233
```js

src/models/AnonymousPlus.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as mmdb from 'maxmind';
2+
import AnonymousIP from './AnonymousIP';
3+
4+
/** Class representing the model of an "AnonymousPlus" response **/
5+
export default class AnonymousPlus extends AnonymousIP {
6+
/**
7+
* A score ranging from 1 to 99 that is our percent confidence that the
8+
* network is currently part of an actively used VPN service.
9+
*/
10+
public anonymizerConfidence?: number;
11+
/**
12+
* The last day that the network was sighted in our analysis of anonymized
13+
* networks. This is in the ISO 8601 date format, e.g., "2025-04-21".
14+
*/
15+
public networkLastSeen?: string;
16+
/**
17+
* The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated
18+
* with the network.
19+
*/
20+
public providerName?: string;
21+
22+
/**
23+
* Instantiates an "AnonymousPlus" using fields from the response
24+
*
25+
* @param response The GeoIP2 response
26+
*/
27+
public constructor(
28+
response: mmdb.AnonymousPlusResponse,
29+
ipAddress?: string,
30+
network?: string
31+
) {
32+
super(response, ipAddress, network);
33+
34+
this.anonymizerConfidence = response.anonymizer_confidence;
35+
this.networkLastSeen = response.network_last_seen;
36+
this.providerName = response.provider_name;
37+
}
38+
}

src/models/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import AnonymousIP from './AnonymousIP';
2+
import AnonymousPlus from './AnonymousPlus';
23
import Asn from './Asn';
34
import City from './City';
45
import ConnectionType from './ConnectionType';
@@ -10,6 +11,7 @@ import Isp from './Isp';
1011

1112
export {
1213
AnonymousIP,
14+
AnonymousPlus,
1315
Asn,
1416
City,
1517
ConnectionType,

src/readerModel.spec.ts

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -113,49 +113,6 @@ describe('ReaderModel', () => {
113113
expect(cityModel).toEqual(expected);
114114
});
115115

116-
it('returns data when record only contains city record', async () => {
117-
expect.assertions(1);
118-
119-
const reader = await Reader.open(
120-
'./test/data/test-data/GeoIP2-City-Test.mmdb'
121-
);
122-
123-
const model = reader.city('2.2.3.1');
124-
125-
const expected = {
126-
city: {
127-
geonameId: 2655045,
128-
names: {
129-
en: 'Boxford',
130-
},
131-
},
132-
continent: undefined,
133-
country: undefined,
134-
location: undefined,
135-
maxmind: undefined,
136-
postal: undefined,
137-
registeredCountry: undefined,
138-
representedCountry: undefined,
139-
subdivisions: undefined,
140-
traits: {
141-
ipAddress: '2.2.3.1',
142-
isAnonymous: false,
143-
isAnonymousProxy: false,
144-
isAnonymousVpn: false,
145-
isAnycast: false,
146-
isHostingProvider: false,
147-
isLegitimateProxy: false,
148-
isPublicProxy: false,
149-
isResidentialProxy: false,
150-
isSatelliteProvider: false,
151-
isTorExitNode: false,
152-
network: '2.2.3.0/24',
153-
},
154-
};
155-
156-
expect(model).toEqual(expected);
157-
});
158-
159116
it('returns data when record only contains continent record', async () => {
160117
expect.assertions(1);
161118

@@ -500,6 +457,34 @@ describe('ReaderModel', () => {
500457
});
501458
});
502459

460+
describe('anonymousPlus()', () => {
461+
it('returns anonymousPlus data', async () => {
462+
expect.assertions(1);
463+
464+
const reader = await Reader.open(
465+
'./test/data/test-data/GeoIP-Anonymous-Plus-Test.mmdb'
466+
);
467+
468+
const model = reader.anonymousPlus('1.2.0.1');
469+
470+
const expected = {
471+
anonymizerConfidence: 30,
472+
ipAddress: '1.2.0.1',
473+
isAnonymous: true,
474+
isAnonymousVpn: true,
475+
isHostingProvider: false,
476+
isPublicProxy: false,
477+
isResidentialProxy: false,
478+
isTorExitNode: false,
479+
network: '1.2.0.1/32',
480+
networkLastSeen: '2025-04-14',
481+
providerName: 'foo',
482+
};
483+
484+
expect(model).toEqual(expected);
485+
});
486+
});
487+
503488
describe('asn()', () => {
504489
it('returns asn data', async () => {
505490
expect.assertions(1);
@@ -690,6 +675,7 @@ describe('ReaderModel', () => {
690675
},
691676
},
692677
{
678+
confidence: 60,
693679
geonameId: 3333217,
694680
isoCode: 'WBK',
695681
names: {

src/readerModel.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class ReaderModel {
1919
}
2020

2121
/**
22-
* Returns the AnonymousIP db data for an IP address
22+
* Returns the Anonymous IP db data for an IP address
2323
*
2424
* @param ipAddress The IP Address you want to query the Anonymous IP db with
2525
*
@@ -36,6 +36,24 @@ export default class ReaderModel {
3636
);
3737
}
3838

39+
/**
40+
* Returns the Anonymous Plus db data for an IP address
41+
*
42+
* @param ipAddress The IP Address you want to query the Anonymous Plus db with
43+
*
44+
* @throws {BadMethodCallError} Throws an error when the DB doesn't support Anonymous Plus queries
45+
* @throws {AddressNotFoundError} Throws an error when the IP address isn't found in the database
46+
* @throws {ValueError} Throws an error when the IP address isn't valid
47+
*/
48+
public anonymousPlus(ipAddress: string): models.AnonymousPlus {
49+
return this.modelFor(
50+
models.AnonymousPlus,
51+
'GeoIP-Anonymous-Plus',
52+
ipAddress,
53+
'anonymousPlus()'
54+
);
55+
}
56+
3957
/**
4058
* Returns the City db data for an IP address
4159
*

test/data

Submodule data updated 57 files

0 commit comments

Comments
 (0)