payfrit-beacon-ios/_backup/Services/AuthStorage.swift
John Pinkyfloyd 8c2320da44 Add ios-marketing idiom, iPad orientations, launch screen
- Fixed App Store icon display with ios-marketing idiom
- Added iPad orientation support for multitasking
- Added UILaunchScreen for iPad requirements
- Removed unused BLE permissions and files from build

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 19:38:11 -08:00

95 lines
3.4 KiB
Swift

import Foundation
import Security
struct AuthCredentials {
let userId: Int
let token: String
let userName: String?
let photoUrl: String?
}
actor AuthStorage {
static let shared = AuthStorage()
private let userIdKey = "payfrit_beacon_user_id"
private let userNameKey = "payfrit_beacon_user_name"
private let userPhotoKey = "payfrit_beacon_user_photo"
private let serviceName = "com.payfrit.beacon"
private let tokenAccount = "auth_token"
// MARK: - Save
func saveAuth(userId: Int, token: String, userName: String? = nil, photoUrl: String? = nil) {
UserDefaults.standard.set(userId, forKey: userIdKey)
// Always overwrite name/photo to prevent stale data from previous user
if let name = userName, !name.isEmpty {
UserDefaults.standard.set(name, forKey: userNameKey)
} else {
UserDefaults.standard.removeObject(forKey: userNameKey)
}
if let photo = photoUrl, !photo.isEmpty {
UserDefaults.standard.set(photo, forKey: userPhotoKey)
} else {
UserDefaults.standard.removeObject(forKey: userPhotoKey)
}
saveToKeychain(token)
}
// MARK: - Load
func loadAuth() -> AuthCredentials? {
let userId = UserDefaults.standard.integer(forKey: userIdKey)
guard userId > 0 else { return nil }
guard let token = loadFromKeychain(), !token.isEmpty else { return nil }
let userName = UserDefaults.standard.string(forKey: userNameKey)
let photoUrl = UserDefaults.standard.string(forKey: userPhotoKey)
return AuthCredentials(userId: userId, token: token, userName: userName, photoUrl: photoUrl)
}
// MARK: - Clear
func clearAuth() {
UserDefaults.standard.removeObject(forKey: userIdKey)
UserDefaults.standard.removeObject(forKey: userNameKey)
UserDefaults.standard.removeObject(forKey: userPhotoKey)
deleteFromKeychain()
}
// MARK: - Keychain
private func saveToKeychain(_ token: String) {
deleteFromKeychain()
guard let data = token.data(using: .utf8) else { return }
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceName,
kSecAttrAccount as String: tokenAccount,
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemAdd(query as CFDictionary, nil)
}
private func loadFromKeychain() -> String? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceName,
kSecAttrAccount as String: tokenAccount,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
guard status == errSecSuccess, let data = result as? Data else { return nil }
return String(data: data, encoding: .utf8)
}
private func deleteFromKeychain() {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceName,
kSecAttrAccount as String: tokenAccount
]
SecItemDelete(query as CFDictionary)
}
}