damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

KeychainStorage.swift (2305B)


      1 //
      2 //  KeychainStorage.swift
      3 //  damus
      4 //
      5 //  Created by Bryan Montz on 5/2/23.
      6 //
      7 
      8 import Foundation
      9 import Security
     10 
     11 @propertyWrapper struct KeychainStorage {
     12     let account: String
     13     private let service = "damus"
     14     
     15     var wrappedValue: String? {
     16         get {
     17             let query = [
     18                 kSecAttrService: service,
     19                 kSecAttrAccount: account,
     20                 kSecClass: kSecClassGenericPassword,
     21                 kSecReturnData: true,
     22                 kSecMatchLimit: kSecMatchLimitOne
     23             ] as [CFString: Any] as CFDictionary
     24             
     25             var result: AnyObject?
     26             let status = SecItemCopyMatching(query, &result)
     27             
     28             if status == errSecSuccess, let data = result as? Data {
     29                 return String(data: data, encoding: .utf8)
     30             } else {
     31                 return nil
     32             }
     33         }
     34         set {
     35             if let newValue {
     36                 let query = [
     37                     kSecAttrService: service,
     38                     kSecAttrAccount: account,
     39                     kSecClass: kSecClassGenericPassword,
     40                     kSecValueData: newValue.data(using: .utf8) as Any
     41                 ] as [CFString: Any] as CFDictionary
     42                 
     43                 var status = SecItemAdd(query, nil)
     44                 
     45                 if status == errSecDuplicateItem {
     46                     let query = [
     47                         kSecAttrService: service,
     48                         kSecAttrAccount: account,
     49                         kSecClass: kSecClassGenericPassword
     50                     ] as [CFString: Any] as CFDictionary
     51                     
     52                     let updates = [
     53                         kSecValueData: newValue.data(using: .utf8) as Any
     54                     ] as CFDictionary
     55                     
     56                     status = SecItemUpdate(query, updates)
     57                 }
     58             } else {
     59                 let query = [
     60                     kSecAttrService: service,
     61                     kSecAttrAccount: account,
     62                     kSecClass: kSecClassGenericPassword
     63                 ] as [CFString: Any] as CFDictionary
     64                 
     65                 _ = SecItemDelete(query)
     66             }
     67         }
     68     }
     69     
     70     init(account: String) {
     71         self.account = account
     72     }
     73 }