feat: stamp users.last_seen on login and token refresh
One conditional UPDATE writes it at most once per five minutes per user. A failed write is logged and never fails authentication, and no user payload carries the column.
This commit is contained in:
@@ -108,6 +108,10 @@ func Login(app *backpack.App) http.HandlerFunc {
|
||||
_ = gdb.WithContext(ctx).Model(user).Update("password", next).Error
|
||||
}
|
||||
}
|
||||
// A failed last_seen write is logged and never fails the login.
|
||||
if err := classes.TouchLastSeen(ctx, gdb, user.ID); err != nil {
|
||||
slog.Default().Warn("golem15.user: stamp last_seen on login", "user_id", user.ID, "err", err)
|
||||
}
|
||||
token, err := mintFor(app, secret, user, requestURL(r))
|
||||
if err != nil {
|
||||
writeOpaque500(w)
|
||||
@@ -174,7 +178,7 @@ func Fetch(app *backpack.App) http.HandlerFunc {
|
||||
// Refresh slides a still-refreshable bearer token.
|
||||
func Refresh(app *backpack.App) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
_, secret, ok := sessionDeps(w, app)
|
||||
gdb, secret, ok := sessionDeps(w, app)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
@@ -195,6 +199,15 @@ func Refresh(app *backpack.App) http.HandlerFunc {
|
||||
})
|
||||
return
|
||||
}
|
||||
// The refresh never loads the user row: the subject comes from the
|
||||
// new token. A failed last_seen write is logged and never fails it.
|
||||
if sub, _, _, _, err := bouncer.VerifyClaims(next, secret); err == nil {
|
||||
if id, err := strconv.ParseUint(sub, 10, 64); err == nil && id != 0 {
|
||||
if err := classes.TouchLastSeen(r.Context(), gdb, uint(id)); err != nil {
|
||||
slog.Default().Warn("golem15.user: stamp last_seen on refresh", "user_id", id, "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"token": next})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user