Files
HealthLog/scripts/fetch-geolite2.sh
T
Marc-André Bombeck 50150e35ef feat(geo): bundle GeoLite2-City and add an offline-first lookup path
Rewrites src/lib/geo.ts so lookupIpLocation reads from the bundled
MaxMind GeoLite2-City MMDB first and falls back to the existing
ipwho.is path only for IPs the offline DB cannot resolve. Adds a
sibling lookupIpAsn that returns { asn, carrier } from the
GeoLite2-ASN MMDB so the admin login-overview can grow a carrier
chip alongside the auth-provider chip.

The MMDB files are too large to vendor in git. scripts/fetch-geolite2.sh
downloads them at build time using a MaxMind license key; the
Dockerfile copies assets/geolite2/ into /opt/geolite2/. When the
license key is absent or the files are missing the image still
builds and the resolver falls back to ipwho.is (v1.4.26 behaviour).

GeoLite2 is CC BY-SA 4.0 — attribution lives on the new public
/about page and in docs/audit/v1427-summary.md.
2026-05-15 16:36:55 +02:00

77 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# v1.4.27 B3 — GeoLite2-City + GeoLite2-ASN download helper.
#
# The MMDB files are too large (~80 MB combined) to vendor in git.
# Instead, an operator runs this script before `docker build` so the
# files land at `assets/geolite2/` where the Dockerfile picks them up
# and copies them into `/opt/geolite2/` inside the image.
#
# The MaxMind GeoLite2 databases require a free MaxMind account and
# a licence key. The key is taken from the `MAXMIND_LICENSE_KEY`
# environment variable. Without the key, the script exits 0 and the
# Docker image builds without the offline databases — the runtime
# resolver in `src/lib/geo.ts` falls back to the online `ipwho.is`
# provider, which is the v1.4.26 behaviour.
#
# Licence: the databases are distributed under
# Creative Commons Attribution-ShareAlike 4.0
# (https://creativecommons.org/licenses/by-sa/4.0/). The attribution
# lives in `docs/audit/v1427-summary.md` and on the `/about` page.
#
# Usage:
# MAXMIND_LICENSE_KEY=xxxx ./scripts/fetch-geolite2.sh
#
# Refresh schedule: re-run before each release. The MMDB layout is
# stable; MaxMind reissues the databases on the first Tuesday of each
# month.
set -euo pipefail
OUT_DIR="${GEOLITE2_OUT_DIR:-assets/geolite2}"
LICENSE_KEY="${MAXMIND_LICENSE_KEY:-}"
if [[ -z "$LICENSE_KEY" ]]; then
echo "fetch-geolite2: MAXMIND_LICENSE_KEY is not set — skipping download." >&2
echo "fetch-geolite2: the runtime resolver will fall back to ipwho.is." >&2
exit 0
fi
mkdir -p "$OUT_DIR"
fetch_edition() {
local edition_id="$1"
local mmdb_basename="$2"
local tmp_tarball
tmp_tarball="$(mktemp -t "${edition_id}.tar.gz.XXXXXX")"
echo "fetch-geolite2: downloading $edition_id ..." >&2
curl --silent --show-error --fail --location \
--output "$tmp_tarball" \
"https://download.maxmind.com/app/geoip_download?edition_id=${edition_id}&license_key=${LICENSE_KEY}&suffix=tar.gz"
# The tarball ships under a date-stamped top-level directory
# (`GeoLite2-City_YYYYMMDD/`). Extract the MMDB into a flat layout
# so the Dockerfile COPY uses a stable path.
tar -xzf "$tmp_tarball" -C "$(dirname "$tmp_tarball")"
local extracted
extracted="$(find "$(dirname "$tmp_tarball")" -maxdepth 2 -name "${mmdb_basename}" -print -quit)"
if [[ -z "$extracted" ]]; then
echo "fetch-geolite2: expected ${mmdb_basename} inside the ${edition_id} tarball" >&2
rm -f "$tmp_tarball"
exit 1
fi
mv "$extracted" "$OUT_DIR/$mmdb_basename"
rm -f "$tmp_tarball"
# Clean up the date-stamped extraction directory.
find "$(dirname "$tmp_tarball")" -maxdepth 1 -type d -name "${edition_id}_*" \
-exec rm -rf {} +
local sha
sha="$(shasum -a 256 "$OUT_DIR/$mmdb_basename" | awk '{print $1}')"
echo "fetch-geolite2: $mmdb_basename SHA256 $sha" >&2
}
fetch_edition "GeoLite2-City" "GeoLite2-City.mmdb"
fetch_edition "GeoLite2-ASN" "GeoLite2-ASN.mmdb"
echo "fetch-geolite2: done. Files in $OUT_DIR." >&2