Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Sources/ConnectAccounts/APIKeyController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ public class APIKeyController {
/// The list of API keys.
public private(set) var apiKeys: [APIKey]?
/// The currently selected API key.
///
/// Deprecated: The concept of a "selected API key" will be removed in a future version.
/// Persist and manage selection state outside of APIKeyController.
@available(*, deprecated, message: "The concept of a selected API key is deprecated and will be removed in a future version. Persist and manage selection outside of APIKeyController.")
public var selectedAPIKey: APIKey? {
didSet {
if let selectedAPIKey {
Expand Down Expand Up @@ -38,6 +42,9 @@ public class APIKeyController {
}

/// Loads the API keys from the keychain.
///
/// Note: This method currently auto-selects an API key if one is available (matching the persisted selection, or the first key).
/// The auto-selection side effect is deprecated and will be removed in a future version. Do not rely on it.
public func loadAPIKeys() throws {
let apiKeys = try keychain.listGenericPasswords(forService: service)
.map { password -> APIKey in
Expand All @@ -56,8 +63,14 @@ public class APIKeyController {
Adds a new API key to the keychain.

- Parameter apiKey: The API key to add.

Note: This method currently auto-selects the key if it is the first one added.
The auto-selection side effect is deprecated and will be removed in a future version. Do not rely on it.
*/
public func addAPIKey(_ apiKey: APIKey) throws {
if apiKeys == nil {
try loadAPIKeys()
}
do {
try keychain.addGenericPassword(forService: service, password: apiKey.getGenericPassword())
} catch KeychainError.duplicatePassword {
Expand All @@ -79,6 +92,9 @@ public class APIKeyController {
- Parameter apiKey: The API key to delete.
*/
public func deleteAPIKey(_ apiKey: APIKey) throws {
if apiKeys == nil {
try loadAPIKeys()
}
try keychain.deleteGenericPassword(forService: service, password: apiKey.getGenericPassword())
guard var apiKeys, let index = apiKeys.firstIndex(where: { $0.keyId == apiKey.keyId }) else {
return
Expand Down
14 changes: 6 additions & 8 deletions Tests/ConnectAccountsTests/AddAPIKeyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,27 @@ struct AddAPIKeyTests {
let mockKeychain = MockKeychain()
let controller = APIKeyController(keychainServiceName: "AppStoreConnectKit", keychain: mockKeychain)
#expect(controller.apiKeys == nil)
#expect(controller.selectedAPIKey == nil)
#expect(mockKeychain.genericPasswordsInKeychain.isEmpty)
// Act
try controller.addAPIKey(apiKey)
// Assert
#expect(controller.apiKeys == [apiKey])
#expect(controller.selectedAPIKey == apiKey)
#expect(try mockKeychain.genericPasswordsInKeychain == [apiKey.getGenericPassword()])
}

@Test("Add API Key - Duplicate error")
func addAPIKey_Duplicate() {
func addAPIKey_Duplicate() throws {
// Arrange
let mockKeychain = MockKeychain()
mockKeychain.returnStatusForAdd = errSecDuplicateItem
let controller = APIKeyController(keychainServiceName: "AppStoreConnectKit", keychain: mockKeychain)
try controller.addAPIKey(apiKey)
#expect(controller.apiKeys == [apiKey])
// Act
#expect(throws: APIKeyError.duplicateAPIKey) {
try controller.addAPIKey(apiKey)
}
// Assert
#expect(controller.apiKeys == nil)
#expect(controller.selectedAPIKey == nil)
#expect(controller.apiKeys == [apiKey])
}

@Test("Add API Key - Unknown error")
Expand All @@ -52,12 +50,12 @@ struct AddAPIKeyTests {
let mockKeychain = MockKeychain()
mockKeychain.returnStatusForAdd = status
let controller = APIKeyController(keychainServiceName: "AppStoreConnectKit", keychain: mockKeychain)
#expect(controller.apiKeys == nil)
// Act
#expect(throws: APIKeyError.failedAddingAPIKey(status)) {
try controller.addAPIKey(apiKey)
}
// Assert
#expect(controller.apiKeys == nil)
#expect(controller.selectedAPIKey == nil)
#expect(controller.apiKeys == [])
}
}