fix: remove Keychain accessGroup — fixes auth reset and health data

- Remove kSecAttrAccessGroup from KeychainService (requires entitlement
  that keeps getting stripped by Xcode)
- Basic Keychain works without accessGroup for the main app
- Fix health credentials migration check — use KeychainService.load directly
- Tokens now persist correctly between app launches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 14:29:52 +03:00
parent 4ada3201b5
commit 0c21a14cb9
3 changed files with 8 additions and 15 deletions

View File

@@ -39,11 +39,12 @@ struct PulseApp: App {
.environmentObject(authManager) .environmentObject(authManager)
.onAppear { .onAppear {
APIService.shared.authManager = authManager APIService.shared.authManager = authManager
// Migrate: set health API key in Keychain if not yet // Ensure health credentials are in Keychain
if authManager.healthApiKey.isEmpty { if KeychainService.load(key: KeychainService.healthApiKeyKey) == nil {
authManager.setHealthApiKey("health-cosmo-2026") KeychainService.save(key: KeychainService.healthApiKeyKey, value: "health-cosmo-2026")
HealthAPIService.configureCredentials(email: "daniilklimov25@gmail.com", password: "cosmo-health-2026") HealthAPIService.configureCredentials(email: "daniilklimov25@gmail.com", password: "cosmo-health-2026")
} }
authManager.healthApiKey = KeychainService.load(key: KeychainService.healthApiKeyKey) ?? ""
Self.scheduleHealthSync() Self.scheduleHealthSync()
} }
} }

View File

@@ -3,15 +3,13 @@ import Security
enum KeychainService { enum KeychainService {
static let service = "com.daniil.pulsehealth" static let service = "com.daniil.pulsehealth"
static let accessGroup = "V9AG8JTFLC.com.daniil.pulsehealth.shared"
static func save(key: String, value: String) { static func save(key: String, value: String) {
guard let data = value.data(using: .utf8) else { return } guard let data = value.data(using: .utf8) else { return }
let query: [String: Any] = [ let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword, kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service, kSecAttrService as String: service,
kSecAttrAccount as String: key, kSecAttrAccount as String: key
kSecAttrAccessGroup as String: accessGroup
] ]
SecItemDelete(query as CFDictionary) SecItemDelete(query as CFDictionary)
var add = query var add = query
@@ -25,7 +23,6 @@ enum KeychainService {
kSecClass as String: kSecClassGenericPassword, kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service, kSecAttrService as String: service,
kSecAttrAccount as String: key, kSecAttrAccount as String: key,
kSecAttrAccessGroup as String: accessGroup,
kSecReturnData as String: true, kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne kSecMatchLimit as String: kSecMatchLimitOne
] ]
@@ -39,8 +36,7 @@ enum KeychainService {
let query: [String: Any] = [ let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword, kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service, kSecAttrService as String: service,
kSecAttrAccount as String: key, kSecAttrAccount as String: key
kSecAttrAccessGroup as String: accessGroup
] ]
SecItemDelete(query as CFDictionary) SecItemDelete(query as CFDictionary)
} }

View File

@@ -3,15 +3,13 @@ import Security
enum KeychainService { enum KeychainService {
static let service = "com.daniil.pulsehealth" static let service = "com.daniil.pulsehealth"
static let accessGroup = "V9AG8JTFLC.com.daniil.pulsehealth.shared"
static func save(key: String, value: String) { static func save(key: String, value: String) {
guard let data = value.data(using: .utf8) else { return } guard let data = value.data(using: .utf8) else { return }
let query: [String: Any] = [ let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword, kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service, kSecAttrService as String: service,
kSecAttrAccount as String: key, kSecAttrAccount as String: key
kSecAttrAccessGroup as String: accessGroup
] ]
SecItemDelete(query as CFDictionary) SecItemDelete(query as CFDictionary)
var add = query var add = query
@@ -25,7 +23,6 @@ enum KeychainService {
kSecClass as String: kSecClassGenericPassword, kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service, kSecAttrService as String: service,
kSecAttrAccount as String: key, kSecAttrAccount as String: key,
kSecAttrAccessGroup as String: accessGroup,
kSecReturnData as String: true, kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne kSecMatchLimit as String: kSecMatchLimitOne
] ]
@@ -39,8 +36,7 @@ enum KeychainService {
let query: [String: Any] = [ let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword, kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service, kSecAttrService as String: service,
kSecAttrAccount as String: key, kSecAttrAccount as String: key
kSecAttrAccessGroup as String: accessGroup
] ]
SecItemDelete(query as CFDictionary) SecItemDelete(query as CFDictionary)
} }