fix: security hardening — Keychain, no hardcoded creds, safe URLs
- Add KeychainService for encrypted token storage (auth, refresh, health JWT, API key) - Remove hardcoded email/password from HealthAPIService, store in Keychain - Move all tokens from UserDefaults to Keychain - API key sent via X-API-Key header instead of URL query parameter - Replace force unwrap URL(string:)! with guard let + throws - Fix force unwrap Calendar.date() in HealthKitService - Mark HealthKitService @MainActor for thread-safe @Published - Use withTaskGroup for parallel habit log fetching in TrackerView - Check notification permission before scheduling reminders - Add input validation (title max 200 chars) - Add privacy policy and terms links in Settings - Update CLAUDE.md with security section Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -127,12 +127,22 @@ struct HabitListView: View {
|
||||
func loadHabits(refresh: Bool = false) async {
|
||||
if !refresh { isLoading = true }
|
||||
var loaded = (try? await APIService.shared.getHabits(token: authManager.token, includeArchived: true)) ?? []
|
||||
// Enrich with completedToday
|
||||
let today = todayStr()
|
||||
for i in loaded.indices where loaded[i].isArchived != true {
|
||||
let logs = (try? await APIService.shared.getHabitLogs(token: authManager.token, habitId: loaded[i].id, days: 1)) ?? []
|
||||
loaded[i].completedToday = logs.contains { $0.dateOnly == today }
|
||||
// Fetch all logs in parallel, then update array
|
||||
let activeIndices = loaded.indices.filter { loaded[$0].isArchived != true }
|
||||
let logResults = await withTaskGroup(of: (Int, Bool).self) { group in
|
||||
for i in activeIndices {
|
||||
let habitId = loaded[i].id
|
||||
group.addTask {
|
||||
let logs = (try? await APIService.shared.getHabitLogs(token: self.authManager.token, habitId: habitId, days: 1)) ?? []
|
||||
return (i, logs.contains { $0.dateOnly == today })
|
||||
}
|
||||
}
|
||||
var results: [(Int, Bool)] = []
|
||||
for await result in group { results.append(result) }
|
||||
return results
|
||||
}
|
||||
for (i, completed) in logResults { loaded[i].completedToday = completed }
|
||||
habits = loaded
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user