diff --git a/mmdb/GeoLite2-City.mmdb b/mmdb/GeoLite2-City.mmdb new file mode 100644 index 000000000..28cad7d58 Binary files /dev/null and b/mmdb/GeoLite2-City.mmdb differ diff --git a/package.json b/package.json index be8c27d80..374c3c414 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,6 @@ "bytebuffer": "^5.0.1", "classnames": "2.2.5", "config": "1.28.1", - "country-code-lookup": "^0.0.19", "curve25519-js": "https://github.com/oxen-io/curve25519-js", "date-fns": "^3.3.1", "dompurify": "^2.0.7", @@ -92,15 +91,16 @@ "emoji-mart": "^5.5.2", "filesize": "3.6.1", "firstline": "1.2.1", + "fs": "^0.0.1-security", "fs-extra": "9.0.0", "glob": "7.1.2", "image-type": "^4.1.0", - "ip2country": "1.0.1", "libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.3.1/libsession_util_nodejs-v0.3.1.tar.gz", "libsodium-wrappers-sumo": "^0.7.9", "linkify-it": "^4.0.1", "lodash": "^4.17.21", "long": "^4.0.0", + "maxmind": "^4.3.6", "mic-recorder-to-mp3": "^2.2.2", "moment": "^2.29.4", "node-fetch": "^2.6.7", @@ -351,6 +351,9 @@ "!node_modules/libsession_util_nodejs/src/*", "ts/webworker/workers/node/libsession/*.node", "!dev-app-update.yml" + ], + "extraFiles": [ + "mmdb/GeoLite2-City.mmdb" ] } } diff --git a/ts/components/dialog/OnionStatusPathDialog.tsx b/ts/components/dialog/OnionStatusPathDialog.tsx index 3d5917922..b19d338ae 100644 --- a/ts/components/dialog/OnionStatusPathDialog.tsx +++ b/ts/components/dialog/OnionStatusPathDialog.tsx @@ -5,8 +5,9 @@ import { useDispatch, useSelector } from 'react-redux'; import useHover from 'react-use/lib/useHover'; import styled from 'styled-components'; -import countryLookup from 'country-code-lookup'; -import ip2country from 'ip2country'; +import { CityResponse, Reader } from 'maxmind'; +import { readFileSync } from 'fs'; +import path from 'path'; import { Snode } from '../../data/data'; import { onionPathModal } from '../../state/ducks/modalDialog'; import { @@ -95,6 +96,15 @@ const OnionPathModalInner = () => { }, ]; + // Ensure we can always find the GeoLite2 database, regardless of whether + // this is a dev or a prod build. + const binPath = (process.env.NODE_APP_INSTANCE || '').startsWith('devprod') + ? path.resolve(`${__dirname}/../../..`) + : path.resolve(`${process.resourcesPath}/..`); + const buffer = readFileSync(`${binPath}/mmdb/GeoLite2-City.mmdb`); + const reader = new Reader(buffer); + const lang = 'en'; + return ( <> @@ -118,10 +128,23 @@ const OnionPathModalInner = () => { - {nodes.map((snode: Snode | any) => { + {nodes.map((snode: Snode | any, index: number) => { + const geoLookup = reader.get(snode.ip || '0.0.0.0'); + const cityName = geoLookup?.city?.names[lang]; + const countryName = geoLookup?.country?.names[lang]; + //const isoCode = geoLookup?.country?.iso_code; + + // If the city is unknown, or the city and country are identical + // (e.g. Luxembourg or Singapore), use just the country. + const cityCountry = cityName + ? cityName === countryName + ? countryName + : `${cityName}, ${countryName}` + : countryName + let labelText = snode.label ? snode.label - : countryLookup.byIso(ip2country(snode.ip))?.country; + : cityCountry if (!labelText) { labelText = window.i18n('unknownCountry'); }