|
7 | 7 | //
|
8 | 8 |
|
9 | 9 | import Foundation
|
10 |
| -import MullvadLogging |
11 | 10 | import MullvadTypes
|
12 | 11 | import Security
|
13 | 12 |
|
14 | 13 | public class KeychainSettingsStore: SettingsStore {
|
15 | 14 | public let serviceName: String
|
16 | 15 | public let accessGroup: String
|
17 |
| - private let logger = Logger(label: "KeychainSettingsStore") |
18 |
| - private let cacheDirectory: URL |
19 | 16 |
|
20 |
| - public init(serviceName: String, accessGroup: String, cacheDirectory: URL) { |
| 17 | + public init(serviceName: String, accessGroup: String) { |
21 | 18 | self.serviceName = serviceName
|
22 | 19 | self.accessGroup = accessGroup
|
23 |
| - self.cacheDirectory = cacheDirectory.appendingPathComponent("keychainLock.json") |
24 | 20 | }
|
25 | 21 |
|
26 | 22 | public func read(key: SettingsKey) throws -> Data {
|
27 |
| - try coordinate(Data(), try readItemData(key)) |
| 23 | + try readItemData(key) |
28 | 24 | }
|
29 | 25 |
|
30 | 26 | public func write(_ data: Data, for key: SettingsKey) throws {
|
31 |
| - try coordinate((), try addOrUpdateItem(key, data: data)) |
| 27 | + try addOrUpdateItem(key, data: data) |
32 | 28 | }
|
33 | 29 |
|
34 | 30 | public func delete(key: SettingsKey) throws {
|
35 |
| - try coordinate((), try deleteItem(key)) |
36 |
| - } |
37 |
| - |
38 |
| - /// Prevents all items in `keys` from backup inclusion |
39 |
| - /// |
40 |
| - /// This method uses the `coordinate` helper function to guarantee atomicity |
41 |
| - /// of the keychain exclusion process so that a pre-running VPN process cannot |
42 |
| - /// accidentally read or write to the keychain when the exclusion happens. |
43 |
| - /// It will be blocked temporarily and automatically resume when the migration is done. |
44 |
| - /// |
45 |
| - /// Likewise, the exclusion process will also be forced to wait until it can access the keychain |
46 |
| - /// if the VPN process is operating on it. |
47 |
| - /// |
48 |
| - /// - Important: Do not call `read`, `write`, or `delete` from this method, |
49 |
| - /// the coordinator is *not reentrant* and will deadlock if you do so. |
50 |
| - /// Only call methods that do not call `coordinate`. |
51 |
| - /// |
52 |
| - /// - Parameter keys: The keys to exclude from backup |
53 |
| - public func excludeFromBackup(keys: [SettingsKey]) { |
54 |
| - let coordination = { [unowned self] in |
55 |
| - for key in keys { |
56 |
| - do { |
57 |
| - let data = try readItemData(key) |
58 |
| - try deleteItem(key) |
59 |
| - try addItem(key, data: data) |
60 |
| - } catch { |
61 |
| - logger.error("Could not exclude \(key) from backups. \(error)") |
62 |
| - } |
63 |
| - } |
64 |
| - } |
65 |
| - |
66 |
| - try? coordinate((), coordination()) |
| 31 | + try deleteItem(key) |
67 | 32 | }
|
68 | 33 |
|
69 | 34 | private func addItem(_ item: SettingsKey, data: Data) throws {
|
70 | 35 | var query = createDefaultAttributes(item: item)
|
71 |
| - query.merge(createAccessAttributesThisDeviceOnly()) { current, _ in |
| 36 | + query.merge(createAccessAttributes()) { current, _ in |
72 | 37 | current
|
73 | 38 | }
|
74 | 39 | query[kSecValueData] = data
|
@@ -131,38 +96,10 @@ public class KeychainSettingsStore: SettingsStore {
|
131 | 96 | ]
|
132 | 97 | }
|
133 | 98 |
|
134 |
| - private func createAccessAttributesThisDeviceOnly() -> [CFString: Any] { |
| 99 | + private func createAccessAttributes() -> [CFString: Any] { |
135 | 100 | [
|
136 | 101 | kSecAttrAccessGroup: accessGroup,
|
137 |
| - kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, |
| 102 | + kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock, |
138 | 103 | ]
|
139 | 104 | }
|
140 |
| - |
141 |
| - /// Runs `action` in a cross process synchronized way |
142 |
| - /// |
143 |
| - /// This enables doing CRUD operations on the keychain items in a cross process safe way. |
144 |
| - /// This does not prevent TOCTOU issues. |
145 |
| - /// - Parameters: |
146 |
| - /// - initial: Dummy value used for the returned value, if any. |
147 |
| - /// - action: The CRUD operation to run on the keychain. |
148 |
| - /// - Returns: The result of the keychain operation, if any. |
149 |
| - private func coordinate<T>(_ initial: T, _ action: @autoclosure () throws -> T) throws -> T { |
150 |
| - let fileCoordinator = NSFileCoordinator(filePresenter: nil) |
151 |
| - var error: NSError? |
152 |
| - var thrownError: Error? |
153 |
| - var returnedValue: T = initial |
154 |
| - fileCoordinator.coordinate(writingItemAt: cacheDirectory, error: &error) { _ in |
155 |
| - do { |
156 |
| - returnedValue = try action() |
157 |
| - } catch { |
158 |
| - thrownError = error |
159 |
| - } |
160 |
| - } |
161 |
| - |
162 |
| - if let thrownError { |
163 |
| - throw thrownError |
164 |
| - } |
165 |
| - |
166 |
| - return returnedValue |
167 |
| - } |
168 | 105 | }
|
0 commit comments