1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
//
// 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)
}
}
}
|