diff options
| author | Dustin Mierau <dustin@mierau.me> | 2024-01-17 23:18:27 -0800 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2024-01-17 23:18:27 -0800 |
| commit | 1b303803e53dbeb24dab1a7c714d71ee14f002db (patch) | |
| tree | 4616861b23642d26c9b58b5925315232c1fdb975 /Hotline/Utility | |
| parent | 8e85fbbdadcb993cd270ff4bf60d2280b9e7ad56 (diff) | |
Added server and tracker bookmarks. Reordering in Servers window. Delete. All stored securely in Keychain.
Diffstat (limited to 'Hotline/Utility')
| -rw-r--r-- | Hotline/Utility/DAKeychain.swift | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/Hotline/Utility/DAKeychain.swift b/Hotline/Utility/DAKeychain.swift new file mode 100644 index 0000000..8031886 --- /dev/null +++ b/Hotline/Utility/DAKeychain.swift @@ -0,0 +1,81 @@ +// +// DAKeychain.swift +// DAKeychain +// +// Created by Dejan on 28/02/2017. +// Copyright © 2017 Dejan. All rights reserved. +// + +import Foundation + +open class DAKeychain { + + open var loggingEnabled = false + + private init() {} + public static let shared = DAKeychain() + + open subscript(key: String) -> String? { + get { + return load(withKey: key) + } set { + DispatchQueue.global().sync(flags: .barrier) { + self.save(newValue, forKey: key) + } + } + } + + private func save(_ string: String?, forKey key: String) { + let query = keychainQuery(withKey: key) + let objectData: Data? = string?.data(using: .utf8, allowLossyConversion: false) + + if SecItemCopyMatching(query, nil) == noErr { + if let dictData = objectData { + let status = SecItemUpdate(query, NSDictionary(dictionary: [kSecValueData: dictData])) + logPrint("Update status: ", status) + } else { + let status = SecItemDelete(query) + logPrint("Delete status: ", status) + } + } else { + if let dictData = objectData { + query.setValue(dictData, forKey: kSecValueData as String) + let status = SecItemAdd(query, nil) + logPrint("Update status: ", status) + } + } + } + + private func load(withKey key: String) -> String? { + let query = keychainQuery(withKey: key) + query.setValue(kCFBooleanTrue, forKey: kSecReturnData as String) + query.setValue(kCFBooleanTrue, forKey: kSecReturnAttributes as String) + + var result: CFTypeRef? + let status = SecItemCopyMatching(query, &result) + + guard + let resultsDict = result as? NSDictionary, + let resultsData = resultsDict.value(forKey: kSecValueData as String) as? Data, + status == noErr + else { + logPrint("Load status: ", status) + return nil + } + return String(data: resultsData, encoding: .utf8) + } + + private func keychainQuery(withKey key: String) -> NSMutableDictionary { + let result = NSMutableDictionary() + result.setValue(kSecClassGenericPassword, forKey: kSecClass as String) + result.setValue(key, forKey: kSecAttrService as String) + result.setValue(kSecAttrAccessibleWhenUnlocked, forKey: kSecAttrAccessible as String) + return result + } + + private func logPrint(_ items: Any...) { + if loggingEnabled { + print(items) + } + } +} |