harden: widget edge cases — expired session, account switch, cache
1. Session expires: widget gets 401 → clears stale cookie from App Group → stops retrying with bad auth → shows cached data until user opens app and re-authenticates 2. Account switch: login() now calls clearWidgetAuth() BEFORE syncCookieToWidget() — clears previous user's cached calories before writing new user's cookie. No brief display of wrong data. 3. Logout: already correct — clearWidgetAuth removes cookie + cached data, widget shows 0/2000 4. Minimum data: only session cookie + 2 cached numbers + timestamp in App Group. No passwords, no user IDs, no PII. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -77,6 +77,7 @@ final class AuthManager {
|
|||||||
currentUser = response.user
|
currentUser = response.user
|
||||||
isLoggedIn = true
|
isLoggedIn = true
|
||||||
UserDefaults.standard.set(true, forKey: loggedInKey)
|
UserDefaults.standard.set(true, forKey: loggedInKey)
|
||||||
|
clearWidgetAuth() // Clear previous user's cached data
|
||||||
syncCookieToWidget()
|
syncCookieToWidget()
|
||||||
WidgetCenter.shared.reloadAllTimelines()
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,8 +116,15 @@ struct CalorieProvider: TimelineProvider {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
let (data, response) = try await URLSession.shared.data(for: request)
|
let (data, response) = try await URLSession.shared.data(for: request)
|
||||||
guard let http = response as? HTTPURLResponse,
|
guard let http = response as? HTTPURLResponse else { return nil }
|
||||||
(200...299).contains(http.statusCode) else { return nil }
|
|
||||||
|
// Session expired — clear stale cookie so we don't retry
|
||||||
|
if http.statusCode == 401 {
|
||||||
|
sharedDefaults.removeObject(forKey: "widget_sessionCookie")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard (200...299).contains(http.statusCode) else { return nil }
|
||||||
return try JSONSerialization.jsonObject(with: data) as? [String: Any]
|
return try JSONSerialization.jsonObject(with: data) as? [String: Any]
|
||||||
} catch {
|
} catch {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user