• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supabase-swift / 28672594529

03 Jul 2026 04:27PM UTC coverage: 80.885% (-0.1%) from 81.008%
28672594529

push

github

web-flow
fix(postgrest): quote in() filter values containing reserved characters (#1061)

12 of 12 new or added lines in 3 files covered. (100.0%)

21 existing lines in 1 file now uncovered.

7655 of 9464 relevant lines covered (80.89%)

1134590.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

25.55
/Sources/Auth/Internal/Keychain.swift
1
#if !os(Windows) && !os(Linux) && !os(Android)
2
  import Foundation
3
  import Security
4

5
  struct Keychain {
6
    let service: String?
7
    let accessGroup: String?
8

9
    init(
10
      service: String?,
11
      accessGroup: String? = nil
12
    ) {
1✔
13
      self.service = service
1✔
14
      self.accessGroup = accessGroup
1✔
15
    }
1✔
16

UNCOV
17
    private func assertSuccess(forStatus status: OSStatus) throws {
×
UNCOV
18
      if status != errSecSuccess {
×
UNCOV
19
        throw KeychainError(code: KeychainError.Code(rawValue: status))
×
UNCOV
20
      }
×
21
    }
×
22

23
    func data(forKey key: String) throws -> Data {
1✔
24
      let query = getOneQuery(byKey: key)
1✔
25
      var result: AnyObject?
1✔
26
      try assertSuccess(forStatus: SecItemCopyMatching(query as CFDictionary, &result))
1✔
27

1✔
28
      guard let data = result as? Data else {
1✔
29
        let message = "Unable to cast the retrieved item to a Data value"
×
30
        throw KeychainError(code: KeychainError.Code.unknown(message: message))
×
31
      }
1✔
32

1✔
33
      return data
1✔
34
    }
1✔
35

36
    func set(_ data: Data, forKey key: String) throws {
×
37
      let addItemQuery = setQuery(forKey: key, data: data)
×
38
      let addStatus = SecItemAdd(addItemQuery as CFDictionary, nil)
×
39

×
40
      if addStatus == KeychainError.duplicateItem.status {
×
41
        let updateQuery = baseQuery(withKey: key)
×
42
        let updateAttributes: [String: Any] = [kSecValueData as String: data]
×
43
        let updateStatus = SecItemUpdate(
×
44
          updateQuery as CFDictionary, updateAttributes as CFDictionary)
×
45
        try assertSuccess(forStatus: updateStatus)
×
46
      } else {
×
47
        try assertSuccess(forStatus: addStatus)
×
48
      }
×
49
    }
×
50

51
    func deleteItem(forKey key: String) throws {
×
52
      let query = baseQuery(withKey: key)
×
53
      try assertSuccess(forStatus: SecItemDelete(query as CFDictionary))
×
54
    }
×
55

56
    private func baseQuery(withKey key: String? = nil, data: Data? = nil) -> [String: Any] {
1✔
57
      var query: [String: Any] = [:]
1✔
58
      query[kSecClass as String] = kSecClassGenericPassword
1✔
59

1✔
60
      if let service {
1✔
61
        query[kSecAttrService as String] = service
1✔
62
      }
1✔
63
      if let key {
1✔
64
        query[kSecAttrAccount as String] = key
1✔
65
      }
1✔
66
      if let data {
1✔
67
        query[kSecValueData as String] = data
×
68
      }
×
69
      if let accessGroup {
1✔
70
        query[kSecAttrAccessGroup as String] = accessGroup
×
71
      }
×
72

1✔
73
      return query
1✔
74
    }
1✔
75

76
    func getOneQuery(byKey key: String) -> [String: Any] {
1✔
77
      var query = baseQuery(withKey: key)
1✔
78
      query[kSecReturnData as String] = kCFBooleanTrue
1✔
79
      query[kSecMatchLimit as String] = kSecMatchLimitOne
1✔
80
      return query
1✔
81
    }
1✔
82

83
    func setQuery(forKey key: String, data: Data) -> [String: Any] {
×
84
      var query = baseQuery(withKey: key, data: data)
×
85

×
86
      query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
×
87

×
88
      return query
×
89
    }
×
90
  }
91

92
  struct KeychainError: LocalizedError, CustomDebugStringConvertible {
93
    enum Code: RawRepresentable, Equatable {
94
      case operationNotImplemented
95
      case invalidParameters
96
      case userCanceled
97
      case itemNotAvailable
98
      case authFailed
99
      case duplicateItem
100
      case itemNotFound
101
      case interactionNotAllowed
102
      case decodeFailed
103
      case other(status: OSStatus)
104
      case unknown(message: String)
105

UNCOV
106
      init(rawValue: OSStatus) {
×
UNCOV
107
        switch rawValue {
×
UNCOV
108
        case errSecUnimplemented: self = .operationNotImplemented
×
UNCOV
109
        case errSecParam: self = .invalidParameters
×
UNCOV
110
        case errSecUserCanceled: self = .userCanceled
×
UNCOV
111
        case errSecNotAvailable: self = .itemNotAvailable
×
UNCOV
112
        case errSecAuthFailed: self = .authFailed
×
UNCOV
113
        case errSecDuplicateItem: self = .duplicateItem
×
UNCOV
114
        case errSecItemNotFound: self = .itemNotFound
×
UNCOV
115
        case errSecInteractionNotAllowed: self = .interactionNotAllowed
×
UNCOV
116
        case errSecDecode: self = .decodeFailed
×
UNCOV
117
        default: self = .other(status: rawValue)
×
UNCOV
118
        }
×
UNCOV
119
      }
×
120

121
      var rawValue: OSStatus {
×
122
        switch self {
×
123
        case .operationNotImplemented: errSecUnimplemented
×
124
        case .invalidParameters: errSecParam
×
125
        case .userCanceled: errSecUserCanceled
×
126
        case .itemNotAvailable: errSecNotAvailable
×
127
        case .authFailed: errSecAuthFailed
×
128
        case .duplicateItem: errSecDuplicateItem
×
129
        case .itemNotFound: errSecItemNotFound
×
130
        case .interactionNotAllowed: errSecInteractionNotAllowed
×
131
        case .decodeFailed: errSecDecode
×
132
        case .other(let status): status
×
133
        case .unknown: errSecSuccess  // This is not a Keychain error
×
134
        }
×
135
      }
×
136
    }
137

138
    let code: Code
139

UNCOV
140
    init(code: Code) {
×
UNCOV
141
      self.code = code
×
UNCOV
142
    }
×
143

144
    var status: OSStatus {
×
145
      code.rawValue
×
146
    }
×
147

148
    var localizedDescription: String { debugDescription }
×
149

150
    var errorDescription: String? { debugDescription }
×
151

152
    var debugDescription: String {
×
153
      switch code {
×
154
      case .operationNotImplemented:
×
155
        "errSecUnimplemented: A function or operation is not implemented."
×
156
      case .invalidParameters:
×
157
        "errSecParam: One or more parameters passed to the function are not valid."
×
158
      case .userCanceled:
×
159
        "errSecUserCanceled: User canceled the operation."
×
160
      case .itemNotAvailable:
×
161
        "errSecNotAvailable: No trust results are available."
×
162
      case .authFailed:
×
163
        "errSecAuthFailed: Authorization and/or authentication failed."
×
164
      case .duplicateItem:
×
165
        "errSecDuplicateItem: The item already exists."
×
166
      case .itemNotFound:
×
167
        "errSecItemNotFound: The item cannot be found."
×
168
      case .interactionNotAllowed:
×
169
        "errSecInteractionNotAllowed: Interaction with the Security Server is not allowed."
×
170
      case .decodeFailed:
×
171
        "errSecDecode: Unable to decode the provided data."
×
172
      case .other:
×
173
        "Unspecified Keychain error: \(status)."
×
174
      case .unknown(let message):
×
175
        "Unknown error: \(message)."
×
176
      }
×
177
    }
×
178

179
    // MARK: - Error Cases
180

181
    /// A function or operation is not implemented.
182
    /// See [errSecUnimplemented](https://developer.apple.com/documentation/security/errsecunimplemented).
183
    static let operationNotImplemented: KeychainError = .init(code: .operationNotImplemented)
184

185
    /// One or more parameters passed to the function are not valid.
186
    /// See [errSecParam](https://developer.apple.com/documentation/security/errsecparam).
187
    static let invalidParameters: KeychainError = .init(code: .invalidParameters)
188

189
    /// User canceled the operation.
190
    /// See [errSecUserCanceled](https://developer.apple.com/documentation/security/errsecusercanceled).
191
    static let userCanceled: KeychainError = .init(code: .userCanceled)
192

193
    /// No trust results are available.
194
    /// See [errSecNotAvailable](https://developer.apple.com/documentation/security/errsecnotavailable).
195
    static let itemNotAvailable: KeychainError = .init(code: .itemNotAvailable)
196

197
    /// Authorization and/or authentication failed.
198
    /// See [errSecAuthFailed](https://developer.apple.com/documentation/security/errsecauthfailed).
199
    static let authFailed: KeychainError = .init(code: .authFailed)
200

201
    /// The item already exists.
202
    /// See [errSecDuplicateItem](https://developer.apple.com/documentation/security/errsecduplicateitem).
203
    static let duplicateItem: KeychainError = .init(code: .duplicateItem)
204

205
    /// The item cannot be found.
206
    /// See [errSecItemNotFound](https://developer.apple.com/documentation/security/errsecitemnotfound).
207
    static let itemNotFound: KeychainError = .init(code: .itemNotFound)
208

209
    /// Interaction with the Security Server is not allowed.
210
    /// See [errSecInteractionNotAllowed](https://developer.apple.com/documentation/security/errsecinteractionnotallowed).
211
    static let interactionNotAllowed: KeychainError = .init(code: .interactionNotAllowed)
212

213
    /// Unable to decode the provided data.
214
    /// See [errSecDecode](https://developer.apple.com/documentation/security/errsecdecode).
215
    static let decodeFailed: KeychainError = .init(code: .decodeFailed)
216

217
    /// Other Keychain error.
218
    /// The `OSStatus` of the Keychain operation can be accessed via the ``status`` property.
219
    static let other: KeychainError = .init(code: .other(status: 0))
220

221
    /// Unknown error. This is not a Keychain error but a Keychain failure. For example, being unable to cast the
222
    /// retrieved item.
223
    static let unknown: KeychainError = .init(code: .unknown(message: ""))
224
  }
225

226
  extension KeychainError: Equatable {
227
    static func == (lhs: KeychainError, rhs: KeychainError) -> Bool {
×
228
      lhs.code == rhs.code && lhs.localizedDescription == rhs.localizedDescription
×
229
    }
×
230
  }
231
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc