mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
feat(admin): resolve the sign-in carrier online + give it its own column
The network operator (carrier) used to resolve only from the optional
offline GeoLite2-ASN database. On a host without it the carrier stayed
empty even though the location resolved fine online.
Mine the operator from the same online provider response the location
lookup already fetches — ip-api's top-level `isp`/`org`/`as`, ipwho.is's
nested `connection.{isp,org,asn}` — so the carrier is populated out of the
box. The offline ASN database stays authoritative when configured.
A single `lookupIpGeo` now returns location + ASN + carrier in one pass;
the audit write and the backfill both go through it. The backfill also
revisits rows that already had a location but no carrier, so the column
fills in across existing history, not just for new sign-ins.
In the admin sign-in overview the carrier moves out of a chip stacked
under the login method into its own column, next to the location.
This commit is contained in:
1 parent
c14d760654
commit
bdac5b2c0d
17 files changed
+439
-200
No files matched your search
@@ -7,6 +7,7 @@ import {
|
||||
Download,
|
||||
Loader2,
|
||||
MapPin,
|
||||
Network,
|
||||
ScrollText,
|
||||
XCircle,
|
||||
} from "lucide-react";
|
||||
@@ -409,6 +410,18 @@ export function LoginOverviewSection() {
|
||||
{t("admin.location")}
|
||||
</span>
|
||||
</th>
|
||||
{/*
|
||||
v1.25.8 — the network operator (carrier) is now its own
|
||||
column instead of a chip stacked under the auth-provider.
|
||||
It resolves from the online geo provider's ISP field, so
|
||||
it's populated even without the optional offline ASN MMDB.
|
||||
*/}
|
||||
<th className="px-3 py-2 text-left font-medium">
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<Network className="h-3 w-3" aria-hidden="true" />
|
||||
{t("admin.carrier")}
|
||||
</span>
|
||||
</th>
|
||||
<th className="px-3 py-2 text-right font-medium">
|
||||
{t("admin.timestamp")}
|
||||
</th>
|
||||
@@ -449,38 +462,6 @@ export function LoginOverviewSection() {
|
||||
/>
|
||||
{AUTH_PROVIDER_LABELS[provider]}
|
||||
</span>
|
||||
{/*
|
||||
v1.4.27 B3 — carrier chip below the auth-provider
|
||||
chip. v1.4.36 W4g — fall back to the city + country
|
||||
string with a "carrier unavailable" qualifier when
|
||||
the GeoLite2-ASN offline lookup miss (free-tier
|
||||
ipwho.is does not expose ASN) leaves `entry.carrier`
|
||||
null but the location lookup populated
|
||||
`entry.location`. Private/loopback IPs and offline-
|
||||
miss rows on BOTH columns keep the original
|
||||
single-chip layout. ASN-known chip carries the
|
||||
short DACH label ("Telekom", "Vodafone", "1&1",
|
||||
"O2") with unknown organisations falling through
|
||||
to the raw GeoLite2 string.
|
||||
*/}
|
||||
{entry.carrier ? (
|
||||
<span
|
||||
className="text-muted-foreground/80 mt-0.5 block text-[10px] leading-tight"
|
||||
data-slot="login-overview-carrier"
|
||||
>
|
||||
{carrierShortLabel(entry.carrier)}
|
||||
</span>
|
||||
) : entry.location ? (
|
||||
<span
|
||||
className="text-muted-foreground/80 mt-0.5 block text-[10px] leading-tight"
|
||||
data-slot="login-overview-carrier"
|
||||
data-source="geo-fallback"
|
||||
>
|
||||
{t("admin.carrierUnavailableGeoFallback", {
|
||||
location: entry.location,
|
||||
})}
|
||||
</span>
|
||||
) : null}
|
||||
</td>
|
||||
<td className="text-muted-foreground px-3 py-2 font-mono text-xs">
|
||||
{entry.ipAddress ?? "—"}
|
||||
@@ -488,6 +469,20 @@ export function LoginOverviewSection() {
|
||||
<td className="text-muted-foreground px-3 py-2 text-xs">
|
||||
{entry.location ?? "—"}
|
||||
</td>
|
||||
{/*
|
||||
v1.25.8 — carrier / network operator in its own
|
||||
column. Known DACH operators fold to a short label
|
||||
("Telekom", "Vodafone", "1&1", "O2"); unknown ones
|
||||
show the raw operator string the provider returned.
|
||||
*/}
|
||||
<td
|
||||
className="text-muted-foreground px-3 py-2 text-xs"
|
||||
data-slot="login-overview-carrier"
|
||||
>
|
||||
{entry.carrier
|
||||
? carrierShortLabel(entry.carrier)
|
||||
: "—"}
|
||||
</td>
|
||||
<td className="text-muted-foreground px-3 py-2 text-right text-xs whitespace-nowrap">
|
||||
{formatDateTime(entry.createdAt)}
|
||||
</td>
|
||||
|
||||
Reference in new issue
Block a user