Skip to content

Commit ebc14a8

Browse files
authored
chore: kickoff release
2 parents 2f61728 + c7e9f58 commit ebc14a8

File tree

11 files changed

+182
-15
lines changed

11 files changed

+182
-15
lines changed

AmplifyPlugins.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Pod::Spec.new do |s|
3636

3737
s.subspec 'AWSAPIPlugin' do |ss|
3838
ss.source_files = 'AmplifyPlugins/API/AWSAPICategoryPlugin/**/*.swift'
39-
ss.dependency 'AppSyncRealTimeClient', "~> 1.8"
39+
ss.dependency 'AppSyncRealTimeClient', "~> 2.0"
4040
end
4141

4242
s.subspec 'AWSCognitoAuthPlugin' do |ss|

AmplifyPlugins/API/APICategoryPlugin.xcodeproj/project.pbxproj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
21A4F98F25A7BF9E00E1047D /* AppSyncListResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A4F98E25A7BF9E00E1047D /* AppSyncListResponseTests.swift */; };
7171
21A90541261644F700EC141D /* GraphQLScalarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A90540261644F700EC141D /* GraphQLScalarTests.swift */; };
7272
21A9054C2616453200EC141D /* GraphQLTestBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A9054B2616453200EC141D /* GraphQLTestBase.swift */; };
73+
21B0AE7F287DEA7F0047C52F /* APIError+Unauthorized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21B0AE7E287DEA7F0047C52F /* APIError+Unauthorized.swift */; };
74+
21B0AE81287DF6840047C52F /* APIError+UnauthorizedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21B0AE80287DF6840047C52F /* APIError+UnauthorizedTests.swift */; };
7375
21D38B9B240C517C00EC2A8D /* AWSOIDCAuthProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21D38B9A240C517C00EC2A8D /* AWSOIDCAuthProvider.swift */; };
7476
21D5286724169E74005186BA /* IAMAuthInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21D5286624169E74005186BA /* IAMAuthInterceptor.swift */; };
7577
21D7A0DF237B54D90057D00D /* AWSGraphQLOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21D7A08D237B54D90057D00D /* AWSGraphQLOperation.swift */; };
@@ -405,6 +407,8 @@
405407
21A4F98E25A7BF9E00E1047D /* AppSyncListResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSyncListResponseTests.swift; sourceTree = "<group>"; };
406408
21A90540261644F700EC141D /* GraphQLScalarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLScalarTests.swift; sourceTree = "<group>"; };
407409
21A9054B2616453200EC141D /* GraphQLTestBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLTestBase.swift; sourceTree = "<group>"; };
410+
21B0AE7E287DEA7F0047C52F /* APIError+Unauthorized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIError+Unauthorized.swift"; sourceTree = "<group>"; };
411+
21B0AE80287DF6840047C52F /* APIError+UnauthorizedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIError+UnauthorizedTests.swift"; sourceTree = "<group>"; };
408412
21D38B9A240C517C00EC2A8D /* AWSOIDCAuthProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AWSOIDCAuthProvider.swift; sourceTree = "<group>"; };
409413
21D5286624169E74005186BA /* IAMAuthInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAMAuthInterceptor.swift; sourceTree = "<group>"; };
410414
21D7A08D237B54D90057D00D /* AWSGraphQLOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AWSGraphQLOperation.swift; sourceTree = "<group>"; };
@@ -903,15 +907,16 @@
903907
21D7A08B237B54D90057D00D /* AWSAPICategoryPlugin */ = {
904908
isa = PBXGroup;
905909
children = (
910+
21B0AE7E287DEA7F0047C52F /* APIError+Unauthorized.swift */,
906911
219F7B1B25BF92C6007107D3 /* AWSAPIPlugin.md */,
907912
21D7A09A237B54D90057D00D /* AWSAPIPlugin.swift */,
908913
6B382B442538E53700906593 /* AWSAPIPlugin+APIAuthProviderFactoryBehavior.swift */,
914+
211A81DC27176C7300C5483D /* AWSAPIPlugin+AuthInformation.swift */,
909915
21D7A098237B54D90057D00D /* AWSAPIPlugin+Configure.swift */,
910916
21D7A0B1237B54D90057D00D /* AWSAPIPlugin+GraphQLBehavior.swift */,
911917
21D7A099237B54D90057D00D /* AWSAPIPlugin+InterceptorBehavior.swift */,
912918
FA8EE784238632620097E4F1 /* AWSAPIPlugin+Log.swift */,
913919
6B33897123AAD94800561E5B /* AWSAPIPlugin+Reachability.swift */,
914-
211A81DC27176C7300C5483D /* AWSAPIPlugin+AuthInformation.swift */,
915920
21D7A096237B54D90057D00D /* AWSAPIPlugin+Resettable.swift */,
916921
21D7A0D0237B54D90057D00D /* AWSAPIPlugin+RESTBehavior.swift */,
917922
21D7A0D1237B54D90057D00D /* AWSAPIPlugin+URLSessionBehaviorDelegate.swift */,
@@ -1157,6 +1162,7 @@
11571162
B4DFA5BE237A611D0013E17B /* AWSAPICategoryPluginTests */ = {
11581163
isa = PBXGroup;
11591164
children = (
1165+
21B0AE80287DF6840047C52F /* APIError+UnauthorizedTests.swift */,
11601166
211A81FE271851B000C5483D /* AWSAPICategoryPlugin+AuthInformationTests.swift */,
11611167
B4DFA5DE237A611D0013E17B /* AWSAPICategoryPlugin+ConfigureTests.swift */,
11621168
B4DFA5CC237A611D0013E17B /* AWSAPICategoryPlugin+GraphQLBehaviorTests.swift */,
@@ -2519,6 +2525,7 @@
25192525
6B33897023AABF1800561E5B /* NetworkReachability.swift in Sources */,
25202526
21D7A0FE237B54D90057D00D /* URLSessionDataTaskBehavior.swift in Sources */,
25212527
76148E0925D896EA007F3F21 /* URLComponents+sigv4Encoding.swift in Sources */,
2528+
21B0AE7F287DEA7F0047C52F /* APIError+Unauthorized.swift in Sources */,
25222529
21A4F94C25A7ACE600E1047D /* GraphQLRequest+toListQuery.swift in Sources */,
25232530
216449482587E92B00C548A5 /* GraphQLResponseDecoder.swift in Sources */,
25242531
21D7A0E5237B54D90057D00D /* AWSAPICategoryPluginConfiguration.swift in Sources */,
@@ -2556,6 +2563,7 @@
25562563
B4DFA5E1237A611D0013E17B /* MockURLSessionTask.swift in Sources */,
25572564
FAA7A5AA24C0E01500CA863F /* AWSGraphQLSubscriptionOperationCancelTests.swift in Sources */,
25582565
211BEDFB25E59DC8004F367A /* AWSHTTPURLResponseTests.swift in Sources */,
2566+
21B0AE81287DF6840047C52F /* APIError+UnauthorizedTests.swift in Sources */,
25592567
B4DFA5F8237A611D0013E17B /* AWSAPICategoryPlugin+ConfigureTests.swift in Sources */,
25602568
B4DFA5F1237A611D0013E17B /* AWSAPICategoryPlugin+URLSessionBehaviorDelegateTests.swift in Sources */,
25612569
B4DFA5E7237A611D0013E17B /* AWSAPICategoryPlugin+InterceptorBehaviorTests.swift in Sources */,
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import Amplify
9+
import AppSyncRealTimeClient
10+
11+
extension APIError {
12+
13+
static let UnauthorizedMessageString: String = "Unauthorized"
14+
15+
/// By default, this consolidates unauthorized error scenarios coming from `APIError.httpStatusError` and
16+
/// `APIError.operationError`. For `.httpStatusError`, this checks if the status code is 401 or 403. For
17+
/// `.operationError`, this checks if the error description contains "Unauthorized".
18+
///
19+
/// **Warning** Customized server responses that indicate unauthorized may not match the internal mapping done
20+
/// in this API and return `false`. Check APIError enum directly or create your own `UnauthorizedDeterming` rule,
21+
/// for example:
22+
/// ```
23+
/// static let customRule = UnauthorizedDetermining { error in
24+
/// // Your custom logic to determine if `error` is unauthorized.
25+
/// // return `true` or `false`.
26+
/// }
27+
/// ```
28+
///
29+
/// - Parameter rule: Used to determine if the `APIError` is an unauthorized error.
30+
/// - Returns: `true` if unauthorized error, `false` otherwise
31+
public func isUnauthorized(rule: UnauthorizedDetermining = .default) -> Bool {
32+
rule.isUnauthorized(self)
33+
}
34+
35+
public struct UnauthorizedDetermining {
36+
let isUnauthorized: (APIError) -> Bool
37+
38+
public init(isUnauthenticated: @escaping (APIError) -> Bool) {
39+
self.isUnauthorized = isUnauthenticated
40+
}
41+
42+
public static let `default` = UnauthorizedDetermining { error in
43+
error.containsUnauthorizedMessageString || error.is401or403
44+
}
45+
}
46+
47+
private var is401or403: Bool {
48+
switch self {
49+
case .httpStatusError(let statusCode, _):
50+
return statusCode == 401 || statusCode == 403
51+
default:
52+
return false
53+
}
54+
}
55+
56+
private var containsUnauthorizedMessageString: Bool {
57+
switch self {
58+
case .operationError(let errorDescription, _, _):
59+
return errorDescription.range(of: APIError.UnauthorizedMessageString, options: .caseInsensitive) != nil
60+
default: return false
61+
}
62+
}
63+
}

AmplifyPlugins/API/AWSAPICategoryPlugin/Operation/AWSGraphQLSubscriptionOperation.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,36 @@ final public class AWSGraphQLSubscriptionOperation<R: Decodable>: GraphQLSubscri
174174
}
175175

176176
private func onSubscriptionFailure(_ error: Error) {
177-
let errorDescription = "Subscription item event failed with error"
177+
var errorDescription = "Subscription item event failed with error"
178178
if case let ConnectionProviderError.subscription(_, payload) = error,
179179
let errors = payload?["errors"] as? AppSyncJSONValue,
180180
let graphQLErrors = try? GraphQLErrorDecoder.decodeAppSyncErrors(errors) {
181+
182+
if graphQLErrors.hasUnauthorizedError() {
183+
errorDescription += ": \(APIError.UnauthorizedMessageString)"
184+
}
185+
181186
let graphQLResponseError = GraphQLResponseError<R>.error(graphQLErrors)
182187
dispatch(result: .failure(APIError.operationError(errorDescription, "", graphQLResponseError)))
183188
finish()
184189
return
190+
} else if case ConnectionProviderError.unauthorized = error {
191+
errorDescription += ": \(APIError.UnauthorizedMessageString)"
185192
}
186193

187194
dispatch(result: .failure(APIError.operationError(errorDescription, "", error)))
188195
finish()
189196
}
197+
}
190198

199+
extension Array where Element == GraphQLError {
200+
func hasUnauthorizedError() -> Bool {
201+
contains { graphQLError in
202+
if case let .string(errorTypeValue) = graphQLError.extensions?["errorType"],
203+
case .unauthorized = AppSyncErrorType(errorTypeValue) {
204+
return true
205+
}
206+
return false
207+
}
208+
}
191209
}

AmplifyPlugins/API/AWSAPICategoryPluginIntegrationTests/GraphQL/GraphQLWithUserPoolIntegrationTests/GraphQLWithUserPoolIntegrationTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,46 @@ class GraphQLWithUserPoolIntegrationTests: XCTestCase {
496496
waitForExpectations(timeout: TestCommonConstants.networkTimeout)
497497
}
498498

499+
/// The user is not signed in so establishing the subscription will fail with an unauthorized error.
500+
func testOnCreateSubscriptionUnauthorized() {
501+
Amplify.Logging.logLevel = .verbose
502+
let connectingInvoked = expectation(description: "Connecting invoked")
503+
let connectedInvoked = expectation(description: "Connection established")
504+
connectedInvoked.isInverted = true
505+
let completedInvoked = expectation(description: "Completed invoked")
506+
let request = GraphQLRequest(document: OnCreateTodoSubscription.document,
507+
variables: nil,
508+
responseType: OnCreateTodoSubscription.Data.self)
509+
let operation = Amplify.API.subscribe(
510+
request: request,
511+
valueListener: { event in
512+
switch event {
513+
case .connection(let state):
514+
switch state {
515+
case .connecting:
516+
connectingInvoked.fulfill()
517+
case .connected:
518+
connectedInvoked.fulfill()
519+
case .disconnected:
520+
break
521+
}
522+
case .data:
523+
break
524+
}
525+
}, completionListener: { event in
526+
switch event {
527+
case .failure(let error):
528+
if error.isUnauthorized() {
529+
completedInvoked.fulfill()
530+
}
531+
case .success:
532+
XCTFail("Unexpected success")
533+
}
534+
})
535+
XCTAssertNotNil(operation)
536+
wait(for: [connectingInvoked, connectedInvoked, completedInvoked], timeout: TestCommonConstants.networkTimeout)
537+
}
538+
499539
/// Given: A successful subscription is created for CreateTodo's
500540
/// When: Call mutate API on CreateTodo
501541
/// Then: The subscription handler is called and Todo object is returned
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import XCTest
9+
10+
@testable import Amplify
11+
@testable import AWSAPICategoryPlugin
12+
13+
class APIErrorUnauthorizedTests: XCTestCase {
14+
15+
func testAPIErrorUnauthorized() throws {
16+
let apiError = APIError.operationError("Unauthorized", "", nil)
17+
18+
XCTAssertTrue(apiError.isUnauthorized())
19+
}
20+
21+
func testAPIErrorUnauthorizedLowerCase() throws {
22+
let apiError = APIError.operationError("unauthorized", "", nil)
23+
24+
XCTAssertTrue(apiError.isUnauthorized())
25+
}
26+
27+
func testAPIErrorHTTPStatus401() throws {
28+
let apiError = APIError.httpStatusError(401, .init())
29+
30+
XCTAssertTrue(apiError.isUnauthorized())
31+
}
32+
33+
func testAPIErrorHTTPStatus403() throws {
34+
let apiError = APIError.httpStatusError(403, .init())
35+
36+
XCTAssertTrue(apiError.isUnauthorized())
37+
}
38+
}

AmplifyPlugins/API/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ include_build_tools!
88
target 'AWSAPICategoryPlugin' do
99
pod 'Amplify', :path => '../../'
1010
pod 'AWSPluginsCore', :path => '../../'
11-
pod "AppSyncRealTimeClient", "~> 1.8"
11+
pod "AppSyncRealTimeClient", "~> 2.0"
1212

1313
target "AWSAPICategoryPluginTests" do
1414
inherit! :complete

AmplifyPlugins/API/Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ PODS:
1919
- AWSMobileClient (~> 2.27.0)
2020
- AWSPluginsCore (= 1.26.2)
2121
- CwlPreconditionTesting (~> 2.0)
22-
- AppSyncRealTimeClient (1.10.0):
22+
- AppSyncRealTimeClient (2.0.0):
2323
- Starscream (~> 4.0.4)
2424
- AWSAuthCore (2.27.10):
2525
- AWSCore (= 2.27.10)
@@ -54,7 +54,7 @@ DEPENDENCIES:
5454
- Amplify (from `../../`)
5555
- AmplifyPlugins/AWSCognitoAuthPlugin (from `../../`)
5656
- AmplifyTestCommon (from `../../`)
57-
- AppSyncRealTimeClient (~> 1.8)
57+
- AppSyncRealTimeClient (~> 2.0)
5858
- AWSPluginsCore (from `../../`)
5959
- CwlPreconditionTesting (from `https://github.com/mattgallagher/CwlPreconditionTesting.git`, tag `2.1.0`)
6060
- SwiftFormat/CLI (= 0.44.17)
@@ -98,7 +98,7 @@ SPEC CHECKSUMS:
9898
Amplify: a4747a22276b4994cfdb29ea8cdbe6eed7964e9f
9999
AmplifyPlugins: c5af5605be693b8c21afa5e69a8f787f02f55165
100100
AmplifyTestCommon: 20bb0ea2535f69ede737d37bb4fcc7a387b9b15d
101-
AppSyncRealTimeClient: 656ab4215e05f6ca47fe6d8c73f416d9984a8aac
101+
AppSyncRealTimeClient: 186ce6451db2081ccd3f8f454b109c5e4e7025b1
102102
AWSAuthCore: ea9baff143a5ff4a98cea3954b006cedc96cd47e
103103
AWSCognitoIdentityProvider: 7ef13d7a86298db707165208f01b92997cc3b5af
104104
AWSCognitoIdentityProviderASF: d745c40a37815ef1c547f9677145d4e522f582f3
@@ -114,6 +114,6 @@ SPEC CHECKSUMS:
114114
SwiftFormat: 3b5caa6389b2b9adbc00e133b3ccc8c6e687a6a4
115115
SwiftLint: f80f1be7fa96d30e0aa68e58d45d4ea1ccaac519
116116

117-
PODFILE CHECKSUM: 54e87158e45936fe60756d4a417b89eb64ea1c51
117+
PODFILE CHECKSUM: 2a9177ccb9833844ad436a0c7c9e5768a7ab8868
118118

119119
COCOAPODS: 1.11.3

AmplifyPlugins/DataStore/Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ PODS:
33
- Amplify/Default (= 1.26.2)
44
- Amplify/Default (1.26.2)
55
- AmplifyPlugins/AWSAPIPlugin (1.26.2):
6-
- AppSyncRealTimeClient (~> 1.8)
6+
- AppSyncRealTimeClient (~> 2.0)
77
- AWSCore (~> 2.27.0)
88
- AWSPluginsCore (= 1.26.2)
99
- AmplifyPlugins/AWSCognitoAuthPlugin (1.26.2):
@@ -23,7 +23,7 @@ PODS:
2323
- AWSMobileClient (~> 2.27.0)
2424
- AWSPluginsCore (= 1.26.2)
2525
- CwlPreconditionTesting (~> 2.0)
26-
- AppSyncRealTimeClient (1.10.0):
26+
- AppSyncRealTimeClient (2.0.0):
2727
- Starscream (~> 4.0.4)
2828
- AWSAuthCore (2.27.10):
2929
- AWSCore (= 2.27.10)
@@ -106,9 +106,9 @@ CHECKOUT OPTIONS:
106106

107107
SPEC CHECKSUMS:
108108
Amplify: a4747a22276b4994cfdb29ea8cdbe6eed7964e9f
109-
AmplifyPlugins: c5af5605be693b8c21afa5e69a8f787f02f55165
109+
AmplifyPlugins: 7e91dfcbde64a7a12a816a594a73b3839880488c
110110
AmplifyTestCommon: 20bb0ea2535f69ede737d37bb4fcc7a387b9b15d
111-
AppSyncRealTimeClient: 656ab4215e05f6ca47fe6d8c73f416d9984a8aac
111+
AppSyncRealTimeClient: 186ce6451db2081ccd3f8f454b109c5e4e7025b1
112112
AWSAuthCore: ea9baff143a5ff4a98cea3954b006cedc96cd47e
113113
AWSCognitoIdentityProvider: 7ef13d7a86298db707165208f01b92997cc3b5af
114114
AWSCognitoIdentityProviderASF: d745c40a37815ef1c547f9677145d4e522f582f3

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)