-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathKeychainStorage.swift
More file actions
80 lines (62 loc) · 2.29 KB
/
Copy pathKeychainStorage.swift
File metadata and controls
80 lines (62 loc) · 2.29 KB
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
//
// KeychainStorage.swift
// Persistence
//
// Created by 반성준 on 6/21/25.
//
import DataSource
import Foundation
public final class KeychainStorage: KeychainStorageProtocol {
private let service: String
private let accessGroup: String?
public init(service: String? = nil, accessGroup: String? = nil) {
self.service = service ?? Bundle.main.bundleIdentifier ?? "DefaultService"
self.accessGroup = accessGroup
}
public func save(_ value: String, forKey key: String) -> Bool {
guard let data = value.data(using: .utf8) else {
return false
}
var query = baseQuery(for: key)
let attributes: [String: Any] = [
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
let status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
if status == errSecItemNotFound {
for (attributeKey, attributeValue) in attributes {
query[attributeKey] = attributeValue
}
return SecItemAdd(query as CFDictionary, nil) == errSecSuccess
}
return status == errSecSuccess
}
public func load(forKey key: String) -> String? {
var query = baseQuery(for: key)
query[kSecReturnData as String] = kCFBooleanTrue
query[kSecMatchLimit as String] = kSecMatchLimitOne
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
if status == errSecSuccess,
let data = result as? Data {
return String(data: data, encoding: .utf8)
}
return nil
}
public func remove(forKey key: String) -> Bool {
let query = baseQuery(for: key)
let status = SecItemDelete(query as CFDictionary)
return status == errSecSuccess || status == errSecItemNotFound
}
private func baseQuery(for key: String) -> [String: Any] {
var query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: key
]
if let accessGroup = accessGroup {
query[kSecAttrAccessGroup as String] = accessGroup
}
return query
}
}