Skip to content

Commit

Permalink
Add support for Maxmind database file (#6)
Browse files Browse the repository at this point in the history
* Add file-based maxmind IP lookup.

* Add deploy file.

* Fix install and setup for geoipupdate

* Add build arg and target.

* Rename to avoid loop

* Rename to avoid loop

* Rename to avoid loop

* Rename to avoid loop

* Rename to avoid loop

* Try bash

* Try bash

* Try bash

* Add secrets, simplify

* Add secrets, simplify

* Add secrets, simplify

* Add secrets, simplify

* Remove yml config

* Update env and readme.

* Revert "Remove yml config"

This reverts commit db94744.

* Rename

* Update dockerfile.

* Remove trigger yml
  • Loading branch information
pcraciunoiu authored Apr 9, 2024
1 parent 35f5925 commit 2ba1923
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ PG_LOGGING=[custom_value]
SENTRY_DSN_URL=[custom_value]
API_KEY=[custom_value]
APP_URL=[custom_value]
# Geolocation - use web locally
GEO_LOCATION_LOOKUP_TYPE=web
GEO_LOCATION_API_KEY=[custom_value]
GEO_LOCATION_ACCOUNT_ID=[custom_value]
GCS_PROJECT_ID=[custom_value]
Expand Down
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ FROM node:18-alpine As production
RUN addgroup -g 10001 app && \
adduser -u 10001 -G app -s /usr/sbin/nologin -D -h /app app -s /bin/sh

# Install go & geoipupdate
RUN wget https://go.dev/dl/go1.22.2.linux-amd64.tar.gz && \
tar -C /usr/local -xzf go1.22.2.linux-amd64.tar.gz && \
/usr/local/go/bin/go install github.com/maxmind/geoipupdate/v6/cmd/geoipupdate@latest

ARG GEO_LOCATION_ACCOUNT_ID
ARG GEO_LOCATION_API_KEY
RUN mkdir -p /usr/local/etc && touch /usr/local/etc/GeoIP.conf && \
echo "AccountID ${GEO_LOCATION_ACCOUNT_ID}" >> /usr/local/etc/GeoIP.conf && \
echo "LicenseKey ${GEO_LOCATION_API_KEY}" >> /usr/local/etc/GeoIP.conf && \
echo "EditionIDs GeoIP2-Country" >> /usr/local/etc/GeoIP.conf && \
$HOME/go/bin/geoipupdate

# Copy crons
COPY geoipupdate-cron.sh /etc/periodic/weekly/geoipupdate-cron
RUN crond -f -l 8 &

# Copy the bundled code from the build stage to the production image
COPY --chown=node:node --from=build /app/node_modules ./node_modules
COPY --chown=node:node --from=build /app/dist ./dist
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ $ npm run start:dev
$ npm run start:prod
```

### Installing Maxmind

To test file-based GeoIP lookup, you must install the `geoipupdate` package.

Details [here](https://github.com/maxmind/geoipupdate).

## Test

```bash
Expand Down
2 changes: 2 additions & 0 deletions geoipupdate-cron.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
/usr/local/bin/geoipupdate
39 changes: 29 additions & 10 deletions src/geolocation/geo-location.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
import { Injectable, Logger } from '@nestjs/common';

import { WebServiceClient } from '@maxmind/geoip2-node';
import { OpenOpts } from 'maxmind/lib';
import { WebServiceClient, Reader } from '@maxmind/geoip2-node';
import { isIP } from 'net';

const getFileBasedIpAddress = async (ipAddress: string) => {
const options: OpenOpts = {};

const GEO_LOCATION_DATABASE_PATH =
process.env.GEO_LOCATION_DATABASE_PATH ||
'/usr/share/GeoIP/GeoIP2-Country.mmdb';

const reader = await Reader.open(GEO_LOCATION_DATABASE_PATH, options);
return reader.country(ipAddress);
};

const getWebBasedIpAddress = async (ipAddress: string) => {
const client = new WebServiceClient(
process.env.GEO_LOCATION_ACCOUNT_ID,
process.env.GEO_LOCATION_API_KEY,
{ host: 'geolite.info' },
);
return await client.country(ipAddress);
};

const getIpAddress =
(process.env.GEO_LOCATION_LOOKUP_TYPE || 'file') === 'file'
? getFileBasedIpAddress
: getWebBasedIpAddress;

@Injectable()
export class GeolocationService {
private readonly logger = new Logger(GeolocationService.name);
Expand All @@ -15,18 +41,11 @@ export class GeolocationService {
return null;
}

const client = new WebServiceClient(
process.env.GEO_LOCATION_ACCOUNT_ID,
process.env.GEO_LOCATION_API_KEY,
{ host: 'geolite.info' },
);
const userCountry = await client.country(ipAddress);
const userCountry = await getIpAddress(ipAddress);

this.logger.error('The geoip2-node result', JSON.stringify(userCountry));

const isValidCountry =
userCountry.hasOwnProperty('country') &&
userCountry.hasOwnProperty('traits');
const isValidCountry = !!userCountry.country && !!userCountry.traits;

if (!isValidCountry) {
this.logger.error(
Expand Down

0 comments on commit 2ba1923

Please sign in to comment.