Extract dunite-geoip for the login-location signal (DEV-525) #32
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/DEV-525-dunite-geoip"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
New crate for DEV-525, epic DEV-495. a8n-tools is gaining new-login-location alerts, which bunyip already has (BUNYIP-366). The whole signal is framework- and storage-agnostic, so it lands here rather than as a second copy.
Three pieces
GeoIpService- IP to country against an IP2Location LITE.BIN, the same file the ecosystem already deploys for dmarc-reporter. Lookups are offline: no per-login external call, no client IP handed to a third party.is_non_public_ip- the addresses that can never carry a country.login_location_decision- record silently, do nothing, or alert.Why
is_non_public_ipis the part most worth sharingWithout it, a request arriving with no real client IP (behind a misconfigured proxy, or any request in development) resolves to no country. The next request that does resolve then reads as a country change and mails the user an alert about a login from their own desk. That is subtle enough to be worth owning in one place rather than rediscovering per app.
Similarly,
login_location_decisionkeeps the first attributable login silent. Alerting on it would mail every existing user the moment the feature ships, and an alert nobody can act on trains people to ignore the ones that matter.Error type
GeoIpErroris owned here, notdunite_core::AppError. Returning the shared error type forces every consumer onto onedunite-corerevision - the version cascade DEV-515 hit and backed out of. Consumers convert at the call site.Not here
The user row, the mailer, and the config. This crate never touches a database, never sends mail and never reads an environment variable. A consumer passes the previous country and the current IP and acts on the answer, which is what lets an actix app and an axum one share it.
Tests
10 unit tests. The ones that matter cover the placeholder values IP2Location stores for unknown and reserved ranges (
"-"and blanks): treating one as a country would turn every login from an unlisted range into a location change and an email.Adoption
a8n-tools/saas consumes this in the follow-up PR. bunyip still carries its own copy in
bunyip-domain/src/services/geoip.rsplus the two helpers inservices/auth.rs; swapping it over is a separate ticket rather than something to bundle here.