Skip to content

Commit

Permalink
Minor updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mikenachbaur-okta committed Oct 29, 2024
1 parent 6d8542b commit 58c314f
Show file tree
Hide file tree
Showing 31 changed files with 101 additions and 141 deletions.
24 changes: 9 additions & 15 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ var package = Package(
.target(name: "OktaClientMacros"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacrosGenericTestSupport", package: "swift-syntax"),
]),
.target(name: "OktaClientMacros",
dependencies: [
Expand All @@ -72,9 +73,7 @@ var package = Package(
path: "Sources/OktaClientMacros/Interface"),

// Concurrency & locking
.target(name: "OktaConcurrency",
exclude: exclude(),
resources: include()),
.target(name: "OktaConcurrency"),
.testTarget(name: "OktaConcurrencyTests",
dependencies: [
.target(name: "OktaConcurrency"),
Expand All @@ -90,9 +89,7 @@ var package = Package(
dependencies: [
.target(name: "OktaConcurrency"),
.target(name: "OktaClientMacros")
],
exclude: exclude(),
resources: include()),
]),
.target(name: "KeychainTestCommon",
dependencies: [
.target(name: "Keychain")
Expand All @@ -110,9 +107,7 @@ var package = Package(
dependencies: [
.target(name: "OktaConcurrency"),
.target(name: "OktaClientMacros")
],
exclude: exclude(),
resources: include()),
]),
.testTarget(name: "OktaUtilitiesTests",
dependencies: [
.target(name: "OktaUtilities"),
Expand All @@ -129,9 +124,7 @@ var package = Package(
.target(name: "APIClient",
dependencies: [
.target(name: "OktaUtilities"),
],
exclude: exclude(),
resources: include()),
]),
.testTarget(name: "APIClientTests",
dependencies: [
.target(name: "APIClient"),
Expand All @@ -155,8 +148,7 @@ var package = Package(
.target(name: "OktaConcurrency"),
.target(name: "APIClient")
],
exclude: exclude(),
resources: include(.process("Resources"))),
resources: [ .process("Resources") ]),
.testTarget(name: "JWTTests",
dependencies: [
.target(name: "OktaConcurrency"),
Expand Down Expand Up @@ -239,7 +231,9 @@ var package = Package(

#if compiler(>=6)
for target in package.targets where target.type != .system && target.type != .test {
target.swiftSettings = target.swiftSettings ?? []
target.swiftSettings = target.swiftSettings ?? [
.enableExperimentalFeature("StrictConcurrency=complete")
]
target.swiftSettings?.append(contentsOf: [
.enableExperimentalFeature("StrictConcurrency"),
.enableUpcomingFeature("ExistentialAny"),
Expand Down
14 changes: 0 additions & 14 deletions Sources/APIClient/PrivacyInfo.xcprivacy

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import OktaUtilities
import Keychain
import JWT

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

private let accountIdRegex = try? NSRegularExpression(pattern: "0oa[0-9a-zA-Z]{17}")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

import Foundation
import Keychain
Expand Down Expand Up @@ -56,6 +56,10 @@ final class KeychainTokenStorage: TokenStorage {
_defaultTokenID = id

try saveDefault()

DispatchQueue.global().async {
self.delegate?.token(storage: self, defaultChanged: id)
}
}

var defaultTokenID: String? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ final class UserDefaultsTokenStorage: TokenStorage {
userDefaults.removeObject(forKey: UserDefaultsKeys.defaultTokenKey)
}
userDefaults.synchronize()

DispatchQueue.global().async {
self.delegate?.token(storage: self, defaultChanged: id)
}
}

var defaultTokenID: String? {
Expand Down
3 changes: 3 additions & 0 deletions Sources/AuthFoundation/Token Management/TokenStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public protocol TokenStorage: Sendable {

/// Protocol that custom ``TokenStorage`` instances are required to communicate changes to.
public protocol TokenStorageDelegate: AnyObject, Sendable {
/// Sent when the default token has been changed.
func token(storage: any TokenStorage, defaultChanged id: String?)

/// Sent when a new token has been added.
///
/// > Important: This message should only be sent when a token is actually new. If the token is semantically identical to another one already in storage, the ``token(storage:replaced:with:)`` message should be sent instead.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import OktaClientMacros
fileprivate let staticLock = Lock()
nonisolated(unsafe) fileprivate var _isDefaultSynchronizable: Bool = false

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)
nonisolated(unsafe) fileprivate var _standard: [Credential.Security] = [.accessibility(.afterFirstUnlockThisDeviceOnly)]
#else
nonisolated(unsafe) fileprivate var _standard: [Credential.Security] = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extension Credential {
///
/// On Apple platforms, this controls the Keychain security settings for the underlying token's keychain item.
public enum Security {
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

/// Defines the accessibility level for a credential.
case accessibility(_ option: Keychain.Accessibility)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ final class CredentialCoordinatorImpl: Sendable, CredentialCoordinator {
}

static func defaultTokenStorage() -> any TokenStorage {
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)
KeychainTokenStorage()
#else
UserDefaultsTokenStorage()
Expand Down Expand Up @@ -216,23 +216,17 @@ extension CredentialCoordinatorImpl: OAuth2ClientDelegate {
}

extension CredentialCoordinatorImpl: TokenStorageDelegate {
// func token(storage: any TokenStorage, defaultTokenChanged token: Token?) {
// withLock {
// // Ensure the default matches what the Token Storage says,
// // and that the new token is indeed different from the local default.
// guard _tokenStorage.defaultTokenID == token?.id,
// _default?.id != token?.id
// else {
// return
// }
//
// if let token = token {
// _default = _credentialDataSource.credential(for: token, coordinator: self)
// } else {
// _default = nil
// }
// }
// }
func token(storage: any TokenStorage, defaultChanged id: String?) {
// Almost all default ID changes will be triggered from the Credential Coordinator.
// In the rare event that the underlying value is changed from some other means,
// this operation will ensure the statei of this class will remain consistent.
withLock {
// Ensure the new token is indeed different from the local default.
if _default?.id != id {
_default = nil
}
}
}

func token(storage: any TokenStorage, added id: String, token: Token) {
}
Expand All @@ -243,7 +237,6 @@ extension CredentialCoordinatorImpl: TokenStorageDelegate {
func token(storage: any TokenStorage, replaced id: String, with newToken: Token) {
// Doing nothing with this, for now...
}

}

extension CredentialCoordinatorImpl: CredentialDataSourceDelegate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import LocalAuthentication
#endif

extension Array where Element == Credential.Security {
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)
#if canImport(LocalAuthentication) && !os(tvOS)
var context: LAContext? {
for case let Credential.Security.context(value) in self {
Expand Down
2 changes: 1 addition & 1 deletion Sources/JWT/Enums/JWTClaim.swift
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ public extension HasClaims where ClaimType == JWTClaim {
/// The person's preferred username.
var preferredUsername: String? { self[.preferredUsername] }

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)
/// The person's name components, pre-assigned to a PersonNameComponents object.
///
/// This property can be used as a convenience to generate a string representation of the user's name, based on the user's current locale.
Expand Down
14 changes: 0 additions & 14 deletions Sources/JWT/PrivacyInfo.xcprivacy

This file was deleted.

2 changes: 1 addition & 1 deletion Sources/Keychain/Internal/Keychain+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

@preconcurrency import Foundation

Expand Down
2 changes: 1 addition & 1 deletion Sources/Keychain/Internal/KeychainProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

import Foundation

Expand Down
2 changes: 1 addition & 1 deletion Sources/Keychain/Keychain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Foundation
import OktaConcurrency
import OktaClientMacros

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

#if canImport(LocalAuthentication) && !os(tvOS)
import LocalAuthentication
Expand Down
2 changes: 1 addition & 1 deletion Sources/Keychain/KeychainError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import Foundation

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(Darwin)

/// Describes errors that may occur when interacting with the keychain.
public enum KeychainError: Error {
Expand Down
14 changes: 0 additions & 14 deletions Sources/OktaConcurrency/PrivacyInfo.xcprivacy

This file was deleted.

14 changes: 0 additions & 14 deletions Sources/OktaUtilities/PrivacyInfo.xcprivacy

This file was deleted.

23 changes: 22 additions & 1 deletion Tests/AuthFoundationTests/CredentialCoordinatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import FoundationNetworking
@testable import TestCommon
@testable import AuthFoundation

final class UserCoordinatorTests: XCTestCase {
final class CredentialCoordinatorTests: XCTestCase {
var userDefaults: UserDefaults!
var storage: UserDefaultsTokenStorage!
var coordinator: CredentialCoordinatorImpl!
Expand Down Expand Up @@ -80,10 +80,31 @@ final class UserCoordinatorTests: XCTestCase {
}

func testImplicitCredentialForToken() throws {
XCTAssertNil(storage.defaultTokenID)
XCTAssertNil(coordinator.default)

let credential = try coordinator.store(token: token, security: [])

XCTAssertEqual(storage.allIDs, [token.id])
XCTAssertEqual(storage.defaultTokenID, token.id)
XCTAssertEqual(coordinator.default, credential)

XCTAssertNoThrow(try credential.remove())
XCTAssertNil(storage.defaultTokenID)
XCTAssertNil(coordinator.default)
}

func testRespondToStorageDelegate() throws {
coordinator.default = try coordinator.store(token: token, security: [])

XCTAssertEqual(storage.allIDs, [token.id])
XCTAssertEqual(storage.defaultTokenID, token.id)
XCTAssertEqual(coordinator.default?.id, token.id)

XCTAssertNoThrow(try storage.remove(id: token.id))
XCTAssertNil(storage.defaultTokenID)

sleep(for: .standard)
XCTAssertNil(coordinator.default)
}
}
35 changes: 16 additions & 19 deletions Tests/AuthFoundationTests/CredentialNotificationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,22 @@ final class CredentialNotificationTests: XCTestCase {
}

func testNotifications() throws {
let wait = expectation(description: "Main actor")
let oldCredential = coordinator.default

Task { @MainActor in
let oldCredential = coordinator.default

let recorder = NotificationRecorder(observing: [.defaultCredentialChanged])

let credential = try coordinator.store(token: token, security: [])
self.wait(for: .standard)
XCTAssertEqual(recorder.notifications.count, 1)
XCTAssertEqual(recorder.notifications.first?.object as? Credential, credential)
XCTAssertNotEqual(oldCredential, credential)

recorder.reset()
coordinator.default = nil
self.wait(for: .standard)
XCTAssertEqual(recorder.notifications.count, 1)
XCTAssertNil(recorder.notifications.first?.object)
}
waitForExpectations(timeout: .long)
let recorder = NotificationRecorder(observing: [.defaultCredentialChanged])

let credential = try coordinator.store(token: token, security: [])
sleep(for: .short)

XCTAssertEqual(recorder.notifications.count, 1)
XCTAssertEqual(recorder.notifications.first?.object as? Credential, credential)
XCTAssertNotEqual(oldCredential, credential)

recorder.reset()
coordinator.default = nil
sleep(for: .short)

XCTAssertEqual(recorder.notifications.count, 1)
XCTAssertNil(recorder.notifications.first?.object)
}
}
2 changes: 1 addition & 1 deletion Tests/AuthFoundationTests/CredentialRefreshTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ final class CredentialRefreshTests: XCTestCase, OAuth2ClientDelegate {
// Stopping should prevent subsequent refreshes
credential.automaticRefresh = false

sleep(1)
sleep(for: .short)
XCTAssertEqual(urlSession.requests.count, 0)
}

Expand Down
Loading

0 comments on commit 58c314f

Please sign in to comment.