fix(tz): JWT context stub carries the user's timezone
The middleware's per-request user lookup (ghost-session guard) fetched the full row and discarded it, then built the context stub without a timezone — so every server-side conversion via the context user fell back to UTC no matter what the handlers did. The stub now carries Timezone from that same lookup (fetchLiveUser). Live-verified: progress page renders 02:03 PM for a 14:03 New York instant; an analytics session at 02:00 UTC buckets to 10-12 (10pm NY the previous day) instead of 10-13.
This commit is contained in:
1 parent
1601548e6c
commit
0772f06d25
1 file changed
+13
-2
@@ -118,8 +118,11 @@ func createJWTMiddleware(cfg *Config) echo.MiddlewareFunc {
|
|||||||
// full access until token expiry before this check). A
|
// full access until token expiry before this check). A
|
||||||
// primary-key lookup per request — instant revocation, no TTL
|
// primary-key lookup per request — instant revocation, no TTL
|
||||||
// semantics; the guard also covers the SSR groups that used to
|
// semantics; the guard also covers the SSR groups that used to
|
||||||
// chain ensureUserExistsMiddleware.
|
// chain ensureUserExistsMiddleware. The fetched row also feeds
|
||||||
if !userExists(cfg, userUUID) {
|
// the context stub: the user's timezone must travel with every
|
||||||
|
// request so server-side time rendering converts per-user.
|
||||||
|
liveUser, exists := fetchLiveUser(cfg, userUUID)
|
||||||
|
if !exists {
|
||||||
log.Printf("Ghost session rejected: user %s no longer exists", userIDStr)
|
log.Printf("Ghost session rejected: user %s no longer exists", userIDStr)
|
||||||
c.SetCookie(&http.Cookie{
|
c.SetCookie(&http.Cookie{
|
||||||
Name: "token",
|
Name: "token",
|
||||||
@@ -144,6 +147,7 @@ func createJWTMiddleware(cfg *Config) echo.MiddlewareFunc {
|
|||||||
Email: claims["user_email"].(string),
|
Email: claims["user_email"].(string),
|
||||||
Username: claims["user_username"].(string),
|
Username: claims["user_username"].(string),
|
||||||
Role: claims["user_role"].(string),
|
Role: claims["user_role"].(string),
|
||||||
|
Timezone: liveUser.Timezone,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -172,6 +176,13 @@ func userExists(cfg *Config, id uuid.UUID) bool {
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fetchLiveUser loads the full user row for the JWT stub — the ghost-session
|
||||||
|
// guard and the timezone travel together on this one per-request lookup.
|
||||||
|
func fetchLiveUser(cfg *Config, id uuid.UUID) (database.GetUserRow, bool) {
|
||||||
|
u, err := cfg.Queries.GetUser(context.Background(), uuidToPGType(id))
|
||||||
|
return u, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
// wantsHTML determines if the request expects HTML response
|
// wantsHTML determines if the request expects HTML response
|
||||||
func wantsHTML(header http.Header) bool {
|
func wantsHTML(header http.Header) bool {
|
||||||
// Check Accept header
|
// Check Accept header
|
||||||
|
|||||||
Reference in new issue
Block a user