Source code for the WriteFreely SwiftUI app for iOS, iPadOS, and macOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

56 lines
2.2 KiB

  1. import Foundation
  2. extension WriteFreelyModel {
  3. func saveTokenToKeychain(_ token: String, username: String?, server: String) throws {
  4. let query: [String: Any] = [
  5. kSecClass as String: kSecClassGenericPassword,
  6. kSecValueData as String: token.data(using: .utf8)!,
  7. kSecAttrAccount as String: username ?? "anonymous",
  8. kSecAttrService as String: server
  9. ]
  10. let status = SecItemAdd(query as CFDictionary, nil)
  11. guard status == errSecDuplicateItem || status == errSecSuccess else {
  12. throw KeychainError.couldNotStoreAccessToken
  13. }
  14. }
  15. func purgeTokenFromKeychain(username: String?, server: String) throws {
  16. let query: [String: Any] = [
  17. kSecClass as String: kSecClassGenericPassword,
  18. kSecAttrAccount as String: username ?? "anonymous",
  19. kSecAttrService as String: server
  20. ]
  21. let status = SecItemDelete(query as CFDictionary)
  22. guard status == errSecSuccess || status == errSecItemNotFound else {
  23. throw KeychainError.couldNotPurgeAccessToken
  24. }
  25. }
  26. func fetchTokenFromKeychain(username: String?, server: String) throws -> String? {
  27. let query: [String: Any] = [
  28. kSecClass as String: kSecClassGenericPassword,
  29. kSecAttrAccount as String: username ?? "anonymous",
  30. kSecAttrService as String: server,
  31. kSecMatchLimit as String: kSecMatchLimitOne,
  32. kSecReturnAttributes as String: true,
  33. kSecReturnData as String: true
  34. ]
  35. var secItem: CFTypeRef?
  36. let status = SecItemCopyMatching(query as CFDictionary, &secItem)
  37. guard status != errSecItemNotFound else {
  38. throw KeychainError.couldNotFetchAccessToken
  39. }
  40. guard status == errSecSuccess else {
  41. throw KeychainError.couldNotFetchAccessToken
  42. }
  43. guard let existingSecItem = secItem as? [String: Any],
  44. let tokenData = existingSecItem[kSecValueData as String] as? Data,
  45. let token = String(data: tokenData, encoding: .utf8) else {
  46. throw KeychainError.couldNotFetchAccessToken
  47. }
  48. return token
  49. }
  50. }