diff --git a/lib/request.js b/lib/request.js index e5527f7d..6e1314d8 100644 --- a/lib/request.js +++ b/lib/request.js @@ -1,8 +1,7 @@ -import path from 'path'; import requestIp from 'request-ip'; import { browserName, detectOS } from 'detect-browser'; import isLocalhost from 'is-localhost-ip'; -import maxmind from 'maxmind'; +import geoip from 'fast-geoip'; import { DESKTOP_OS, @@ -12,8 +11,6 @@ import { MOBILE_SCREEN_WIDTH, } from './constants'; -let lookup; - export function getIpAddress(req) { // Cloudflare if (req.headers['cf-connecting-ip']) { @@ -51,7 +48,7 @@ export function getDevice(screen, browser, os) { } } -export async function getCountry(req, ip) { +export async function getLocation(req, ip) { // Cloudflare if (req.headers['cf-ipcountry']) { return req.headers['cf-ipcountry']; @@ -62,23 +59,24 @@ export async function getCountry(req, ip) { return; } - // Database lookup - if (!lookup) { - lookup = await maxmind.open(path.resolve('./public/geo/GeoLite2-Country.mmdb')); - } + const result = await geoip.lookup(ip); - const result = lookup.get(ip); - - return result?.country?.iso_code; + return { + country: result?.country, + region: result?.region, + city: result?.city, + }; } export async function getClientInfo(req, { screen }) { const userAgent = req.headers['user-agent']; const ip = getIpAddress(req); - const country = await getCountry(req, ip); + const country = await getLocation(req, ip).country; + const region = await getLocation(req, ip).region; + const city = await getLocation(req, ip).city; const browser = browserName(userAgent); const os = detectOS(userAgent); const device = getDevice(screen, browser, os); - return { userAgent, browser, os, ip, country, device }; + return { userAgent, browser, os, ip, country, device, region, city }; } diff --git a/lib/session.js b/lib/session.js index 3d2fc7bc..9773ee71 100644 --- a/lib/session.js +++ b/lib/session.js @@ -23,7 +23,10 @@ export async function getSession(req) { throw new Error(`Invalid website: ${website_uuid}`); } - const { userAgent, browser, os, ip, country, device } = await getClientInfo(req, payload); + const { userAgent, browser, os, ip, country, device, region, city } = await getClientInfo( + req, + payload, + ); const website = await getWebsiteByUuid(website_uuid); @@ -46,6 +49,8 @@ export async function getSession(req) { language, country, device, + region, + city, }); } diff --git a/package.json b/package.json index 4b560931..0ba41a95 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "build-tracker": "rollup -c rollup.tracker.config.js", "build-db": "npm-run-all copy-db-schema build-db-client", "build-lang": "npm-run-all format-lang compile-lang", - "build-geo": "node scripts/build-geo.js", "build-db-schema": "dotenv prisma introspect", "build-db-client": "dotenv prisma generate", "build-mysql-schema": "dotenv prisma introspect -- --schema=./prisma/schema.mysql.prisma", @@ -72,6 +71,7 @@ "date-fns-tz": "^1.1.4", "detect-browser": "^5.2.0", "dotenv": "^8.2.0", + "fast-geoip": "^1.1.40", "formik": "^2.2.9", "immer": "^9.0.6", "ipaddr.js": "^2.0.1", diff --git a/pages/api/website/[id]/metrics.js b/pages/api/website/[id]/metrics.js index 3e9b9925..4e1c0c93 100644 --- a/pages/api/website/[id]/metrics.js +++ b/pages/api/website/[id]/metrics.js @@ -2,7 +2,7 @@ import { getPageviewMetrics, getSessionMetrics, getWebsiteById } from 'lib/queri import { ok, methodNotAllowed, unauthorized, badRequest } from 'lib/response'; import { allowQuery } from 'lib/auth'; -const sessionColumns = ['browser', 'os', 'device', 'country']; +const sessionColumns = ['browser', 'os', 'device', 'country', 'region', 'city']; const pageviewColumns = ['url', 'referrer']; function getTable(type) { diff --git a/prisma/schema.postgresql.prisma b/prisma/schema.postgresql.prisma index d46e7dc1..a4c652e5 100644 --- a/prisma/schema.postgresql.prisma +++ b/prisma/schema.postgresql.prisma @@ -62,6 +62,8 @@ model session { screen String? @db.VarChar(11) language String? @db.VarChar(35) country String? @db.Char(2) + region String? @db.VarChar(35) + city String? @db.VarChar(100) website website @relation(fields: [website_id], references: [website_id]) event event[] pageview pageview[] diff --git a/scripts/build-geo.js b/scripts/build-geo.js index cc66f941..5cf3a2d3 100644 --- a/scripts/build-geo.js +++ b/scripts/build-geo.js @@ -6,7 +6,7 @@ const zlib = require('zlib'); const tar = require('tar'); let url = - 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/GeoLite2-Country.tar.gz'; + 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/GeoLite2-City.tar.gz'; if (process.env.MAXMIND_LICENSE_KEY) { url =