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:
@@ -119,6 +119,14 @@ PulseHealth/
|
||||
- **Color pickers:** LazyVGrid 5 columns (not HStack — overflow on small screens)
|
||||
- **App icon:** Glassmorphism style, Assets.xcassets/AppIcon.appiconset
|
||||
|
||||
## Security
|
||||
- **Keychain** — все токены (auth, refresh, health JWT, API key) хранятся в iOS Keychain через `KeychainService.swift`, не в UserDefaults
|
||||
- **Health credentials** — email/password для health API хранятся в Keychain, устанавливаются один раз при первом запуске
|
||||
- **API key** — передаётся в `X-API-Key` header, не в URL query parameter
|
||||
- **No force unwraps** — URL создаются через guard/optional binding
|
||||
- **HealthKitService** — помечен `@MainActor` для thread-safe @Published
|
||||
- **Privacy policy** — ссылки в Settings (pulse.digital-home.site/privacy, /terms)
|
||||
|
||||
## Key Design Decisions & Gotchas
|
||||
- **Buttons in ScrollView/List MUST have `.buttonStyle(.plain)`** — otherwise taps get swallowed
|
||||
- **Tracker rows:** Separate tap zones — `.onTapGesture` on text area for edit, `Button` with `.buttonStyle(.plain)` for checkbox
|
||||
|
||||
Reference in New Issue
Block a user