aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Utility
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2024-01-17 23:18:27 -0800
committerDustin Mierau <dustin@mierau.me>2024-01-17 23:18:27 -0800
commit1b303803e53dbeb24dab1a7c714d71ee14f002db (patch)
tree4616861b23642d26c9b58b5925315232c1fdb975 /Hotline/Utility
parent8e85fbbdadcb993cd270ff4bf60d2280b9e7ad56 (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.swift81
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)
+ }
+ }
+}