package middlewares import ( "strconv" "doormile/db" "doormile/models" "doormile/utils" "github.com/gofiber/fiber/v2" ) // LegacyMilerIdentity resolves a rider identity for machine-to-machine ingest // and puts it in c.Locals("userid"), which is exactly where the normal miler // handlers read it from. That is the whole point: the ingest routes reuse the // existing handlers unchanged rather than growing a parallel set with their own // (inevitably drifting) validation. // // It must be mounted *behind* InternalKeyAuth. On its own it is not // authentication — it names a rider, it does not prove anything about the // caller. The X-Internal-Key check is what makes that safe, and it is the reason // this cannot be reached from the public internet. // // Two headers, checked in order: // // X-Miler-Userid a Doormile userid, used directly // X-Legacy-Userid a jupiter/Nearle userid, resolved via MilerProfile.Legacyuserid // // The identity deliberately does NOT come from the request body. The miler // telemetry handlers overwrite any body-supplied userid with the token's, which // is what stops one rider writing another's GPS trail; taking it from the body // here would reopen that hole from behind the internal key. A header keeps the // rule intact and works for POST /consignments/logs, whose body is a bare JSON // array with nowhere to put an id anyway. func LegacyMilerIdentity(c *fiber.Ctx) error { if raw := c.Get("X-Miler-Userid"); raw != "" { userID, err := strconv.Atoi(raw) if err != nil || userID <= 0 { return utils.BadRequest(c, "invalid X-Miler-Userid") } var count int64 if err := db.DB.Model(&models.MilerProfile{}). Where("userid = ?", userID).Count(&count).Error; err != nil { return utils.Internal(c, "failed to resolve miler") } if count == 0 { return utils.NotFound(c, "no miler with that userid") } c.Locals("userid", userID) return c.Next() } raw := c.Get("X-Legacy-Userid") if raw == "" { return utils.BadRequest(c, "X-Miler-Userid or X-Legacy-Userid header is required") } legacyID, err := strconv.Atoi(raw) if err != nil || legacyID <= 0 { return utils.BadRequest(c, "invalid X-Legacy-Userid") } var profile models.MilerProfile if err := db.DB.Where("legacyuserid = ?", legacyID).First(&profile).Error; err != nil { // Unmapped is the expected case for every rider who was never migrated // from jupiter, so this is a routine 404 rather than an error condition. // The forwarder treats it as "drop, do not retry" — retrying cannot // invent a mapping, and NAK-looping on it would wedge the consumer. return utils.NotFound(c, "no Doormile miler mapped to that legacy userid") } c.Locals("userid", profile.Userid) return c.Next() }