From 08f020fafc37b3a2913bb6d0870fd6d702f171b9 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe <309420+danthorpe@users.noreply.github.com> Date: Sun, 8 Dec 2024 16:07:40 +0000 Subject: [PATCH] fix: ASWebAuthenticationPresentationContextProviding requires @MainActor (#108) * chore: update dependencies * chore: fix issue with MainActor presentation context * chore: make requests numbered * chore: update tests --------- Co-authored-by: danthorpe --- .../xcshareddata/swiftpm/Package.resolved | 12 ++++++------ .../Spotify/App/SignedOut/SignedOutFeature.swift | 4 ++-- .../Spotify/App/SpotifyClient/SpotifyClient.swift | 1 + Package.resolved | 4 ++-- Sources/OAuth/ASWebAuthenticationSession+.swift | 4 ++-- Sources/OAuth/OAuthDelegate.swift | 6 +++++- Sources/OAuth/OAuthError.swift | 1 + Tests/OAuthTests/OAuthDelegateTests.swift | 5 +++++ Tests/OAuthTests/StubOAuthSystem.swift | 2 +- 9 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Examples/Examples.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/Examples.xcworkspace/xcshareddata/swiftpm/Package.resolved index a47842ac..2c409400 100644 --- a/Examples/Examples.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Examples/Examples.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-composable-architecture", "state" : { - "revision" : "8013f1a72af8ccb2b1735d7aed831a8dc07c6fd0", - "version" : "1.15.0" + "revision" : "69247baf7be2fd6f5820192caef0082d01849cd0", + "version" : "1.16.1" } }, { @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-concurrency-extras", "state" : { - "revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", - "version" : "1.1.0" + "revision" : "163409ef7dae9d960b87f34b51587b6609a76c1f", + "version" : "1.3.0" } }, { @@ -149,8 +149,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-navigation", "state" : { - "revision" : "e834b3760731160d7d448509ee6a1408c8582a6b", - "version" : "2.2.0" + "revision" : "16a27ab7ae0abfefbbcba73581b3e2380b47a579", + "version" : "2.2.2" } }, { diff --git a/Examples/Spotify/App/SignedOut/SignedOutFeature.swift b/Examples/Spotify/App/SignedOut/SignedOutFeature.swift index 1261f1a1..426a98d0 100644 --- a/Examples/Spotify/App/SignedOut/SignedOutFeature.swift +++ b/Examples/Spotify/App/SignedOut/SignedOutFeature.swift @@ -37,8 +37,8 @@ struct SignedOutFeature { state = .failed return .none case .view(.signInButtonTapped): - return .run { send in - try await spotify.signIn(nil) + return .run { @MainActor send in + try await spotify.signIn(presentationContext: DefaultPresentationContext()) await send(.signInResponse(.success(true))) } catch: { error, send in await send(.signInResponse(.failure(error))) diff --git a/Examples/Spotify/App/SpotifyClient/SpotifyClient.swift b/Examples/Spotify/App/SpotifyClient/SpotifyClient.swift index 151e8842..727538a6 100644 --- a/Examples/Spotify/App/SpotifyClient/SpotifyClient.swift +++ b/Examples/Spotify/App/SpotifyClient/SpotifyClient.swift @@ -47,6 +47,7 @@ extension Spotify { .logged(using: Logger(subsystem: "works.dan.networking.examples.spotify", category: "Spotify API")) .server(prefixPath: "v1") .server(authority: "api.spotify.com") + .numbered() .authenticated( oauth: .spotify( clientId: "b4937bc99da547b4b90559f5024d8467", diff --git a/Package.resolved b/Package.resolved index a03e33ae..f41b4e9c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-concurrency-extras", "state" : { - "revision" : "6054df64b55186f08b6d0fd87152081b8ad8d613", - "version" : "1.2.0" + "revision" : "163409ef7dae9d960b87f34b51587b6609a76c1f", + "version" : "1.3.0" } }, { diff --git a/Sources/OAuth/ASWebAuthenticationSession+.swift b/Sources/OAuth/ASWebAuthenticationSession+.swift index 4ce8cdd2..8d68c8aa 100644 --- a/Sources/OAuth/ASWebAuthenticationSession+.swift +++ b/Sources/OAuth/ASWebAuthenticationSession+.swift @@ -43,8 +43,8 @@ extension ASWebAuthenticationSession { } } -final class DefaultPresentationContext: NSObject, ASWebAuthenticationPresentationContextProviding { - func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { +@MainActor public final class DefaultPresentationContext: NSObject, ASWebAuthenticationPresentationContextProviding { + public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { #if os(macOS) ASPresentationAnchor() #else diff --git a/Sources/OAuth/OAuthDelegate.swift b/Sources/OAuth/OAuthDelegate.swift index cd664f57..5fda52b1 100644 --- a/Sources/OAuth/OAuthDelegate.swift +++ b/Sources/OAuth/OAuthDelegate.swift @@ -11,7 +11,7 @@ extension OAuth { let upstream: any NetworkingComponent var system: any OAuthSystem - var presentationContext: (any ASWebAuthenticationPresentationContextProviding) = DefaultPresentationContext() + var presentationContext: (any ASWebAuthenticationPresentationContextProviding)? @Dependency(\.webAuthenticationSession) var webAuthenticationSession @@ -46,6 +46,10 @@ extension OAuth.Delegate: AuthenticationDelegate { codeChallenge: codeChallenge ) + guard let presentationContext else { + throw OAuth.Error.presentationContextNotSet + } + let callbackURL = try await webAuthenticationSession.start( state: state, authorizationURL: url, diff --git a/Sources/OAuth/OAuthError.swift b/Sources/OAuth/OAuthError.swift index f2c7dc84..11f5bf1b 100644 --- a/Sources/OAuth/OAuthError.swift +++ b/Sources/OAuth/OAuthError.swift @@ -3,6 +3,7 @@ import Foundation extension OAuth { public enum Error: Swift.Error, Equatable { case oauthNotInstalled + case presentationContextNotSet case invalidAuthorizationEndpoint(String) case invalidTokenEndpoint(String) diff --git a/Tests/OAuthTests/OAuthDelegateTests.swift b/Tests/OAuthTests/OAuthDelegateTests.swift index c4d92dd5..73cd31f3 100644 --- a/Tests/OAuthTests/OAuthDelegateTests.swift +++ b/Tests/OAuthTests/OAuthDelegateTests.swift @@ -43,6 +43,11 @@ final class OAuthDelegateTests: OAuthTestCase { .server(authenticationMethod: .stub) .authenticated(oauth: stub) + // Configure Network + try await network.stubOAuthSystem { + await $0.set(presentationContext: DefaultPresentationContext()) + } + // Make a request to protected resource var request = HTTPRequestData(path: "/protected-resource") request.authenticationMethod = .stub diff --git a/Tests/OAuthTests/StubOAuthSystem.swift b/Tests/OAuthTests/StubOAuthSystem.swift index b5ec66e8..ad3ef756 100644 --- a/Tests/OAuthTests/StubOAuthSystem.swift +++ b/Tests/OAuthTests/StubOAuthSystem.swift @@ -21,7 +21,7 @@ struct StubOAuthSystem: StandardOAuthSystem { extension NetworkingComponent { func stubOAuthSystem( - perform: (any OAuthProxy) async throws -> ReturnValue + perform: @MainActor (any OAuthProxy) async throws -> ReturnValue ) async throws -> ReturnValue { try await oauth(of: StubOAuthSystem.Credentials.self, perform: perform) }