Line data Source code
1 : // 2 : // SwiftySimpleKeychain+Get.swift 3 : // SwiftySimpleKeychain 4 : // 5 : // Copyright (c) 2022 Ezequiel (Kimi) Aceto (https://eaceto.dev). Based on Auth0's SimpleKeychain 6 : // 7 : // Permission is hereby granted, free of charge, to any person obtaining a copy 8 : // of this software and associated documentation files (the "Software"), to deal 9 : // in the Software without restriction, including without limitation the rights 10 : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 : // copies of the Software, and to permit persons to whom the Software is 12 : // furnished to do so, subject to the following conditions: 13 : // 14 : // The above copyright notice and this permission notice shall be included in 15 : // all copies or substantial portions of the Software. 16 : // 17 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 : // THE SOFTWARE. 24 : 25 : #if canImport(Foundation) 26 : import Foundation 27 : #endif 28 : 29 : public extension SwiftySimpleKeychain { 30 : 31 : /** 32 : * Checks if the entry with **key** exists in the Keychain 33 : * 34 : * Usage: 35 : * ```swift 36 : * if keychain.hasValue(for: "aKey") { 37 : * // entry exists in Keychain 38 : * } 39 : * ``` 40 : * 41 : * - Parameter key: Identifier of the entry 42 : * - Returns **true** if the key exists 43 : */ 44 6 : func hasValue(for key: String) -> Bool { 45 6 : if key.isEmpty { return false } 46 6 : let query = queryFind(by: key) 47 6 : let status = SecItemCopyMatching(query as CFDictionary, nil) 48 6 : return status == errSecSuccess 49 6 : } 50 : 51 : /** 52 : * Returns a **DataErrorResult** for the given key 53 : * 54 : * - Parameter key: Identifier of the key 55 : * - Parameter promptMessage: A message to show to the user in case the Keychain should be unlocked 56 : * - Returns **DataErrorResult** 57 : */ 58 9 : func dataResult(for key: String, with promptMessage: String? = nil) -> DataErrorResult { 59 9 : let query = queryFetchOne(by: key, promptMessage: promptMessage) 60 9 : 61 9 : var item: CFTypeRef? 62 9 : let status = SecItemCopyMatching(query as CFDictionary, &item) 63 9 : 64 9 : if status != errSecSuccess { 65 5 : return .failure(SwiftySimpleKeychainError.from(status)) 66 5 : } 67 4 : 68 4 : guard let data = item as? Data else { 69 0 : return .failure(.decode) 70 4 : } 71 4 : 72 4 : return .success(data) 73 4 : } 74 : 75 : /** 76 : * Returns a **StringErrorResult** for the given key 77 : * 78 : * - Parameter key: Identifier of the key 79 : * - Parameter promptMessage: A message to show to the user in case the Keychain should be unlocked 80 : * - Returns **StringErrorResult** 81 : */ 82 2 : func stringResult(for key: String, with promptMessage: String? = nil) -> StringErrorResult { 83 2 : let result = dataResult(for: key, with: promptMessage) 84 2 : switch result { 85 2 : case .success(let data): 86 1 : guard let string = String(data: data, encoding: .utf8) else { 87 0 : return .failure(.decode) 88 1 : } 89 1 : return .success(string) 90 2 : case .failure(let error): 91 1 : return .failure(error) 92 2 : } 93 2 : } 94 : 95 : /** 96 : * Returns a **Data** for the given key if exists 97 : * 98 : * Usage: 99 : * ```swift 100 : * if let data = keychain.data(for: "aKey") { 101 : * // valid data retrieved from the Keychain 102 : * } 103 : * ``` 104 : * 105 : * - Parameter key: Identifier of the key 106 : * - Parameter promptMessage: A message to show to the user in case the Keychain should be unlocked 107 : * - Returns **Data** if an entry exists for the given key, or **nil** in case of error. 108 : */ 109 5 : func data(for key: String, with promptMessage: String? = nil) -> Data? { 110 5 : switch dataResult(for: key, with: promptMessage) { 111 5 : case .success(let dataValue): 112 2 : return dataValue 113 5 : case .failure: 114 3 : return nil 115 5 : } 116 5 : } 117 : 118 : /** 119 : * Returns a **String** for the given key if exists 120 : * 121 : * Usage: 122 : * ```swift 123 : * if let text = keychain.string(for: "aKey") { 124 : * // valid string retrieved from the Keychain 125 : * } 126 : * ``` 127 : * 128 : * - Parameter key: Identifier of the key 129 : * - Parameter promptMessage: A message to show to the user in case the Keychain should be unlocked 130 : * - Returns **String** if an entry exists for the given key, or **nil** in case of error. 131 : */ 132 3 : func string(for key: String, with promptMessage: String? = nil) -> String? { 133 3 : guard let data = data(for: key, with: promptMessage), let string = String(data: data, encoding: .utf8) else { 134 2 : return nil 135 2 : } 136 1 : return string 137 3 : } 138 : }