From cf7119da27095f7e420354ff3fd5cf4ba9393e03 Mon Sep 17 00:00:00 2001 From: AWS Date: Fri, 2 Jun 2017 07:38:29 +0000 Subject: [PATCH] The AWS Mobile SDK for iOS 2.5.8. --- AWSAPIGateway.podspec | 4 +- AWSAPIGateway/AWSAPIGatewayClient.m | 2 +- AWSAPIGateway/Info.plist | 2 +- AWSAutoScaling.podspec | 4 +- AWSAutoScaling/AWSAutoScalingService.m | 40 +- AWSAutoScaling/Info.plist | 2 +- AWSAutoScalingTests/AWSAutoScalingTests.m | 7 +- AWSCloudWatch.podspec | 4 +- AWSCloudWatch/AWSCloudWatchService.m | 40 +- AWSCloudWatch/Info.plist | 2 +- AWSCloudWatchTests/AWSCloudWatchTests.m | 5 +- AWSCognito.podspec | 4 +- AWSCognito/AWSCognitoService.m | 4 +- .../CognitoSync/AWSCognitoSyncService.m | 5 +- AWSCognito/Info.plist | 2 +- AWSCognitoAuth.podspec | 18 + AWSCognitoAuth/AWSCognitoAuth.h | 256 +++ AWSCognitoAuth/AWSCognitoAuth.m | 817 ++++++++++ AWSCognitoAuth/Info.plist | 26 + .../Internal/AWSCognitoAuth_Internal.h | 30 + .../AWSCognitoAuthUICKeyChainStore.h | 281 ++++ .../AWSCognitoAuthUICKeyChainStore.m | 1388 +++++++++++++++++ .../Internal/UICKeyChainStore/LICENSE | 9 + .../Internal/UICKeyChainStore/README.md | 543 +++++++ AWSCognitoAuthTests/AWSCognitoAuthTests.m | 24 + AWSCognitoAuthTests/Info.plist | 39 + .../AWSCognitoAuthUnitTests.m | 34 + AWSCognitoAuthUnitTests/Info.plist | 24 + AWSCognitoIdentityProvider.podspec | 4 +- .../AWSCognitoIdentityUserPool.m | 2 +- .../AWSCognitoIdentityProviderService.m | 5 +- AWSCognitoIdentityProvider/Info.plist | 2 +- AWSCognitoSync.podspec | 4 +- AWSCognitoTests/CognitoTestUtils.m | 9 +- AWSCore.podspec | 2 +- .../AWSCognitoIdentityService.m | 3 +- AWSCore/Info.plist | 2 +- AWSCore/STS/AWSSTSService.m | 38 +- AWSCore/Service/AWSService.m | 2 +- AWSDynamoDB.podspec | 4 +- AWSDynamoDB/AWSDynamoDBService.m | 5 +- AWSDynamoDB/Info.plist | 2 +- AWSEC2.podspec | 4 +- AWSEC2/AWSEC2Service.m | 5 +- AWSEC2/Info.plist | 2 +- AWSElasticLoadBalancing.podspec | 4 +- .../AWSElasticLoadBalancingService.m | 40 +- AWSElasticLoadBalancing/Info.plist | 2 +- .../AWSElasticLoadBalancingTests.m | 3 + AWSIoT.podspec | 4 +- AWSIoT/AWSIoTDataManager.h | 2 +- AWSIoT/AWSIoTDataManager.m | 8 +- AWSIoT/AWSIoTDataService.h | 2 +- AWSIoT/AWSIoTDataService.m | 5 +- AWSIoT/AWSIoTService.m | 5 +- AWSIoT/Info.plist | 2 +- AWSKMS.podspec | 4 +- AWSKMS/AWSKMSService.m | 5 +- AWSKMS/Info.plist | 2 +- AWSKinesis.podspec | 4 +- AWSKinesis/AWSFirehoseService.m | 5 +- AWSKinesis/AWSKinesisService.m | 5 +- AWSKinesis/Info.plist | 2 +- AWSLambda.podspec | 4 +- AWSLambda/AWSLambdaService.m | 3 +- AWSLambda/Info.plist | 2 +- AWSLex.podspec | 4 +- AWSLex/AWSLexInteractionKit.m | 2 +- AWSLex/AWSLexService.m | 5 +- AWSLex/Info.plist | 2 +- AWSLogs.podspec | 4 +- AWSLogs/AWSLogsService.m | 5 +- AWSLogs/Info.plist | 2 +- AWSMachineLearning.podspec | 4 +- .../AWSMachineLearningService.m | 2 +- AWSMachineLearning/Info.plist | 2 +- AWSMobileAnalytics.podspec | 4 +- .../AWSMobileAnalyticsERSService.m | 3 +- AWSMobileAnalytics/Info.plist | 2 +- AWSPinpoint.podspec | 4 +- .../AWSPinpointAnalyticsService.m | 3 +- AWSPinpoint/AWSPinpointConfiguration.h | 10 + AWSPinpoint/AWSPinpointEndpointProfile.h | 6 + AWSPinpoint/AWSPinpointEndpointProfile.m | 42 +- .../AWSPinpointTargetingService.m | 3 +- AWSPinpoint/AWSPinpointTargetingClient.m | 4 +- AWSPinpoint/Info.plist | 2 +- .../AWSPinpointTargetingClientTests.m | 128 +- AWSPolly.podspec | 4 +- AWSPolly/AWSPollyService.m | 5 +- AWSPolly/AWSPollySynthesizeSpeechURLBuilder.m | 2 +- AWSPolly/Info.plist | 2 +- AWSRekognition.podspec | 4 +- AWSRekognition/AWSRekognitionService.m | 5 +- AWSRekognition/Info.plist | 2 +- AWSS3.podspec | 4 +- AWSS3/AWSS3PreSignedURL.m | 2 +- AWSS3/AWSS3Service.m | 2 +- AWSS3/Info.plist | 2 +- AWSSES.podspec | 4 +- AWSSES/AWSSESService.m | 40 +- AWSSES/Info.plist | 2 +- AWSSESTests/AWSSESTests.m | 5 +- AWSSNS.podspec | 4 +- AWSSNS/AWSSNSService.m | 40 +- AWSSNS/Info.plist | 2 +- AWSSNSTests/AWSSNSTests.m | 5 +- AWSSQS.podspec | 4 +- AWSSQS/AWSSQSService.m | 40 +- AWSSQS/Info.plist | 2 +- AWSSQSTests/AWSSQSTests.m | 7 +- AWSSimpleDB.podspec | 4 +- AWSSimpleDB/AWSSimpleDBService.m | 40 +- AWSSimpleDB/Info.plist | 2 +- AWSSimpleDBTests/AWSSimpleDBTests.m | 5 +- AWSiOSSDKv2.podspec | 56 +- AWSiOSSDKv2.xcodeproj/project.pbxproj | 438 +++++- .../xcschemes/AWSCognitoAuth.xcscheme | 137 ++ CHANGELOG.md | 26 +- Scripts/GenerateAppleDocs.sh | 4 +- Scripts/Package.sh | 1 + 121 files changed, 4625 insertions(+), 344 deletions(-) create mode 100644 AWSCognitoAuth.podspec create mode 100644 AWSCognitoAuth/AWSCognitoAuth.h create mode 100644 AWSCognitoAuth/AWSCognitoAuth.m create mode 100644 AWSCognitoAuth/Info.plist create mode 100644 AWSCognitoAuth/Internal/AWSCognitoAuth_Internal.h create mode 100644 AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.h create mode 100644 AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.m create mode 100644 AWSCognitoAuth/Internal/UICKeyChainStore/LICENSE create mode 100644 AWSCognitoAuth/Internal/UICKeyChainStore/README.md create mode 100644 AWSCognitoAuthTests/AWSCognitoAuthTests.m create mode 100644 AWSCognitoAuthTests/Info.plist create mode 100644 AWSCognitoAuthUnitTests/AWSCognitoAuthUnitTests.m create mode 100644 AWSCognitoAuthUnitTests/Info.plist create mode 100644 AWSiOSSDKv2.xcodeproj/xcshareddata/xcschemes/AWSCognitoAuth.xcscheme diff --git a/AWSAPIGateway.podspec b/AWSAPIGateway.podspec index 18a183155c6..2b21745d0cf 100644 --- a/AWSAPIGateway.podspec +++ b/AWSAPIGateway.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'AWSAPIGateway' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSAPIGateway/*.{h,m}' end diff --git a/AWSAPIGateway/AWSAPIGatewayClient.m b/AWSAPIGateway/AWSAPIGatewayClient.m index 30157f4dade..a7bba741deb 100644 --- a/AWSAPIGateway/AWSAPIGatewayClient.m +++ b/AWSAPIGateway/AWSAPIGatewayClient.m @@ -23,7 +23,7 @@ static NSString *const AWSAPIGatewayAPIKeyHeader = @"x-api-key"; -static NSString *const AWSAPIGatewaySDKVersion = @"2.5.7"; +static NSString *const AWSAPIGatewaySDKVersion = @"2.5.8"; static int defaultChunkSize = 1024; diff --git a/AWSAPIGateway/Info.plist b/AWSAPIGateway/Info.plist index d2037249412..18d5c3de538 100644 --- a/AWSAPIGateway/Info.plist +++ b/AWSAPIGateway/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSAutoScaling.podspec b/AWSAutoScaling.podspec index 3456106e15d..a7bfd2d1085 100644 --- a/AWSAutoScaling.podspec +++ b/AWSAutoScaling.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSAutoScaling' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSAutoScaling/*.{h,m}' end diff --git a/AWSAutoScaling/AWSAutoScalingService.m b/AWSAutoScaling/AWSAutoScalingService.m index b050b34579f..053100dbac1 100644 --- a/AWSAutoScaling/AWSAutoScalingService.m +++ b/AWSAutoScaling/AWSAutoScalingService.m @@ -26,7 +26,7 @@ #import "AWSAutoScalingResources.h" static NSString *const AWSInfoAutoScaling = @"AutoScaling"; -static NSString *const AWSAutoScalingSDKVersion = @"2.5.7"; +static NSString *const AWSAutoScalingSDKVersion = @"2.5.8"; @interface AWSAutoScalingResponseSerializer : AWSXMLResponseSerializer @@ -62,23 +62,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSAutoScalingErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSAutoScalingErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSAutoScalingErrorDomain + code:AWSAutoScalingErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -94,7 +95,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSAutoScaling/Info.plist b/AWSAutoScaling/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSAutoScaling/Info.plist +++ b/AWSAutoScaling/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSAutoScalingTests/AWSAutoScalingTests.m b/AWSAutoScalingTests/AWSAutoScalingTests.m index d336b8ed917..25b2e91e48d 100644 --- a/AWSAutoScalingTests/AWSAutoScalingTests.m +++ b/AWSAutoScalingTests/AWSAutoScalingTests.m @@ -89,9 +89,10 @@ -(void)testAttachInstancesFailed { attacheInstancesQuery.autoScalingGroupName = @"invalidGroupName"; //invalid group name [[[autoScaling attachInstances:attacheInstancesQuery] continueWithBlock:^id(AWSTask *task) { - if (task.error == nil) { - XCTFail(@"Expect Error but got nil"); - } + XCTAssertNotNil(task.error, @"Expected ValidationError error not found."); + XCTAssertEqual(task.error.code, 0); + XCTAssertTrue([@"ValidationError" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"Instance ID(s) must be provided" isEqualToString:task.error.userInfo[@"Message"]]); return nil; }]waitUntilFinished]; diff --git a/AWSCloudWatch.podspec b/AWSCloudWatch.podspec index d7b79e594b5..d18b764e300 100644 --- a/AWSCloudWatch.podspec +++ b/AWSCloudWatch.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSCloudWatch' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSCloudWatch/*.{h,m}' end diff --git a/AWSCloudWatch/AWSCloudWatchService.m b/AWSCloudWatch/AWSCloudWatchService.m index 36cf4cd6134..d9b621537da 100644 --- a/AWSCloudWatch/AWSCloudWatchService.m +++ b/AWSCloudWatch/AWSCloudWatchService.m @@ -26,7 +26,7 @@ #import "AWSCloudWatchResources.h" static NSString *const AWSInfoCloudWatch = @"CloudWatch"; -static NSString *const AWSCloudWatchSDKVersion = @"2.5.7"; +static NSString *const AWSCloudWatchSDKVersion = @"2.5.8"; @interface AWSCloudWatchResponseSerializer : AWSXMLResponseSerializer @@ -64,23 +64,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSCloudWatchErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSCloudWatchErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSCloudWatchErrorDomain + code:AWSCloudWatchErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -96,7 +97,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSCloudWatch/Info.plist b/AWSCloudWatch/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSCloudWatch/Info.plist +++ b/AWSCloudWatch/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSCloudWatchTests/AWSCloudWatchTests.m b/AWSCloudWatchTests/AWSCloudWatchTests.m index daeea738d51..661d8ecd604 100644 --- a/AWSCloudWatchTests/AWSCloudWatchTests.m +++ b/AWSCloudWatchTests/AWSCloudWatchTests.m @@ -109,7 +109,10 @@ - (void)testGetMetricStatisticsFailed { statisticsInput.namespace = @""; //namespace is empty [[[cloudWatch getMetricStatistics:statisticsInput] continueWithBlock:^id(AWSTask *task) { - XCTAssertNotNil(task.error, @"Expected MissingParameter error not found."); + XCTAssertNotNil(task.error, @"Expected InvalidParameterCombination error not found."); + XCTAssertEqual(task.error.code, 4); + XCTAssertTrue([@"InvalidParameterCombination" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"At least one of the parameters Statistics and ExtendedStatistics must be specified." isEqualToString:task.error.userInfo[@"Message"]]); return nil; }] waitUntilFinished]; diff --git a/AWSCognito.podspec b/AWSCognito.podspec index db2fda7a483..16fd605d561 100644 --- a/AWSCognito.podspec +++ b/AWSCognito.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSCognito' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Cognito SDK for iOS' s.description = 'Amazon Cognito offers multi device data synchronization with offline access' @@ -13,7 +13,7 @@ Pod::Spec.new do |s| :tag => s.version} s.requires_arc = true s.library = 'sqlite3' - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSCognito/*.{h,m}', 'AWSCognito/**/*.{h,m}' s.public_header_files = 'AWSCognito/*.h', 'AWSCognito/CognitoSync/*.h' s.private_header_files = 'AWSCognito/Fabric/*.h', 'AWSCognito/Internal/*.h' diff --git a/AWSCognito/AWSCognitoService.m b/AWSCognito/AWSCognitoService.m index 967fcfcbb94..f1b9a877525 100644 --- a/AWSCognito/AWSCognitoService.m +++ b/AWSCognito/AWSCognitoService.m @@ -34,7 +34,7 @@ #import "Fabric+FABKits.h" static NSString *const AWSInfoCognito = @"Cognito"; -static NSString *const AWSCognitoSDKVersion = @"2.5.7"; +static NSString *const AWSCognitoSDKVersion = @"2.5.8"; NSString *const AWSCognitoDidStartSynchronizeNotification = @"com.amazon.cognito.AWSCognitoDidStartSynchronizeNotification"; NSString *const AWSCognitoDidEndSynchronizeNotification = @"com.amazon.cognito.AWSCognitoDidEndSynchronizeNotification"; @@ -233,7 +233,7 @@ - (void)wipe { } - (AWSTask *> *)refreshDatasetMetadata { - return [[[self.cognitoCredentialsProvider getIdentityId] continueWithBlock:^id(AWSTask *task) { + return [[[self.cognitoCredentialsProvider credentials] continueWithBlock:^id(AWSTask *task) { if (task.error) { return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoErrorDomain code:AWSCognitoAuthenticationFailed userInfo:nil]]; } diff --git a/AWSCognito/CognitoSync/AWSCognitoSyncService.m b/AWSCognito/CognitoSync/AWSCognitoSyncService.m index 94423007450..396d2a74f4c 100644 --- a/AWSCognito/CognitoSync/AWSCognitoSyncService.m +++ b/AWSCognito/CognitoSync/AWSCognitoSyncService.m @@ -26,7 +26,7 @@ #import "AWSCognitoSyncResources.h" static NSString *const AWSInfoCognitoSync = @"CognitoSync"; -static NSString *const AWSCognitoSyncSDKVersion = @"2.5.7"; +static NSString *const AWSCognitoSyncSDKVersion = @"2.5.8"; @interface AWSCognitoSyncResponseSerializer : AWSJSONResponseSerializer @@ -106,7 +106,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSCognito/Info.plist b/AWSCognito/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSCognito/Info.plist +++ b/AWSCognito/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSCognitoAuth.podspec b/AWSCognitoAuth.podspec new file mode 100644 index 00000000000..bf667978e8c --- /dev/null +++ b/AWSCognitoAuth.podspec @@ -0,0 +1,18 @@ +Pod::Spec.new do |s| + s.name = 'AWSCognitoAuth' + s.version = '2.5.8' + s.summary = 'Amazon Cognito Auth SDK for iOS (Beta)' + + s.description = 'Amazon Cognito Auth enables sign up and authentication of your end users via a hosted UI' + + s.homepage = 'http://aws.amazon.com/mobile/sdk' + s.license = 'Apache License, Version 2.0' + s.author = { 'Amazon Web Services' => 'amazonwebservices' } + s.platform = :ios, '9.0' + s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', + :tag => s.version} + s.requires_arc = true + s.source_files = 'AWSCognitoAuth/**/*.{h,m,c}' + s.public_header_files = 'AWSCognitoAuth/*.h' + s.private_header_files = 'AWSCognitoAuth/Internal/*.h' +end diff --git a/AWSCognitoAuth/AWSCognitoAuth.h b/AWSCognitoAuth/AWSCognitoAuth.h new file mode 100644 index 00000000000..bd7032b0ff1 --- /dev/null +++ b/AWSCognitoAuth/AWSCognitoAuth.h @@ -0,0 +1,256 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class AWSCognitoAuthUserSession; +@class AWSCognitoAuthUserSessionToken; +@class AWSCognitoAuthConfiguration; + +@protocol AWSCognitoAuthDelegate; + +/** + The error domain for AWSCognitoAuth errors. +
    +
  • AWSCognitoAuthClientErrorUnknown - Unknown error.
  • +
  • AWSCognitoAuthClientErrorUserCanceledOperation - User canceled flow.
  • +
  • AWSCognitoAuthClientErrorLoadingPageFailed - A necessary page failed to load.
  • +
  • AWSCognitoAuthClientErrorBadRequest - A parameter was missing or invalid.
  • +
  • AWSCognitoAuthClientErrorSecurityReason - The security of this request could not be guaranteed.
  • +
  • AWSCognitoAuthClientInvalidAuthenticationDelegate - The AWSCognitoAuthDelegate delegate is not setup or returned an invalid value.
  • +
  • AWSCognitoAuthClientNoIdTokenIssued - If no id token was issued. For future use.
  • +
+ */ +FOUNDATION_EXPORT NSString *const AWSCognitoAuthErrorDomain; + +typedef NS_ENUM(NSInteger, AWSCognitoAuthClientErrorType) { + AWSCognitoAuthClientErrorUnknown = 0, + AWSCognitoAuthClientErrorUserCanceledOperation = -1000, + AWSCognitoAuthClientErrorLoadingPageFailed = -2000, + AWSCognitoAuthClientErrorBadRequest = -3000, + AWSCognitoAuthClientErrorSecurityFailed = -4000, + AWSCognitoAuthClientInvalidAuthenticationDelegate = -5000, + AWSCognitoAuthClientNoIdTokenIssued = -6000 +}; + +typedef void (^AWSCognitoAuthGetSessionBlock)(AWSCognitoAuthUserSession * _Nullable session, NSError * _Nullable error); +typedef void (^AWSCognitoAuthSignOutBlock)(NSError * _Nullable error); + + +/** + A lightweight web-based ui to manage signup/signin of your end users + */ +@interface AWSCognitoAuth : NSObject + +/** + Set this delegate to obtain the current view controller to interact with the end user + */ +@property (nonatomic, strong) id delegate; + +/** + The auth configuration + */ +@property (nonatomic, readonly) AWSCognitoAuthConfiguration *authConfiguration; + +/** + Determines whether there is an active session or not. If the refresh token is expired + the end user will be prompted to authenticate when you call getSession. + */ +@property (nonatomic, readonly, getter=isSignedIn) BOOL signedIn; + +/** + Fetches the Cognito User Pool instance configured in the `info.plist` under `AWS->CognitoUserPool->Default` + @return the default instance for Cognito Auth + */ ++ (instancetype)defaultCognitoAuth; + +/** + Register a managed instance with name forKey and configuration authConfiguration. + @param authConfiguration the auth configuration + @param key the key to register under + */ ++ (void)registerCognitoAuthWithAuthConfiguration:(AWSCognitoAuthConfiguration *)authConfiguration + forKey:(NSString *)key; +/** + Fetch a managed instance with a particular AuthConfiguration. + @param key the key to fetch + @return the CognitoAuth object + */ ++ (instancetype)CognitoAuthForKey:(NSString *)key; + +/** + Unregister a managed instance. + @param key key to remove the object for + */ ++ (void)removeCognitoAuthForKey:(NSString *)key; + +/** + Get a session with id, access and refresh tokens. + @param vc viewController to display the UI on if needed during sign in. + @param completion completion block to invoke on completion + */ +- (void)getSession:(UIViewController *) vc completion: (nullable AWSCognitoAuthGetSessionBlock) completion; + +/** + Get a session with id, access and refresh tokens, use delegate to get view controller. + @param completion completion block to invoke on completion + */ +- (void)getSession: (nullable AWSCognitoAuthGetSessionBlock) completion; + + +/** + Sign out locally and from the server. + @param vc viewController to display the UI on during sign out. + @param completion completion block to invoke on completion + */ +- (void) signOut:(UIViewController *) vc completion: (nullable AWSCognitoAuthSignOutBlock) completion; + +/** + Sign out locally and from the server, use delegate to get view controller. + @param completion completion block to invoke on completion + */ +- (void) signOut: (nullable AWSCognitoAuthSignOutBlock) completion; + + +/** + Method to handle app redirect. Call from AppDelegate application:openURL:options + */ +- (BOOL)application:(UIApplication *)app + openURL:(NSURL *)url + options:(NSDictionary *)options; + + +@end + +/** + Houses all configuration for AWSCognitoAuth + */ +@interface AWSCognitoAuthConfiguration : NSObject + +/** + The app client id + */ +@property (nonatomic, readonly) NSString * appClientId; + +/** + The optional app client secret + */ +@property (nonatomic, readonly) NSString * appClientSecret; + +/** + The scopes + */ +@property (nonatomic, readonly) NSSet * scopes; + +/** + uri to redirect on sign in. Must be configured as a uri scheme in your info.plist + */ +@property (nonatomic, readonly) NSString * signInRedirectUri; + +/** + uri to redirect on sign out. Must be configured as a uri scheme in your info.plist + */ +@property (nonatomic, readonly) NSString * signOutRedirectUri; + +/** + The FQDN of your Cognito endpoint, something like https://mydomain.region.auth.amazoncognito.com + */ +@property (nonatomic, readonly) NSString * webDomain; + + +/** + Configuration object for CognitoAuth + @param appClientId The app client id + @param appClientSecret The optional app client secret + @param scopes Set of scopes to obtain + @param signInRedirectUri uri to redirect on sign in. Must be configured as a uri scheme in your info.plist + @param signOutRedirectUri uri to redirect on sign out. Must be configured as a uri scheme in your info.plist + @param webDomain The FQDN of your Cognito endpoint, something like https://mydomain.region.auth.amazoncognito.com + */ +- (instancetype)initWithAppClientId:(NSString *) appClientId + appClientSecret:(nullable NSString *) appClientSecret + scopes:(NSSet *) scopes + signInRedirectUri:(NSString *) signInRedirectUri + signOutRedirectUri:(NSString *) signOutRedirectUri + webDomain:(NSString *) webDomain; +@end + + +/** + A User session. Encapsulates all tokens (id, access and refresh tokens) for a user. + */ +@interface AWSCognitoAuthUserSession : NSObject + +/** + The id token + **/ +@property (nonatomic, readonly, nullable) AWSCognitoAuthUserSessionToken * idToken; + +/** + The access token + **/ +@property (nonatomic, readonly, nullable) AWSCognitoAuthUserSessionToken * accessToken; + +/** + The refresh token + **/ +@property (nonatomic, readonly, nullable) AWSCognitoAuthUserSessionToken * refreshToken; + +/** + Date this session expires + */ +@property (nonatomic, readonly, nullable) NSDate * expirationTime; + +/** + Username for this session + */ +@property (nonatomic, readonly, nullable) NSString * username; + +@end + +/** + A JWT session token. + */ +@interface AWSCognitoAuthUserSessionToken : NSObject + +/** + The raw jwt token string + */ +@property (nonatomic, readonly) NSString * tokenString; + +/** + The claims from the token + **/ +@property (nonatomic, readonly) NSDictionary * claims; + +@end + + +/** + For obtaining current view controller to interact with the end user + */ +@protocol AWSCognitoAuthDelegate +/** + Get view controller to display user authentication on top of. + */ +- (UIViewController *) getViewController; +@end + + +NS_ASSUME_NONNULL_END + diff --git a/AWSCognitoAuth/AWSCognitoAuth.m b/AWSCognitoAuth/AWSCognitoAuth.m new file mode 100644 index 00000000000..f16fabe5751 --- /dev/null +++ b/AWSCognitoAuth/AWSCognitoAuth.m @@ -0,0 +1,817 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import "AWSCognitoAuth_Internal.h" +#import +#import +#import + +NSString *const AWSCognitoAuthErrorDomain = @"com.amazon.cognito.AWSCognitoAuthErrorDomain"; + +@interface AWSCognitoAuth() + +@property (atomic, readwrite) AWSCognitoAuthGetSessionBlock getSessionBlock; +@property (atomic, readwrite) AWSCognitoAuthSignOutBlock signOutBlock; +@property (atomic, readwrite) NSError * getSessionError; +@property (atomic, readwrite) NSError * signOutError; + +@property (atomic, readwrite) SFSafariViewController *svc; +@property (atomic, readwrite) UIViewController * pvc; +@property (atomic, readwrite) NSString * state; +@property (atomic, readwrite) NSString * proofKey; +@property (atomic, readwrite) NSString * proofKeyHash; +@property (atomic, readwrite) NSMutableData * responseData; + +@property (nonatomic, strong) NSOperationQueue * getSessionQueue; +@property (nonatomic, strong) NSOperationQueue * signOutQueue; + +@end + +@implementation AWSCognitoAuth + +static NSString *const AWSCognitoAuthSDKVersion = @"2.5.8"; + + +static NSMutableDictionary *_instanceDictionary = nil; +static dispatch_queue_t _dispatchQueue = nil; + +static NSString *const AWSInfoCognitoAuth = @"CognitoUserPool"; //Consistent with AWSCognitoIdentityUserPool name +NSString *const AWSCognitoAuthUserAccessToken = @"accessToken"; //Consistent with AWSCognitoIdentityUserPool name +static const NSString * AWSCognitoAuthUserIdToken = @"idToken"; //Consistent with AWSCognitoIdentityUserPool name +static const NSString * AWSCognitoAuthUserRefreshToken = @"refreshToken"; //Consistent with AWSCognitoIdentityUserPool name +static const NSString * AWSCognitoAuthUserScopes = @"scopes"; +static const NSString * AWSCognitoAuthUserTokenExpiration = @"tokenExpiration"; //Consistent with AWSCognitoIdentityUserPool name +static NSString * AWSCognitoAuthUserPoolCurrentUser = @"currentUser"; //Consistent with AWSCognitoIdentityUserPool name +static NSString *const AWSCognitoAuthAppClientId = @"CognitoUserPoolAppClientId"; //Consistent with AWSCognitoIdentityUserPool name +static NSString *const AWSCognitoAuthAppClientSecret = @"CognitoUserPoolAppClientSecret"; //Consistent with AWSCognitoIdentityUserPool name +static NSString *const AWSCognitoAuthWebDomain = @"CognitoAuthWebDomain"; +static NSString *const AWSCognitoAuthScopes = @"CognitoAuthScopes"; +static NSString *const AWSCognitoAuthSignInRedirectUri = @"CognitoAuthSignInRedirectUri"; +static NSString *const AWSCognitoAuthSignOutRedirectUri = @"CognitoAuthSignOutRedirectUri"; +static NSString *const AWSCognitoAuthUnknown = @"Unknown"; + + +#pragma mark init and configuration + ++ (instancetype)defaultCognitoAuth { + static AWSCognitoAuth *_defaultAuth = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + //get config from Info.plist + NSDictionary * infoDictionary = [[NSBundle mainBundle] infoDictionary][@"AWS"][AWSInfoCognitoAuth][@"Default"]; + NSString *appClientId = infoDictionary[AWSCognitoAuthAppClientId]; + NSString *appClientSecret = infoDictionary[AWSCognitoAuthAppClientSecret]; + NSString *webDomain = infoDictionary[AWSCognitoAuthWebDomain]; + NSSet *scopes = infoDictionary[AWSCognitoAuthScopes]!=nil?[NSSet setWithArray:infoDictionary[AWSCognitoAuthScopes]]:nil; + NSString *signInRedirectUri = infoDictionary[AWSCognitoAuthSignInRedirectUri]; + NSString *signOutRedirectUri = infoDictionary[AWSCognitoAuthSignOutRedirectUri]; + + if (appClientId && webDomain && scopes && signOutRedirectUri && signInRedirectUri) { + AWSCognitoAuthConfiguration *authConfiguration = [[AWSCognitoAuthConfiguration alloc] initWithAppClientId:appClientId + appClientSecret:appClientSecret + scopes:scopes + signInRedirectUri:signInRedirectUri + signOutRedirectUri:signOutRedirectUri + webDomain:webDomain]; + _defaultAuth = [[AWSCognitoAuth alloc] initWithConfiguration:authConfiguration]; + } else { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"The service configuration is `nil`. You need to configure `Info.plist` before using this method." + userInfo:nil]; + } + }); + + return _defaultAuth; +} + ++ (void)registerCognitoAuthWithAuthConfiguration:(AWSCognitoAuthConfiguration *) authConfiguration + forKey:(NSString *)key { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _instanceDictionary = [NSMutableDictionary new]; + _dispatchQueue = dispatch_queue_create("com.amazonaws.AWSCognitoAuthDictionary", DISPATCH_QUEUE_SERIAL); + }); + AWSCognitoAuth *cognitoAuth = [[AWSCognitoAuth alloc] initWithConfiguration:authConfiguration]; + [self setObject:cognitoAuth + forKey:key]; +} + ++ (instancetype)CognitoAuthForKey:(NSString *)key { + return [self objectForKey:key]; +} + ++ (void)removeCognitoAuthForKey:(NSString *)key { + [self removeObjectForKey:key]; +} + +- (instancetype)init { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"`- init` is not a valid initializer. Use `+ defaultCognitoAuth` or `+ CognitoAuthForKey:` instead." + userInfo:nil]; + return nil; +} + +// Internal init method +- (instancetype)initWithConfiguration:(AWSCognitoAuthConfiguration *)authConfiguration; { + if (self = [super init]) { + _signOutQueue = [NSOperationQueue new]; + _getSessionQueue = [NSOperationQueue new]; + _authConfiguration = [authConfiguration copy]; + _keychain = [AWSCognitoAuthUICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@", [NSBundle mainBundle].bundleIdentifier, @"AWSCognitoIdentityUserPool"]]; //Consistent with AWSCognitoIdentityUserPool + } + return self; +} + +- (BOOL) isSignedIn { + NSString * keyChainNamespace = [self keyChainNamespaceClientId: [self currentUsername]]; + NSString * refreshTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserRefreshToken]; + NSString * refreshToken = self.keychain[refreshTokenKey]; + return refreshToken!=nil; +} + +#pragma mark sign in + +- (void)getSession:(AWSCognitoAuthGetSessionBlock) completion { + [self enqueueGetSession:nil completion:completion]; +} + +- (void)getSession:(UIViewController *) vc completion: (AWSCognitoAuthGetSessionBlock) completion { + [self enqueueGetSession:vc completion:completion]; +} + +/** + Adds another getSession operation to the serialized queue of getSession requests + */ +- (void)enqueueGetSession:(nullable UIViewController *) vc completion: (AWSCognitoAuthGetSessionBlock) completion { + __block NSOperation *getSessionOperation = [NSBlockOperation blockOperationWithBlock:^{ + [self getSessionInternal:vc completion:completion]; + if(getSessionOperation.isCancelled){ + [self completeGetSession:nil error:self.getSessionError]; + } + }]; + + [self.getSessionQueue addOperation:getSessionOperation]; +} + +/** + Cleanup resources from the sign in attempt + */ +- (void) cleanupSignIn { + self.getSessionBlock = nil; + self.proofKey = nil; + self.state = nil; + self.proofKeyHash = nil; + self.pvc = nil; + self.responseData = nil; +} + +/** + Launch the sign in ui on the provided viewcontroller + */ +- (void) launchSignInVC: (UIViewController *) vc { + NSString *url = [NSString stringWithFormat:@"%@/authorize?response_type=code&client_id=%@&state=%@&redirect_uri=%@&scope=%@&code_challenge=%@&code_challenge_method=S256",self.authConfiguration.webDomain, self.authConfiguration.appClientId, self.state,[self urlEncode:self.authConfiguration.signInRedirectUri], [self urlEncode:[self normalizeScopes]], self.proofKeyHash]; + self.svc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:url] entersReaderIfAvailable:NO]; + self.svc.delegate = self; + self.svc.modalPresentationStyle = UIModalPresentationPopover; + dispatch_async(dispatch_get_main_queue(), ^{ + if(!vc){ + if(!self.delegate){ + [self completeGetSession:nil error:[self getError:@"delegate must be set to a valid AWSCognitoAuthDelegate" code:AWSCognitoAuthClientInvalidAuthenticationDelegate]]; + return; + } + [[self.delegate getViewController] presentViewController:self.svc animated:NO completion:nil]; + }else { + [vc presentViewController:self.svc animated:NO completion:nil]; + } + }); +} + +/** + Check keychain for valid session, if expired or not available, prompt end user via ui + */ +- (void)getSessionInternal: (nullable UIViewController *) vc completion: (AWSCognitoAuthGetSessionBlock) completion { + self.getSessionBlock = completion; + self.state = [[[NSUUID UUID] UUIDString] lowercaseString]; + self.proofKey = [self generateRandom:32]; + self.proofKeyHash = [self calculateSHA256Hash:self.proofKey]; + self.pvc = vc; + + + //check to see if we have valid tokens + NSString * username = [self currentUsername]; + if(username){ + __block NSString * keyChainNamespace = [self keyChainNamespaceClientId: [self currentUsername]]; + NSString * expirationDateKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserTokenExpiration]; + NSString * expirationDate = self.keychain[expirationDateKey]; + NSString * scopesKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserScopes]; + NSString * scopes = self.keychain[scopesKey]; + + if(expirationDate && scopes != nil && [scopes isEqualToString:[self normalizeScopes]]){ + NSDate *expiration = [self dateFromString:expirationDate]; + NSString * refreshTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserRefreshToken]; + NSString * refreshToken = self.keychain[refreshTokenKey]; + + //if the session expires > 5 minutes return it. + if(expiration && [expiration compare:[NSDate dateWithTimeIntervalSinceNow:5 * 60]] == NSOrderedDescending){ + NSString * idTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserIdToken]; + NSString * accessTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserAccessToken]; + AWSCognitoAuthUserSession * session = [[AWSCognitoAuthUserSession alloc] initWithIdToken:self.keychain[idTokenKey] accessToken:self.keychain[accessTokenKey] refreshToken:refreshToken expirationTime:expiration]; + [self completeGetSession:session error:nil]; + return; + } + //else refresh it using the refresh token + else if(refreshToken){ + NSString *url = [NSString stringWithFormat:@"%@/token",self.authConfiguration.webDomain]; + NSString *body = [NSString stringWithFormat:@"grant_type=refresh_token&client_id=%@&refresh_token=%@&redirect_uri=%@",self.authConfiguration.appClientId, refreshToken, self.authConfiguration.signInRedirectUri]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; + [self addHeaders:request]; + request.HTTPMethod = @"POST"; + request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; + [[[NSURLConnection alloc] initWithRequest:request delegate:self] start]; + return; + } + } + } + //if we made it this far, we need the end user to authenticate + [self launchSignInVC: vc]; +} + +/** + Dismiss ui, invoke completion and cleanup a getSession call. + */ +- (void) completeGetSession: (nullable AWSCognitoAuthUserSession *) userSession error:(nullable NSError *) error { + [self dismissSafariVC]; + if(error){ + self.getSessionError = error; + [self.getSessionQueue cancelAllOperations]; + } + if(self.getSessionBlock){ + self.getSessionBlock(userSession, error); + } + + [self cleanupSignIn]; +} + +#pragma mark sign out + +/** + Dismiss ui, invoke completion and cleanup a signOut call. + */ +- (void) completeSignOut:(nullable NSError *) error { + [self dismissSafariVC]; + if(error){ + self.signOutError = error; + [self.signOutQueue cancelAllOperations]; + } + if(self.signOutBlock){ + self.signOutBlock(error); + self.signOutBlock = nil; + } +} + +- (void) signOut: (AWSCognitoAuthSignOutBlock) completion { + if(!self.delegate){ + completion([self getError:@"delegate must be set to a valid AWSCognitoAuthDelegate" code:AWSCognitoAuthClientInvalidAuthenticationDelegate]); + }else { + [self signOut: [self.delegate getViewController] completion:completion]; + } +} + +- (void) signOut: (UIViewController *) vc completion: (AWSCognitoAuthSignOutBlock) completion { + __block NSOperation *signOutOperation = [NSBlockOperation blockOperationWithBlock:^{ + if(signOutOperation.isCancelled){ + completion(self.signOutError); + } + [self signOutInternal:vc completion:completion]; + }]; + [self.signOutQueue addOperation:signOutOperation]; + +} + + +/** + Display ui for signout + */ +- (void) signOutInternal: (UIViewController *) vc completion: (AWSCognitoAuthSignOutBlock) completion { + self.signOutBlock = completion; + NSString *url = [NSString stringWithFormat:@"%@/logout?client_id=%@&logout_uri=%@",self.authConfiguration.webDomain, self.authConfiguration.appClientId, [self urlEncode:self.authConfiguration.signOutRedirectUri]]; + self.svc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:url] entersReaderIfAvailable:NO]; + self.svc.delegate = self; + self.svc.modalPresentationStyle = UIModalPresentationPopover; + dispatch_async(dispatch_get_main_queue(), ^{ + [vc presentViewController:self.svc animated:NO completion:nil]; + }); +} + +/** + Remove user session from keychain + */ +-(void) signOutLocally { + if([self currentUsername]){ + NSArray *keys = self.keychain.allKeys; + NSString *keyChainPrefix = [[self keyChainNamespaceClientId:[self currentUsername]] stringByAppendingString:@"."]; + for (NSString *key in keys) { + //clear tokens associated with this user + if([key hasPrefix:keyChainPrefix]){ + [self.keychain removeItemForKey:key]; + } + } + } +} + +/** + Remove user session from keychain and clear last known username. + */ +-(void) signOutLocallyAndClearLastKnownUser{ + [self signOutLocally]; + [self clearLastKnownUser]; +} + +#pragma mark date conversion + +/** + Obtain a date formatter for this format: yyyy-MM-dd'T'HH:mm:ss'Z' + */ +-(NSDateFormatter *) getDateFormatter { + static NSDateFormatter *_dateFormatter = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _dateFormatter = [NSDateFormatter new]; + _dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; + _dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + _dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'"; + }); + return _dateFormatter; +} + +/** + Convert a string to date + */ +-(NSDate *) dateFromString:(NSString *)string { + return [[self getDateFormatter] dateFromString:string]; +} + +/** + Convert a string to date + */ +-(NSString *) stringValue: (NSDate*) date { + return [[self getDateFormatter] stringFromDate:date]; +} + + + +#pragma mark SFSafariViewController delegate + +/*! @abstract Delegate callback called when the user taps the Done button. Upon this call, the view controller is dismissed modally. */ +- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { + NSError *error = [self getError:@"User cancelled operation" code:AWSCognitoAuthClientErrorUserCanceledOperation]; + if(self.getSessionBlock){ + [self completeGetSession:nil error:error]; + }else { + [self completeSignOut:error]; + } +} + +/*! @abstract Invoked when the initial URL load is complete. + @param didLoadSuccessfully YES if loading completed successfully, NO if loading failed. + @discussion This method is invoked when SFSafariViewController completes the loading of the URL that you pass + to its initializer. It is not invoked for any subsequent page loads in the same SFSafariViewController instance. + */ +- (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully { + if(!didLoadSuccessfully){ + NSError *error = [self getError:@"Loading page failed" code:AWSCognitoAuthClientErrorLoadingPageFailed]; + if(self.getSessionBlock){ + [self completeGetSession:nil error:error]; + }else if(self.signOutBlock){ + [self completeSignOut:error]; + } + } +} + +#pragma PKCE + +/** + Generate a random number of size bytes and base64 encode it with a url safe encoding. + */ +-(NSString *) generateRandom: (int) size { + NSMutableData *data = [NSMutableData dataWithLength:size]; + int result = SecRandomCopyBytes(kSecRandomDefault, size, data.mutableBytes); + + if(result){ + return nil; + } + + return [self urlSafeBase64:[data base64EncodedStringWithOptions:0]]; +} + +/** + Calculate a SHA256 Hash of a string and base64 encode it with a url safe encoding. + */ +-(NSString *) calculateSHA256Hash: (NSString *) string { + NSMutableData *hashOutput = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH]; + if(CC_SHA256([[[string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] mutableCopy] mutableBytes], (CC_LONG)[string lengthOfBytesUsingEncoding:NSASCIIStringEncoding], hashOutput.mutableBytes)){ + return [self urlSafeBase64:[hashOutput base64EncodedStringWithOptions:0]]; + } + return nil; +} + +/** + Make a base64 encoded string url safe + */ +-(NSString *) urlSafeBase64: (NSString *) string { + return [[[string stringByReplacingOccurrencesOfString:@"/" withString:@"_"] stringByReplacingOccurrencesOfString:@"+" withString:@"-"] stringByReplacingOccurrencesOfString:@"=" withString:@""]; +} + +/** + Make a string url safe + **/ +- (NSString *) urlEncode: (NSString *) stringToEncode { + return [stringToEncode stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; +} + + + +- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url + resolvingAgainstBaseURL:NO]; + NSArray* queryItems = [urlComponents queryItems]; + NSMutableDictionary *queryItemsDict = nil; + if(queryItems) { + queryItemsDict = [NSMutableDictionary new]; + + for(NSURLQueryItem * queryItem in queryItems){ + [queryItemsDict setObject:queryItem.value forKey:queryItem.name]; + } + } + if([[url absoluteString] hasPrefix:self.authConfiguration.signInRedirectUri] && queryItemsDict[@"state"] && queryItemsDict[@"code"]){ + //if state doesn't match, abort + if(![self.state isEqualToString:queryItemsDict[@"state"]]){ + [self completeGetSession:nil error:[self getError:@"State code did not match request" code: AWSCognitoAuthClientErrorSecurityFailed]]; + return YES; + } else { + //continue with authorization code request + NSString * code = queryItemsDict[@"code"]; + if(code){ + NSString *url = [NSString stringWithFormat:@"%@/token",self.authConfiguration.webDomain]; + NSString *body = [NSString stringWithFormat:@"grant_type=authorization_code&client_id=%@&code=%@&redirect_uri=%@&code_verifier=%@", + self.authConfiguration.appClientId, code, self.authConfiguration.signInRedirectUri, self.proofKey]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; + request.HTTPMethod = @"POST"; + request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; + [self addHeaders:request]; + [[[NSURLConnection alloc] initWithRequest:request delegate:self] start]; + return YES; + } + } + }else if([[url absoluteString] hasPrefix:self.authConfiguration.signOutRedirectUri]){ + if(queryItemsDict[@"error"]){ + [self completeSignOut:[self getError:queryItemsDict[@"error"] code:AWSCognitoAuthClientErrorBadRequest]]; + }else{ + [self signOutLocallyAndClearLastKnownUser]; + [self completeSignOut:nil]; + } + return YES; + } + return NO; +} + +#pragma mark HTTP header modification + +/** + Add authorization and User-Agent header as appropriate. + */ +-(void) addHeaders: (NSMutableURLRequest *) request { + if(self.authConfiguration.appClientSecret){ + NSString* value = [[[NSString stringWithFormat:@"%@:%@", self.authConfiguration.appClientId, self.authConfiguration.appClientSecret] dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]; + value = [NSString stringWithFormat: @"Basic %@", value]; + [request setValue:value forHTTPHeaderField:@"Authorization"]; + } + [request setValue: [AWSCognitoAuth userAgent] forHTTPHeaderField:@"User-Agent"]; +} + +/** + Dismiss and reap the safari view controller + */ +-(void) dismissSafariVC { + dispatch_async(dispatch_get_main_queue(), ^{ + if(self.svc){ + [self.svc dismissViewControllerAnimated:NO completion:^{ + //clean up vc + self.svc = nil; + }]; + } + }); +} + +#pragma mark NSURLConnection Delegate Methods + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + self.responseData = [[NSMutableData alloc] init]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + [self.responseData appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + NSError * error; + NSDictionary *result = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:&error]; + if(error){ + [self completeGetSession:nil error:[self getError:[error description] code:AWSCognitoAuthClientErrorUnknown]]; + return; + } + else if(result[@"error"]){ + //refresh token has expired, switch to interactive auth + if([@"invalid_grant" isEqualToString:result[@"error"]]){ + [self launchSignInVC:self.pvc]; + return; + } + + [self completeGetSession:nil error:[self getError:result[@"error"] code:AWSCognitoAuthClientErrorUnknown]]; + }else { + AWSCognitoAuthUserSession *userSession = [[AWSCognitoAuthUserSession alloc] initWithIdToken:[result valueForKey:@"id_token"] accessToken:[result valueForKey:@"access_token"] refreshToken:[result valueForKey:@"refresh_token"] expiresIn:[result valueForKey:@"expires_in"]]; + if(!userSession.accessToken){ + [self completeGetSession:nil error: [self getError:@"Tokens not received" code:AWSCognitoAuthClientErrorUnknown]]; + }else{ + [self updateUsernameAndPersistTokens:userSession]; + [self completeGetSession:userSession error:nil]; + } + } +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + [self completeGetSession:nil error:[self getError:error.description code:AWSCognitoAuthClientErrorLoadingPageFailed]]; +} + + +#pragma mark keychain utilities + +- (NSString*) currentUsername { + return self.keychain[[self currentUserKey]]; +} + +- (NSString *) currentUserKey { + return [self keyChainNamespaceClientId:AWSCognitoAuthUserPoolCurrentUser]; +} + +- (void) setCurrentUser:(NSString *) username { + self.keychain[[self currentUserKey]] = username; +} + +- (void) clearLastKnownUser { + NSString * currentUserKey = [self currentUserKey]; + if(currentUserKey){ + [self.keychain removeItemForKey:[self currentUserKey]]; + } +} + +/** + Removes everything from the keychain under this appClientId + */ +- (void) clearAll { + NSArray *keys = self.keychain.allKeys; + NSString *keyChainPrefix = [self keyChainNamespaceClientId:@""]; + for (NSString *key in keys) { + if([key hasPrefix:keyChainPrefix]){ + [self.keychain removeItemForKey:key]; + } + } +} + +- (NSString *) keyChainNamespaceClientId:(NSString *)username { + return [NSString stringWithFormat:@"%@.%@", self.authConfiguration.appClientId, username]; +} + + +/** + * Get a namespaced keychain key given a namespace and key + */ +- (NSString *) keyChainKey: (NSString *) namespace key:(const NSString *) key { + return [NSString stringWithFormat:@"%@.%@", namespace, key]; +} + +/** + Update the username and persist session tokens in the keychain + */ +- (void) updateUsernameAndPersistTokens: (AWSCognitoAuthUserSession *) session { + NSString * keyChainNamespace = [self keyChainNamespaceClientId:session.username]; + NSString * idTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserIdToken]; + + if(session.idToken){ + self.keychain[idTokenKey] = session.idToken.tokenString; + } + if(session.accessToken){ + NSString * accessTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserAccessToken]; + self.keychain[accessTokenKey] = session.accessToken.tokenString; + if(!session.idToken){ + [self.keychain removeItemForKey:idTokenKey]; + } + NSString * scopesKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserScopes]; + self.keychain[scopesKey] = [self normalizeScopes]; + } + if(session.refreshToken){ + NSString * refreshTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserRefreshToken]; + self.keychain[refreshTokenKey] = session.refreshToken.tokenString; + } + if(session.expirationTime){ + NSString * expirationTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoAuthUserTokenExpiration]; + self.keychain[expirationTokenKey] = [self stringValue:session.expirationTime]; + } + [self setCurrentUser:session.username]; +} + +/** + Helper for getting errors + */ +-(NSError *) getError:(NSString *) error code:(AWSCognitoAuthClientErrorType) code { + NSMutableDictionary * errors = [NSMutableDictionary new]; + if(error){ + [errors setObject:error forKey:@"error"]; + } + return [NSError errorWithDomain:AWSCognitoAuthErrorDomain code:code userInfo:errors]; +} + +/** + Sort scopes in lexigraphical order and join them with a space character. + */ +-(NSString*) normalizeScopes { + return [[[self.authConfiguration.scopes allObjects] sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { + NSString * string1 = (NSString *) obj1; + NSString * string2 = (NSString *) obj2; + return [string1 compare:string2]; + }] componentsJoinedByString:@" "]; +} + +#pragma mark instance dictionary + +/** + Get an object from the instanceDictionary + */ ++ (id)objectForKey:(id)aKey { + __block id returnObject = nil; + + dispatch_sync(_dispatchQueue, ^{ + returnObject = [_instanceDictionary objectForKey:aKey]; + }); + + return returnObject; +} + +/** + Remove an object from the instanceDictionary + */ ++ (void)removeObjectForKey:(id)aKey { + dispatch_sync(_dispatchQueue, ^{ + [_instanceDictionary removeObjectForKey:aKey]; + }); +} + +/** + Set an object in the instanceDictionary + */ ++ (void)setObject:(id)anObject forKey:(id )aKey { + dispatch_sync(_dispatchQueue, ^{ + [_instanceDictionary setObject:anObject forKey:aKey]; + }); +} + + +/** + Generate the user agent string + */ ++ (NSString *) userAgent { + static NSString *_userAgent = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *systemName = [[[UIDevice currentDevice] systemName] stringByReplacingOccurrencesOfString:@" " withString:@"-"]; + if (!systemName) { + systemName = AWSCognitoAuthUnknown; + } + NSString *systemVersion = [[UIDevice currentDevice] systemVersion]; + if (!systemVersion) { + systemVersion = AWSCognitoAuthUnknown; + } + NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier]; + if (!localeIdentifier) { + localeIdentifier = AWSCognitoAuthUnknown; + } + _userAgent = [NSString stringWithFormat:@"aws-sdk-iOS/%@ %@/%@ %@/lite", AWSCognitoAuthSDKVersion, systemName, systemVersion, localeIdentifier]; + }); + + return _userAgent; +} + +@end + +@implementation AWSCognitoAuthUserSession + +-(instancetype) initWithIdToken:(NSString *)idToken accessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expiresIn:(NSNumber *) expiresIn { + self = [self initWithIdToken:idToken accessToken:accessToken refreshToken:refreshToken expirationTime:[NSDate dateWithTimeIntervalSinceNow:expiresIn.doubleValue]]; + return self; +} + +-(instancetype) initWithIdToken:(NSString *)idToken accessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expirationTime:(NSDate *) expirationTime { + self = [super init]; + if(self != nil) { + self.idToken = [[AWSCognitoAuthUserSessionToken alloc] initWithToken:idToken]; + self.accessToken = [[AWSCognitoAuthUserSessionToken alloc] initWithToken:accessToken]; + self.refreshToken = [[AWSCognitoAuthUserSessionToken alloc] initWithToken:refreshToken]; + self.expirationTime = expirationTime; + } + return self; +} + + +-(NSString *) username { + return self.accessToken.claims[@"username"]; +} + + +@end + +@implementation AWSCognitoAuthUserSessionToken + +-(instancetype) initWithToken:(NSString *)token { + if(token == nil){ + return nil; + } + self = [super init]; + if(self != nil) { + self.tokenString = token; + } + return self; +} + +-(NSDictionary *) claims { + NSDictionary * result = nil; + NSArray *pieces = [self.tokenString componentsSeparatedByString:@"."]; + if(pieces.count > 2){ + NSString * claims = pieces[1]; + //JWT is not padded with =, pad it if necessary + NSUInteger paddedLength = claims.length + (4 - (claims.length % 4)) % 4;; + claims = [claims stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0]; + + NSData * claimsData = [[NSData alloc] initWithBase64EncodedString:claims options:NSDataBase64DecodingIgnoreUnknownCharacters]; + NSError *error = nil; + if(claimsData != nil){ + result = [NSJSONSerialization JSONObjectWithData:claimsData options:kNilOptions error:&error]; + if(error) { + NSLog(@"Unable to deserialize token claims: %@", error); + } + } else { + NSLog(@"Token is not valid base64"); + } + } + return result; +} + + +@end + +@implementation AWSCognitoAuthConfiguration + +- (instancetype)initWithAppClientId:(NSString *) appClientId + appClientSecret:(nullable NSString *)appClientSecret + scopes:(NSSet *) scopes + signInRedirectUri:(NSString *) signInRedirectUri + signOutRedirectUri:(NSString *) signOutRedirectUri + webDomain:(NSString *) webDomain +{ + if (self = [super init]) { + _appClientId = appClientId; + _appClientSecret = appClientSecret; + _scopes = scopes; + _signInRedirectUri = signInRedirectUri; + _signOutRedirectUri = signOutRedirectUri; + _webDomain = webDomain; + } + + return self; +} + + +- (id)copyWithZone:(NSZone *)zone { + AWSCognitoAuthConfiguration *configuration = [[[self class] allocWithZone:zone] initWithAppClientId:self.appClientId + appClientSecret:self.appClientSecret + scopes:self.scopes + signInRedirectUri:self.signInRedirectUri + signOutRedirectUri:self.signOutRedirectUri + webDomain:self.webDomain]; + return configuration; +} + +@end diff --git a/AWSCognitoAuth/Info.plist b/AWSCognitoAuth/Info.plist new file mode 100644 index 00000000000..cb092a67ec3 --- /dev/null +++ b/AWSCognitoAuth/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.5.8 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/AWSCognitoAuth/Internal/AWSCognitoAuth_Internal.h b/AWSCognitoAuth/Internal/AWSCognitoAuth_Internal.h new file mode 100644 index 00000000000..e88dee5c307 --- /dev/null +++ b/AWSCognitoAuth/Internal/AWSCognitoAuth_Internal.h @@ -0,0 +1,30 @@ +#import "AWSCognitoAuth.h" +#import "AWSCognitoAuthUICKeyChainStore.h" + +FOUNDATION_EXPORT NSString *const AWSCognitoAuthUserAccessToken; + + +@interface AWSCognitoAuth() +@property (nonatomic, strong) AWSCognitoAuthUICKeyChainStore *keychain; + +- (NSString*) currentUsername; +- (NSString *) keyChainNamespaceClientId:(NSString *)username; +- (NSString *) keyChainKey: (NSString *) namespace key:(const NSString *) key; +-(NSError *) getError:(NSString *) error code:(AWSCognitoAuthClientErrorType) code; + + +@end + +@interface AWSCognitoAuthUserSessionToken() +@property (nonatomic, strong) NSString * tokenString; +-(instancetype) initWithToken:(NSString *)token; +@end + +@interface AWSCognitoAuthUserSession() +@property (nonatomic, strong) AWSCognitoAuthUserSessionToken * idToken; +@property (nonatomic, strong) AWSCognitoAuthUserSessionToken * accessToken; +@property (nonatomic, strong) AWSCognitoAuthUserSessionToken * refreshToken; +@property (nonatomic, strong) NSDate * expirationTime; +-(instancetype) initWithIdToken: (NSString *)idToken accessToken:(NSString *) accessToken refreshToken:(NSString *) refreshToken expirationTime:(NSDate*) expirationTime; +-(instancetype) initWithIdToken: (NSString *)idToken accessToken:(NSString *) accessToken refreshToken:(NSString *) refreshToken expiresIn:(NSNumber*) expiresIn; +@end diff --git a/AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.h b/AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.h new file mode 100644 index 00000000000..3a2b303db8f --- /dev/null +++ b/AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.h @@ -0,0 +1,281 @@ +// +// UICKeyChainStore.h +// UICKeyChainStore +// +// Created by Kishikawa Katsumi on 11/11/20. +// Copyright (c) 2011 Kishikawa Katsumi. All rights reserved. +// + +#import + +#if !__has_feature(nullability) +#define NS_ASSUME_NONNULL_BEGIN +#define NS_ASSUME_NONNULL_END +#define nullable +#define nonnull +#define null_unspecified +#define null_resettable +#define __nullable +#define __nonnull +#define __null_unspecified +#endif + +#if __has_extension(objc_generics) +#define UIC_KEY_TYPE +#define UIC_CREDENTIAL_TYPE *> +#else +#define UIC_KEY_TYPE +#define UIC_CREDENTIAL_TYPE +#endif + +NS_ASSUME_NONNULL_BEGIN + +extern NSString * const AWSCognitoAuthUICKeyChainStoreErrorDomain; + +typedef NS_ENUM(NSInteger, AWSCognitoAuthUICKeyChainStoreErrorCode) { + AWSCognitoAuthUICKeyChainStoreErrorInvalidArguments = 1, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoAuthUICKeyChainStoreItemClass) { + AWSCognitoAuthUICKeyChainStoreItemClassGenericPassword = 1, + AWSCognitoAuthUICKeyChainStoreItemClassInternetPassword, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoAuthUICKeyChainStoreProtocolType) { + AWSCognitoAuthUICKeyChainStoreProtocolTypeFTP = 1, + AWSCognitoAuthUICKeyChainStoreProtocolTypeFTPAccount, + AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeIRC, + AWSCognitoAuthUICKeyChainStoreProtocolTypeNNTP, + AWSCognitoAuthUICKeyChainStoreProtocolTypePOP3, + AWSCognitoAuthUICKeyChainStoreProtocolTypeSMTP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeSOCKS, + AWSCognitoAuthUICKeyChainStoreProtocolTypeIMAP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeLDAP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeAppleTalk, + AWSCognitoAuthUICKeyChainStoreProtocolTypeAFP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeTelnet, + AWSCognitoAuthUICKeyChainStoreProtocolTypeSSH, + AWSCognitoAuthUICKeyChainStoreProtocolTypeFTPS, + AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTPS, + AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTPProxy, + AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTPSProxy, + AWSCognitoAuthUICKeyChainStoreProtocolTypeFTPProxy, + AWSCognitoAuthUICKeyChainStoreProtocolTypeSMB, + AWSCognitoAuthUICKeyChainStoreProtocolTypeRTSP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeRTSPProxy, + AWSCognitoAuthUICKeyChainStoreProtocolTypeDAAP, + AWSCognitoAuthUICKeyChainStoreProtocolTypeEPPC, + AWSCognitoAuthUICKeyChainStoreProtocolTypeNNTPS, + AWSCognitoAuthUICKeyChainStoreProtocolTypeLDAPS, + AWSCognitoAuthUICKeyChainStoreProtocolTypeTelnetS, + AWSCognitoAuthUICKeyChainStoreProtocolTypeIRCS, + AWSCognitoAuthUICKeyChainStoreProtocolTypePOP3S, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoAuthUICKeyChainStoreAuthenticationType) { + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeNTLM = 1, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeMSN, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeDPA, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeRPA, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeHTTPBasic, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeHTTPDigest, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeHTMLForm, + AWSCognitoAuthUICKeyChainStoreAuthenticationTypeDefault, +}; + +typedef NS_ENUM(NSInteger, AWSCognitoAuthUICKeyChainStoreAccessibility) { + AWSCognitoAuthUICKeyChainStoreAccessibilityWhenUnlocked = 1, + AWSCognitoAuthUICKeyChainStoreAccessibilityAfterFirstUnlock, + AWSCognitoAuthUICKeyChainStoreAccessibilityAlways, + AWSCognitoAuthUICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly + __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0), + AWSCognitoAuthUICKeyChainStoreAccessibilityWhenUnlockedThisDeviceOnly, + AWSCognitoAuthUICKeyChainStoreAccessibilityAfterFirstUnlockThisDeviceOnly, + AWSCognitoAuthUICKeyChainStoreAccessibilityAlwaysThisDeviceOnly, +} +__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_4_0); + +typedef NS_ENUM(NSInteger, AWSCognitoAuthUICKeyChainStoreAuthenticationPolicy) { + AWSCognitoAuthUICKeyChainStoreAuthenticationPolicyUserPresence = kSecAccessControlUserPresence, +}; + +@interface AWSCognitoAuthUICKeyChainStore : NSObject + +@property (nonatomic, readonly) AWSCognitoAuthUICKeyChainStoreItemClass itemClass; + +@property (nonatomic, readonly, nullable) NSString *service; +@property (nonatomic, readonly, nullable) NSString *accessGroup; + +@property (nonatomic, readonly, nullable) NSURL *server; +@property (nonatomic, readonly) AWSCognitoAuthUICKeyChainStoreProtocolType protocolType; +@property (nonatomic, readonly) AWSCognitoAuthUICKeyChainStoreAuthenticationType authenticationType; + +@property (nonatomic) AWSCognitoAuthUICKeyChainStoreAccessibility accessibility; +@property (nonatomic, readonly) AWSCognitoAuthUICKeyChainStoreAuthenticationPolicy authenticationPolicy +__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); + +@property (nonatomic) BOOL synchronizable; + +@property (nonatomic, nullable) NSString *authenticationPrompt +__OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_8_0); + +@property (nonatomic, readonly, nullable) NSArray UIC_KEY_TYPE *allKeys; +@property (nonatomic, readonly, nullable) NSArray *allItems; + ++ (NSString *)defaultService; ++ (void)setDefaultService:(NSString *)defaultService; + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStore; ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithService:(nullable NSString *)service; ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithService:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType; ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType authenticationType:(AWSCognitoAuthUICKeyChainStoreAuthenticationType)authenticationType; + +- (instancetype)init; +- (instancetype)initWithService:(nullable NSString *)service; +- (instancetype)initWithService:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; + +- (instancetype)initWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType; +- (instancetype)initWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType authenticationType:(AWSCognitoAuthUICKeyChainStoreAuthenticationType)authenticationType; + ++ (nullable NSString *)stringForKey:(NSString *)key; ++ (nullable NSString *)stringForKey:(NSString *)key service:(nullable NSString *)service; ++ (nullable NSString *)stringForKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; + ++ (nullable NSData *)dataForKey:(NSString *)key; ++ (nullable NSData *)dataForKey:(NSString *)key service:(nullable NSString *)service; ++ (nullable NSData *)dataForKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; + +- (BOOL)contains:(nullable NSString *)key; + +- (BOOL)setString:(nullable NSString *)string forKey:(nullable NSString *)key; +- (BOOL)setString:(nullable NSString *)string forKey:(nullable NSString *)key label:(nullable NSString *)label comment:(nullable NSString *)comment; +- (nullable NSString *)stringForKey:(NSString *)key; + +- (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key; +- (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key label:(nullable NSString *)label comment:(nullable NSString *)comment; +- (nullable NSData *)dataForKey:(NSString *)key; + ++ (BOOL)removeItemForKey:(NSString *)key; ++ (BOOL)removeItemForKey:(NSString *)key service:(nullable NSString *)service; ++ (BOOL)removeItemForKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; + ++ (BOOL)removeAllItems; ++ (BOOL)removeAllItemsForService:(nullable NSString *)service; ++ (BOOL)removeAllItemsForService:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup; + +- (BOOL)removeItemForKey:(NSString *)key; + +- (BOOL)removeAllItems; + +- (nullable NSString *)objectForKeyedSubscript:(NSString *)key; +- (void)setObject:(nullable NSString *)obj forKeyedSubscript:(NSString *)key; + ++ (nullable NSArray UIC_KEY_TYPE *)allKeysWithItemClass:(AWSCognitoAuthUICKeyChainStoreItemClass)itemClass; +- (nullable NSArray UIC_KEY_TYPE *)allKeys; + ++ (nullable NSArray *)allItemsWithItemClass:(AWSCognitoAuthUICKeyChainStoreItemClass)itemClass; +- (nullable NSArray *)allItems; + +- (void)setAccessibility:(AWSCognitoAuthUICKeyChainStoreAccessibility)accessibility authenticationPolicy:(AWSCognitoAuthUICKeyChainStoreAuthenticationPolicy)authenticationPolicy +__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); + +#if TARGET_OS_IOS +- (void)sharedPasswordWithCompletion:(nullable void (^)(NSString * __nullable account, NSString * __nullable password, NSError * __nullable error))completion; +- (void)sharedPasswordForAccount:(NSString *)account completion:(nullable void (^)(NSString * __nullable password, NSError * __nullable error))completion; + +- (void)setSharedPassword:(nullable NSString *)password forAccount:(NSString *)account completion:(nullable void (^)(NSError * __nullable error))completion; +- (void)removeSharedPasswordForAccount:(NSString *)account completion:(nullable void (^)(NSError * __nullable error))completion; + ++ (void)requestSharedWebCredentialWithCompletion:(nullable void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError * __nullable error))completion; ++ (void)requestSharedWebCredentialForDomain:(nullable NSString *)domain account:(nullable NSString *)account completion:(nullable void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError * __nullable error))completion; + ++ (NSString *)generatePassword; +#endif + +@end + +@interface AWSCognitoAuthUICKeyChainStore (ErrorHandling) + ++ (nullable NSString *)stringForKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (nullable NSString *)stringForKey:(NSString *)key service:(nullable NSString *)service error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (nullable NSString *)stringForKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (nullable NSData *)dataForKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (nullable NSData *)dataForKey:(NSString *)key service:(nullable NSString *)service error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (nullable NSData *)dataForKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup error:(NSError * __nullable __autoreleasing * __nullable)error; + +- (BOOL)setString:(nullable NSString *)string forKey:(NSString * )key error:(NSError * __nullable __autoreleasing * __nullable)error; +- (BOOL)setString:(nullable NSString *)string forKey:(NSString * )key label:(nullable NSString *)label comment:(nullable NSString *)comment error:(NSError * __nullable __autoreleasing * __nullable)error; + +- (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; +- (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key label:(nullable NSString *)label comment:(nullable NSString *)comment error:(NSError * __nullable __autoreleasing * __nullable)error; + +- (nullable NSString *)stringForKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; +- (nullable NSData *)dataForKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)removeItemForKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)removeItemForKey:(NSString *)key service:(nullable NSString *)service error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)removeItemForKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)removeAllItemsWithError:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)removeAllItemsForService:(nullable NSString *)service error:(NSError * __nullable __autoreleasing * __nullable)error; ++ (BOOL)removeAllItemsForService:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup error:(NSError * __nullable __autoreleasing * __nullable)error; + +- (BOOL)removeItemForKey:(NSString *)key error:(NSError * __nullable __autoreleasing * __nullable)error; +- (BOOL)removeAllItemsWithError:(NSError * __nullable __autoreleasing * __nullable)error; + +@end + +@interface AWSCognitoAuthUICKeyChainStore (ForwardCompatibility) + ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service genericAttribute:(nullable id)genericAttribute; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup genericAttribute:(nullable id)genericAttribute; ++ (BOOL)setString:(nullable NSString *)value forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service genericAttribute:(nullable id)genericAttribute; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup genericAttribute:(nullable id)genericAttribute; ++ (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key service:(nullable NSString *)service accessGroup:(nullable NSString *)accessGroup genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + +- (BOOL)setString:(nullable NSString *)string forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute; +- (BOOL)setString:(nullable NSString *)string forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + +- (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute; +- (BOOL)setData:(nullable NSData *)data forKey:(NSString *)key genericAttribute:(nullable id)genericAttribute error:(NSError * __nullable __autoreleasing * __nullable)error; + +@end + +@interface AWSCognitoAuthUICKeyChainStore (Deprecation) + +- (void)synchronize __attribute__((deprecated("calling this method is no longer required"))); +- (BOOL)synchronizeWithError:(NSError * __nullable __autoreleasing * __nullable)error __attribute__((deprecated("calling this method is no longer required"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.m b/AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.m new file mode 100644 index 00000000000..969af351434 --- /dev/null +++ b/AWSCognitoAuth/Internal/UICKeyChainStore/AWSCognitoAuthUICKeyChainStore.m @@ -0,0 +1,1388 @@ +// +// UICKeyChainStore.m +// UICKeyChainStore +// +// Created by Kishikawa Katsumi on 11/11/20. +// Copyright (c) 2011 Kishikawa Katsumi. All rights reserved. +// + +#import "AWSCognitoAuthUICKeyChainStore.h" + +NSString * const AWSCognitoAuthUICKeyChainStoreErrorDomain = @"com.kishikawakatsumi.uickeychainstore"; +static NSString *_defaultService; + +@interface AWSCognitoAuthUICKeyChainStore () + +@end + +@implementation AWSCognitoAuthUICKeyChainStore + ++ (NSString *)defaultService +{ + if (!_defaultService) { + _defaultService = [[NSBundle mainBundle] bundleIdentifier] ?: @""; + } + + return _defaultService; +} + ++ (void)setDefaultService:(NSString *)defaultService +{ + _defaultService = defaultService; +} + +#pragma mark - + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStore +{ + return [[self alloc] initWithService:nil accessGroup:nil]; +} + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithService:(NSString *)service +{ + return [[self alloc] initWithService:service accessGroup:nil]; +} + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithService:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [[self alloc] initWithService:service accessGroup:accessGroup]; +} + +#pragma mark - + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType +{ + return [[self alloc] initWithServer:server protocolType:protocolType authenticationType:AWSCognitoAuthUICKeyChainStoreAuthenticationTypeDefault]; +} + ++ (AWSCognitoAuthUICKeyChainStore *)keyChainStoreWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType authenticationType:(AWSCognitoAuthUICKeyChainStoreAuthenticationType)authenticationType +{ + return [[self alloc] initWithServer:server protocolType:protocolType authenticationType:authenticationType]; +} + +#pragma mark - + +- (instancetype)init +{ + return [self initWithService:[self.class defaultService] accessGroup:nil]; +} + +- (instancetype)initWithService:(NSString *)service +{ + return [self initWithService:service accessGroup:nil]; +} + +- (instancetype)initWithService:(NSString *)service accessGroup:(NSString *)accessGroup +{ + self = [super init]; + if (self) { + _itemClass = AWSCognitoAuthUICKeyChainStoreItemClassGenericPassword; + + if (!service) { + service = [self.class defaultService]; + } + _service = service.copy; + _accessGroup = accessGroup.copy; + [self commonInit]; + } + + return self; +} + +#pragma mark - + +- (instancetype)initWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType +{ + return [self initWithServer:server protocolType:protocolType authenticationType:AWSCognitoAuthUICKeyChainStoreAuthenticationTypeDefault]; +} + +- (instancetype)initWithServer:(NSURL *)server protocolType:(AWSCognitoAuthUICKeyChainStoreProtocolType)protocolType authenticationType:(AWSCognitoAuthUICKeyChainStoreAuthenticationType)authenticationType +{ + self = [super init]; + if (self) { + _itemClass = AWSCognitoAuthUICKeyChainStoreItemClassInternetPassword; + + _server = server.copy; + _protocolType = protocolType; + _authenticationType = authenticationType; + + [self commonInit]; + } + + return self; +} + +#pragma mark - + +- (void)commonInit +{ + _accessibility = AWSCognitoAuthUICKeyChainStoreAccessibilityAfterFirstUnlock; +} + +#pragma mark - + ++ (NSString *)stringForKey:(NSString *)key +{ + return [self stringForKey:key service:nil accessGroup:nil error:nil]; +} + ++ (NSString *)stringForKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self stringForKey:key service:nil accessGroup:nil error:error]; +} + ++ (NSString *)stringForKey:(NSString *)key service:(NSString *)service +{ + return [self stringForKey:key service:service accessGroup:nil error:nil]; +} + ++ (NSString *)stringForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error +{ + return [self stringForKey:key service:service accessGroup:nil error:error]; +} + ++ (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self stringForKey:key service:service accessGroup:accessGroup error:nil]; +} + ++ (NSString *)stringForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error +{ + if (!key) { + NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; + if (error) { + *error = e; + } + return nil; + } + if (!service) { + service = [self defaultService]; + } + + AWSCognitoAuthUICKeyChainStore *keychain = [AWSCognitoAuthUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; + return [keychain stringForKey:key error:error]; +} + +#pragma mark - + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key +{ + return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:nil error:nil]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:nil error:error]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key genericAttribute:(id)genericAttribute +{ + return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:nil]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + return [self setString:value forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:error]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service +{ + return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:nil error:nil]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error +{ + return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:nil error:error]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute +{ + return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:nil]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + return [self setString:value forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:error]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:nil]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error +{ + return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:error]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute +{ + return [self setString:value forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:nil]; +} + ++ (BOOL)setString:(NSString *)value forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + if (!value) { + return [self removeItemForKey:key service:service accessGroup:accessGroup error:error]; + } + NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding]; + if (data) { + return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:error]; + } + NSError *e = [self conversionError:NSLocalizedString(@"failed to convert string to data", nil)]; + if (error) { + *error = e; + } + return NO; +} + +#pragma mark - + ++ (NSData *)dataForKey:(NSString *)key +{ + return [self dataForKey:key service:nil accessGroup:nil error:nil]; +} + ++ (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self dataForKey:key service:nil accessGroup:nil error:error]; +} + ++ (NSData *)dataForKey:(NSString *)key service:(NSString *)service +{ + return [self dataForKey:key service:service accessGroup:nil error:nil]; +} + ++ (NSData *)dataForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error +{ + return [self dataForKey:key service:service accessGroup:nil error:error]; +} + ++ (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self dataForKey:key service:service accessGroup:accessGroup error:nil]; +} + ++ (NSData *)dataForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error +{ + if (!key) { + NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; + if (error) { + *error = e; + } + return nil; + } + if (!service) { + service = [self defaultService]; + } + + AWSCognitoAuthUICKeyChainStore *keychain = [AWSCognitoAuthUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; + return [keychain dataForKey:key error:error]; +} + +#pragma mark - + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key +{ + return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:nil error:nil]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:nil error:error]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute +{ + return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:nil]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + return [self setData:data forKey:key service:nil accessGroup:nil genericAttribute:genericAttribute error:error]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service +{ + return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:nil error:nil]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error +{ + return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:nil error:error]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute +{ + return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:nil]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + return [self setData:data forKey:key service:service accessGroup:nil genericAttribute:genericAttribute error:error]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:nil]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error +{ + return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:nil error:error]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute +{ + return [self setData:data forKey:key service:service accessGroup:accessGroup genericAttribute:genericAttribute error:nil]; +} + ++ (BOOL)setData:(NSData *)data forKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + if (!key) { + NSError *e = [self argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; + if (error) { + *error = e; + } + return NO; + } + if (!service) { + service = [self defaultService]; + } + + AWSCognitoAuthUICKeyChainStore *keychain = [AWSCognitoAuthUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; + return [keychain setData:data forKey:key genericAttribute:genericAttribute]; +} + +#pragma mark - + +- (BOOL)contains:(NSString *)key +{ + NSMutableDictionary *query = [self query]; + query[(__bridge __strong id)kSecAttrAccount] = key; + + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); + return status == errSecSuccess; +} + +#pragma mark - + +- (NSString *)stringForKey:(id)key +{ + return [self stringForKey:key error:nil]; +} + +- (NSString *)stringForKey:(id)key error:(NSError *__autoreleasing *)error +{ + NSData *data = [self dataForKey:key error:error]; + if (data) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (string) { + return string; + } + NSError *e = [self.class conversionError:NSLocalizedString(@"failed to convert data to string", nil)]; + if (error) { + *error = e; + } + return nil; + } + + return nil; +} + +#pragma mark - + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key +{ + return [self setString:string forKey:key genericAttribute:nil label:nil comment:nil error:nil]; +} + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self setString:string forKey:key genericAttribute:nil label:nil comment:nil error:error]; +} + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute +{ + return [self setString:string forKey:key genericAttribute:genericAttribute label:nil comment:nil error:nil]; +} + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + return [self setString:string forKey:key genericAttribute:genericAttribute label:nil comment:nil error:error]; +} + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment +{ + return [self setString:string forKey:key genericAttribute:nil label:label comment:comment error:nil]; +} + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error +{ + return [self setString:string forKey:key genericAttribute:nil label:label comment:comment error:error]; +} + +- (BOOL)setString:(NSString *)string forKey:(NSString *)key genericAttribute:(id)genericAttribute label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error +{ + if (!string) { + return [self removeItemForKey:key error:error]; + } + NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; + if (data) { + return [self setData:data forKey:key genericAttribute:genericAttribute label:label comment:comment error:error]; + } + NSError *e = [self.class conversionError:NSLocalizedString(@"failed to convert string to data", nil)]; + if (error) { + *error = e; + } + return NO; +} + +#pragma mark - + +- (NSData *)dataForKey:(NSString *)key +{ + return [self dataForKey:key error:nil]; +} + +- (NSData *)dataForKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + NSMutableDictionary *query = [self query]; + query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue; + + query[(__bridge __strong id)kSecAttrAccount] = key; + + CFTypeRef data = nil; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &data); + + if (status == errSecSuccess) { + NSData *ret = [NSData dataWithData:(__bridge NSData *)data]; + if (data) { + CFRelease(data); + return ret; + } else { + NSError *e = [self.class unexpectedError:NSLocalizedString(@"Unexpected error has occurred.", nil)]; + if (error) { + *error = e; + } + return nil; + } + } else if (status == errSecItemNotFound) { + return nil; + } + + NSError *e = [self.class securityError:status]; + if (error) { + *error = e; + } + return nil; +} + +#pragma mark - + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key +{ + return [self setData:data forKey:key genericAttribute:nil label:nil comment:nil error:nil]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self setData:data forKey:key genericAttribute:nil label:nil comment:nil error:error]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute +{ + return [self setData:data forKey:key genericAttribute:genericAttribute label:nil comment:nil error:nil]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute error:(NSError * __autoreleasing *)error +{ + return [self setData:data forKey:key genericAttribute:genericAttribute label:nil comment:nil error:error]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment +{ + return [self setData:data forKey:key genericAttribute:nil label:label comment:comment error:nil]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error +{ + return [self setData:data forKey:key genericAttribute:nil label:label comment:comment error:error]; +} + +- (BOOL)setData:(NSData *)data forKey:(NSString *)key genericAttribute:(id)genericAttribute label:(NSString *)label comment:(NSString *)comment error:(NSError *__autoreleasing *)error +{ + if (!key) { + NSError *e = [self.class argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; + if (error) { + *error = e; + } + return NO; + } + if (!data) { + return [self removeItemForKey:key error:error]; + } + + NSMutableDictionary *query = [self query]; + query[(__bridge __strong id)kSecAttrAccount] = key; +#if TARGET_OS_IOS +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (floor(NSFoundationVersionNumber) > floor(1144.17)) { // iOS 9+ + query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail; + } else if (floor(NSFoundationVersionNumber) > floor(1047.25)) { // iOS 8+ + query[(__bridge __strong id)kSecUseNoAuthenticationUI] = (__bridge id)kCFBooleanTrue; + } +#pragma clang diagnostic pop +#elif TARGET_OS_WATCH || TARGET_OS_TV + query[(__bridge __strong id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail; +#endif + + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); + if (status == errSecSuccess || status == errSecInteractionNotAllowed) { + query = [self query]; + query[(__bridge __strong id)kSecAttrAccount] = key; + + NSError *unexpectedError = nil; + NSMutableDictionary *attributes = [self attributesWithKey:nil value:data error:&unexpectedError]; + + if (genericAttribute) { + attributes[(__bridge __strong id)kSecAttrGeneric] = genericAttribute; + } + if (label) { + attributes[(__bridge __strong id)kSecAttrLabel] = label; + } + if (comment) { + attributes[(__bridge __strong id)kSecAttrComment] = comment; + } + + if (unexpectedError) { + NSLog(@"error: [%@] %@", @(unexpectedError.code), NSLocalizedString(@"Unexpected error has occurred.", nil)); + if (error) { + *error = unexpectedError; + } + return NO; + } else { + + if (status == errSecInteractionNotAllowed && floor(NSFoundationVersionNumber) <= floor(1140.11)) { // iOS 8.0.x + if ([self removeItemForKey:key error:error]) { + return [self setData:data forKey:key label:label comment:comment error:error]; + } + } else { + status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributes); + } + if (status != errSecSuccess) { + NSError *e = [self.class securityError:status]; + if (error) { + *error = e; + } + return NO; + } + } + } else if (status == errSecItemNotFound) { + NSError *unexpectedError = nil; + NSMutableDictionary *attributes = [self attributesWithKey:key value:data error:&unexpectedError]; + + if (genericAttribute) { + attributes[(__bridge __strong id)kSecAttrGeneric] = genericAttribute; + } + if (label) { + attributes[(__bridge __strong id)kSecAttrLabel] = label; + } + if (comment) { + attributes[(__bridge __strong id)kSecAttrComment] = comment; + } + + if (unexpectedError) { + NSLog(@"error: [%@] %@", @(unexpectedError.code), NSLocalizedString(@"Unexpected error has occurred.", nil)); + if (error) { + *error = unexpectedError; + } + return NO; + } else { + status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL); + if (status != errSecSuccess) { + NSError *e = [self.class securityError:status]; + if (error) { + *error = e; + } + return NO; + } + } + } else { + NSError *e = [self.class securityError:status]; + if (error) { + *error = e; + } + return NO; + } + + return YES; +} + +#pragma mark - + ++ (BOOL)removeItemForKey:(NSString *)key +{ + return [self removeItemForKey:key service:nil accessGroup:nil error:nil]; +} + ++ (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + return [self removeItemForKey:key service:nil accessGroup:nil error:error]; +} + ++ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service +{ + return [self removeItemForKey:key service:service accessGroup:nil error:nil]; +} + ++ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service error:(NSError *__autoreleasing *)error +{ + return [self removeItemForKey:key service:service accessGroup:nil error:error]; +} + ++ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self removeItemForKey:key service:service accessGroup:accessGroup error:nil]; +} + ++ (BOOL)removeItemForKey:(NSString *)key service:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error +{ + if (!key) { + NSError *e = [self.class argumentError:NSLocalizedString(@"the key must not to be nil", nil)]; + if (error) { + *error = e; + } + return NO; + } + if (!service) { + service = [self defaultService]; + } + + AWSCognitoAuthUICKeyChainStore *keychain = [AWSCognitoAuthUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; + return [keychain removeItemForKey:key error:error]; +} + +#pragma mark - + ++ (BOOL)removeAllItems +{ + return [self removeAllItemsForService:nil accessGroup:nil error:nil]; +} + ++ (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error +{ + return [self removeAllItemsForService:nil accessGroup:nil error:error]; +} + ++ (BOOL)removeAllItemsForService:(NSString *)service +{ + return [self removeAllItemsForService:service accessGroup:nil error:nil]; +} + ++ (BOOL)removeAllItemsForService:(NSString *)service error:(NSError *__autoreleasing *)error +{ + return [self removeAllItemsForService:service accessGroup:nil error:error]; +} + ++ (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup +{ + return [self removeAllItemsForService:service accessGroup:accessGroup error:nil]; +} + ++ (BOOL)removeAllItemsForService:(NSString *)service accessGroup:(NSString *)accessGroup error:(NSError *__autoreleasing *)error +{ + AWSCognitoAuthUICKeyChainStore *keychain = [AWSCognitoAuthUICKeyChainStore keyChainStoreWithService:service accessGroup:accessGroup]; + return [keychain removeAllItemsWithError:error]; +} + +#pragma mark - + +- (BOOL)removeItemForKey:(NSString *)key +{ + return [self removeItemForKey:key error:nil]; +} + +- (BOOL)removeItemForKey:(NSString *)key error:(NSError *__autoreleasing *)error +{ + NSMutableDictionary *query = [self query]; + query[(__bridge __strong id)kSecAttrAccount] = key; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + if (status != errSecSuccess && status != errSecItemNotFound) { + NSError *e = [self.class securityError:status]; + if (error) { + *error = e; + } + return NO; + } + + return YES; +} + +#pragma mark - + +- (BOOL)removeAllItems +{ + return [self removeAllItemsWithError:nil]; +} + +- (BOOL)removeAllItemsWithError:(NSError *__autoreleasing *)error +{ + NSMutableDictionary *query = [self query]; +#if !TARGET_OS_IPHONE + query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; +#endif + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); + if (status != errSecSuccess && status != errSecItemNotFound) { + NSError *e = [self.class securityError:status]; + if (error) { + *error = e; + } + return NO; + } + + return YES; +} + +#pragma mark - + +- (NSString *)objectForKeyedSubscript:(NSString *)key +{ + return [self stringForKey:key]; +} + +- (void)setObject:(NSString *)obj forKeyedSubscript:(NSString *)key +{ + if (!obj) { + [self removeItemForKey:key]; + } else { + [self setString:obj forKey:key]; + } +} + +#pragma mark - + +- (NSArray UIC_KEY_TYPE *)allKeys +{ + NSArray *items = [self.class prettify:[self itemClassObject] items:[self items]]; + NSMutableArray *keys = [[NSMutableArray alloc] init]; + for (NSDictionary *item in items) { + [keys addObject:item[@"key"]]; + } + return keys.copy; +} + ++ (NSArray UIC_KEY_TYPE *)allKeysWithItemClass:(AWSCognitoAuthUICKeyChainStoreItemClass)itemClass +{ + CFTypeRef itemClassObject = kSecClassGenericPassword; + if (itemClass == AWSCognitoAuthUICKeyChainStoreItemClassGenericPassword) { + itemClassObject = kSecClassGenericPassword; + } else if (itemClass == AWSCognitoAuthUICKeyChainStoreItemClassInternetPassword) { + itemClassObject = kSecClassInternetPassword; + } + + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + query[(__bridge __strong id)kSecClass] = (__bridge id)itemClassObject; + query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; + query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; + + CFArrayRef result = nil; + CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(query); + OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&result); + CFRelease(cfquery); + + if (status == errSecSuccess) { + NSArray *items = [self prettify:itemClassObject items:(__bridge NSArray *)result]; + NSMutableArray *keys = [[NSMutableArray alloc] init]; + for (NSDictionary *item in items) { + if (itemClassObject == kSecClassGenericPassword) { + [keys addObject:@{@"service": item[@"service"] ?: @"", @"key": item[@"key"] ?: @""}]; + } else if (itemClassObject == kSecClassInternetPassword) { + [keys addObject:@{@"server": item[@"service"] ?: @"", @"key": item[@"key"] ?: @""}]; + } + } + return keys.copy; + } else if (status == errSecItemNotFound) { + return @[]; + } + + return nil; +} + ++ (NSArray *)allItemsWithItemClass:(AWSCognitoAuthUICKeyChainStoreItemClass)itemClass +{ + CFTypeRef itemClassObject = kSecClassGenericPassword; + if (itemClass == AWSCognitoAuthUICKeyChainStoreItemClassGenericPassword) { + itemClassObject = kSecClassGenericPassword; + } else if (itemClass == AWSCognitoAuthUICKeyChainStoreItemClassInternetPassword) { + itemClassObject = kSecClassInternetPassword; + } + + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + query[(__bridge __strong id)kSecClass] = (__bridge id)itemClassObject; + query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; + query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; +#if TARGET_OS_IPHONE + query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue; +#endif + + CFArrayRef result = nil; + CFDictionaryRef cfquery = (CFDictionaryRef)CFBridgingRetain(query); + OSStatus status = SecItemCopyMatching(cfquery, (CFTypeRef *)&result); + CFRelease(cfquery); + + if (status == errSecSuccess) { + return [self prettify:itemClassObject items:(__bridge NSArray *)result]; + } else if (status == errSecItemNotFound) { + return @[]; + } + + return nil; +} + +- (NSArray *)allItems +{ + return [self.class prettify:[self itemClassObject] items:[self items]]; +} + +- (NSArray *)items +{ + NSMutableDictionary *query = [self query]; + query[(__bridge __strong id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; + query[(__bridge __strong id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; +#if TARGET_OS_IPHONE + query[(__bridge __strong id)kSecReturnData] = (__bridge id)kCFBooleanTrue; +#endif + + CFArrayRef result = nil; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query,(CFTypeRef *)&result); + + if (status == errSecSuccess) { + return CFBridgingRelease(result); + } else if (status == errSecItemNotFound) { + return @[]; + } + + return nil; +} + ++ (NSArray *)prettify:(CFTypeRef)itemClass items:(NSArray *)items +{ + NSMutableArray *prettified = [[NSMutableArray alloc] init]; + + for (NSDictionary *attributes in items) { + NSMutableDictionary *item = [[NSMutableDictionary alloc] init]; + if (itemClass == kSecClassGenericPassword) { + item[@"class"] = @"GenericPassword"; + id service = attributes[(__bridge id)kSecAttrService]; + if (service) { + item[@"service"] = service; + } + id accessGroup = attributes[(__bridge id)kSecAttrAccessGroup]; + if (accessGroup) { + item[@"accessGroup"] = accessGroup; + } + } else if (itemClass == kSecClassInternetPassword) { + item[@"class"] = @"InternetPassword"; + id server = attributes[(__bridge id)kSecAttrServer]; + if (server) { + item[@"server"] = server; + } + id protocolType = attributes[(__bridge id)kSecAttrProtocol]; + if (protocolType) { + item[@"protocol"] = protocolType; + } + id authenticationType = attributes[(__bridge id)kSecAttrAuthenticationType]; + if (authenticationType) { + item[@"authenticationType"] = authenticationType; + } + } + id key = attributes[(__bridge id)kSecAttrAccount]; + if (key) { + item[@"key"] = key; + } + NSData *data = attributes[(__bridge id)kSecValueData]; + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (string) { + item[@"value"] = string; + } else { + item[@"value"] = data; + } + + id accessible = attributes[(__bridge id)kSecAttrAccessible]; + if (accessible) { + item[@"accessibility"] = accessible; + } + + if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ + id synchronizable = attributes[(__bridge id)kSecAttrSynchronizable]; + if (synchronizable) { + item[@"synchronizable"] = synchronizable; + } + } + + [prettified addObject:item]; + } + + return prettified.copy; +} + +#pragma mark - + +- (void)setSynchronizable:(BOOL)synchronizable +{ + _synchronizable = synchronizable; + if (_authenticationPolicy) { + NSLog(@"%@", @"Cannot specify both an authenticationPolicy and a synchronizable"); + } +} + +- (void)setAccessibility:(AWSCognitoAuthUICKeyChainStoreAccessibility)accessibility authenticationPolicy:(AWSCognitoAuthUICKeyChainStoreAuthenticationPolicy)authenticationPolicy +{ + _accessibility = accessibility; + _authenticationPolicy = authenticationPolicy; + if (_synchronizable) { + NSLog(@"%@", @"Cannot specify both an authenticationPolicy and a synchronizable"); + } +} + +#pragma mark - + +#if TARGET_OS_IOS +- (void)sharedPasswordWithCompletion:(void (^)(NSString *account, NSString *password, NSError *error))completion +{ + NSString *domain = self.server.host; + if (domain.length > 0) { + [self.class requestSharedWebCredentialForDomain:domain account:nil completion:^(NSArray *credentials, NSError *error) { + NSDictionary *credential = credentials.firstObject; + if (credential) { + NSString *account = credential[@"account"]; + NSString *password = credential[@"password"]; + if (completion) { + completion(account, password, error); + } + } else { + if (completion) { + completion(nil, nil, error); + } + } + }]; + } else { + NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)]; + if (completion) { + completion(nil, nil, error); + } + } +} + +- (void)sharedPasswordForAccount:(NSString *)account completion:(void (^)(NSString *password, NSError *error))completion +{ + NSString *domain = self.server.host; + if (domain.length > 0) { + [self.class requestSharedWebCredentialForDomain:domain account:account completion:^(NSArray *credentials, NSError *error) { + NSDictionary *credential = credentials.firstObject; + if (credential) { + NSString *password = credential[@"password"]; + if (completion) { + completion(password, error); + } + } else { + if (completion) { + completion(nil, error); + } + } + }]; + } else { + NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)]; + if (completion) { + completion(nil, error); + } + } +} + +- (void)setSharedPassword:(NSString *)password forAccount:(NSString *)account completion:(void (^)(NSError *error))completion +{ + NSString *domain = self.server.host; + if (domain.length > 0) { + SecAddSharedWebCredential((__bridge CFStringRef)domain, (__bridge CFStringRef)account, (__bridge CFStringRef)password, ^(CFErrorRef error) { + if (completion) { + completion((__bridge NSError *)error); + } + }); + } else { + NSError *error = [self.class argumentError:NSLocalizedString(@"the server property must not to be nil, should use 'keyChainStoreWithServer:protocolType:' initializer to instantiate keychain store", nil)]; + if (completion) { + completion(error); + } + } +} + +- (void)removeSharedPasswordForAccount:(NSString *)account completion:(void (^)(NSError *error))completion +{ + [self setSharedPassword:nil forAccount:account completion:completion]; +} + ++ (void)requestSharedWebCredentialWithCompletion:(void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError *error))completion +{ + [self requestSharedWebCredentialForDomain:nil account:nil completion:completion]; +} + ++ (void)requestSharedWebCredentialForDomain:(NSString *)domain account:(NSString *)account completion:(void (^)(NSArray UIC_CREDENTIAL_TYPE *credentials, NSError *error))completion +{ + SecRequestSharedWebCredential((__bridge CFStringRef)domain, (__bridge CFStringRef)account, ^(CFArrayRef credentials, CFErrorRef error) { + if (error) { + NSError *e = (__bridge NSError *)error; + if (e.code != errSecItemNotFound) { + NSLog(@"error: [%@] %@", @(e.code), e.localizedDescription); + } + } + + NSMutableArray *sharedCredentials = [[NSMutableArray alloc] init]; + for (NSDictionary *credential in (__bridge NSArray *)credentials) { + NSMutableDictionary *sharedCredential = [[NSMutableDictionary alloc] init]; + NSString *server = credential[(__bridge __strong id)kSecAttrServer]; + if (server) { + sharedCredential[@"server"] = server; + } + NSString *account = credential[(__bridge __strong id)kSecAttrAccount]; + if (account) { + sharedCredential[@"account"] = account; + } + NSString *password = credential[(__bridge __strong id)kSecSharedPassword]; + if (password) { + sharedCredential[@"password"] = password; + } + [sharedCredentials addObject:sharedCredential]; + } + + if (completion) { + completion(sharedCredentials.copy, (__bridge NSError *)error); + } + }); +} + ++ (NSString *)generatePassword +{ + return CFBridgingRelease(SecCreateSharedWebCredentialPassword()); +} + +#endif + +#pragma mark - + +- (void)synchronize +{ + // Deprecated, calling this method is no longer required +} + +- (BOOL)synchronizeWithError:(NSError *__autoreleasing *)error +{ + // Deprecated, calling this method is no longer required + return true; +} + +#pragma mark - + +- (NSString *)description +{ + NSArray *items = [self allItems]; + if (items.count == 0) { + return @"()"; + } + NSMutableString *description = [[NSMutableString alloc] initWithString:@"(\n"]; + for (NSDictionary *item in items) { + [description appendFormat:@" %@", item]; + } + [description appendString:@")"]; + return description.copy; +} + +- (NSString *)debugDescription +{ + return [NSString stringWithFormat:@"%@", [self items]]; +} + +#pragma mark - + +- (NSMutableDictionary *)query +{ + NSMutableDictionary *query = [[NSMutableDictionary alloc] init]; + + CFTypeRef itemClass = [self itemClassObject]; + query[(__bridge __strong id)kSecClass] =(__bridge id)itemClass; + if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ (NSFoundationVersionNumber_iOS_6_1) + query[(__bridge __strong id)kSecAttrSynchronizable] = (__bridge id)kSecAttrSynchronizableAny; + } + + if (itemClass == kSecClassGenericPassword) { + query[(__bridge __strong id)(kSecAttrService)] = _service; +#if !TARGET_OS_SIMULATOR + if (_accessGroup) { + query[(__bridge __strong id)kSecAttrAccessGroup] = _accessGroup; + } +#endif + } else { + if (_server.host) { + query[(__bridge __strong id)kSecAttrServer] = _server.host; + } + if (_server.port) { + query[(__bridge __strong id)kSecAttrPort] = _server.port; + } + CFTypeRef protocolTypeObject = [self protocolTypeObject]; + if (protocolTypeObject) { + query[(__bridge __strong id)kSecAttrProtocol] = (__bridge id)protocolTypeObject; + } + CFTypeRef authenticationTypeObject = [self authenticationTypeObject]; + if (authenticationTypeObject) { + query[(__bridge __strong id)kSecAttrAuthenticationType] = (__bridge id)authenticationTypeObject; + } + } + +#if TARGET_OS_IOS + if (_authenticationPrompt) { + if (floor(NSFoundationVersionNumber) > floor(1047.25)) { // iOS 8+ (NSFoundationVersionNumber_iOS_7_1) + query[(__bridge __strong id)kSecUseOperationPrompt] = _authenticationPrompt; + } else { + NSLog(@"%@", @"Unavailable 'authenticationPrompt' attribute on iOS versions prior to 8.0."); + } + } +#endif + + return query; +} + +- (NSMutableDictionary *)attributesWithKey:(NSString *)key value:(NSData *)value error:(NSError *__autoreleasing *)error +{ + NSMutableDictionary *attributes; + + if (key) { + attributes = [self query]; + attributes[(__bridge __strong id)kSecAttrAccount] = key; + } else { + attributes = [[NSMutableDictionary alloc] init]; + } + + attributes[(__bridge __strong id)kSecValueData] = value; + +#if TARGET_OS_IOS + double iOS_7_1_or_10_9_2 = 1047.25; // NSFoundationVersionNumber_iOS_7_1 +#else + double iOS_7_1_or_10_9_2 = 1056.13; // NSFoundationVersionNumber10_9_2 +#endif + CFTypeRef accessibilityObject = [self accessibilityObject]; + if (_authenticationPolicy && accessibilityObject) { + if (floor(NSFoundationVersionNumber) > floor(iOS_7_1_or_10_9_2)) { // iOS 8+ or OS X 10.10+ + CFErrorRef securityError = NULL; + SecAccessControlRef accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibilityObject, (SecAccessControlCreateFlags)_authenticationPolicy, &securityError); + if (securityError) { + NSError *e = (__bridge NSError *)securityError; + NSLog(@"error: [%@] %@", @(e.code), e.localizedDescription); + if (error) { + *error = e; + CFRelease(accessControl); + return nil; + } + } + if (!accessControl) { + NSString *message = NSLocalizedString(@"Unexpected error has occurred.", nil); + NSError *e = [self.class unexpectedError:message]; + if (error) { + *error = e; + } + return nil; + } + attributes[(__bridge __strong id)kSecAttrAccessControl] = (__bridge_transfer id)accessControl; + } else { +#if TARGET_OS_IOS + NSLog(@"%@", @"Unavailable 'Touch ID integration' on iOS versions prior to 8.0."); +#else + NSLog(@"%@", @"Unavailable 'Touch ID integration' on OS X versions prior to 10.10."); +#endif + } + } else { + if (floor(NSFoundationVersionNumber) <= floor(iOS_7_1_or_10_9_2) && _accessibility == AWSCognitoAuthUICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly) { +#if TARGET_OS_IOS + NSLog(@"%@", @"Unavailable 'UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly' attribute on iOS versions prior to 8.0."); +#else + NSLog(@"%@", @"Unavailable 'UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly' attribute on OS X versions prior to 10.10."); +#endif + } else { + if (accessibilityObject) { + attributes[(__bridge __strong id)kSecAttrAccessible] = (__bridge id)accessibilityObject; + } + } + } + + if (floor(NSFoundationVersionNumber) > floor(993.00)) { // iOS 7+ + attributes[(__bridge __strong id)kSecAttrSynchronizable] = @(_synchronizable); + } + + return attributes; +} + +#pragma mark - + +- (CFTypeRef)itemClassObject +{ + switch (_itemClass) { + case AWSCognitoAuthUICKeyChainStoreItemClassGenericPassword: + return kSecClassGenericPassword; + case AWSCognitoAuthUICKeyChainStoreItemClassInternetPassword: + return kSecClassInternetPassword; + default: + return nil; + } +} + +- (CFTypeRef)protocolTypeObject +{ + switch (_protocolType) { + case AWSCognitoAuthUICKeyChainStoreProtocolTypeFTP: + return kSecAttrProtocolFTP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeFTPAccount: + return kSecAttrProtocolFTPAccount; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTP: + return kSecAttrProtocolHTTP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeIRC: + return kSecAttrProtocolIRC; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeNNTP: + return kSecAttrProtocolNNTP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypePOP3: + return kSecAttrProtocolPOP3; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeSMTP: + return kSecAttrProtocolSMTP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeSOCKS: + return kSecAttrProtocolSOCKS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeIMAP: + return kSecAttrProtocolIMAP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeLDAP: + return kSecAttrProtocolLDAP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeAppleTalk: + return kSecAttrProtocolAppleTalk; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeAFP: + return kSecAttrProtocolAFP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeTelnet: + return kSecAttrProtocolTelnet; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeSSH: + return kSecAttrProtocolSSH; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeFTPS: + return kSecAttrProtocolFTPS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTPS: + return kSecAttrProtocolHTTPS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTPProxy: + return kSecAttrProtocolHTTPProxy; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeHTTPSProxy: + return kSecAttrProtocolHTTPSProxy; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeFTPProxy: + return kSecAttrProtocolFTPProxy; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeSMB: + return kSecAttrProtocolSMB; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeRTSP: + return kSecAttrProtocolRTSP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeRTSPProxy: + return kSecAttrProtocolRTSPProxy; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeDAAP: + return kSecAttrProtocolDAAP; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeEPPC: + return kSecAttrProtocolEPPC; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeNNTPS: + return kSecAttrProtocolNNTPS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeLDAPS: + return kSecAttrProtocolLDAPS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeTelnetS: + return kSecAttrProtocolTelnetS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypeIRCS: + return kSecAttrProtocolIRCS; + case AWSCognitoAuthUICKeyChainStoreProtocolTypePOP3S: + return kSecAttrProtocolPOP3S; + default: + return nil; + } +} + +- (CFTypeRef)authenticationTypeObject +{ + switch (_authenticationType) { + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeNTLM: + return kSecAttrAuthenticationTypeNTLM; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeMSN: + return kSecAttrAuthenticationTypeMSN; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeDPA: + return kSecAttrAuthenticationTypeDPA; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeRPA: + return kSecAttrAuthenticationTypeRPA; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeHTTPBasic: + return kSecAttrAuthenticationTypeHTTPBasic; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeHTTPDigest: + return kSecAttrAuthenticationTypeHTTPDigest; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeHTMLForm: + return kSecAttrAuthenticationTypeHTMLForm; + case AWSCognitoAuthUICKeyChainStoreAuthenticationTypeDefault: + return kSecAttrAuthenticationTypeDefault; + default: + return nil; + } +} + +- (CFTypeRef)accessibilityObject +{ + switch (_accessibility) { + case AWSCognitoAuthUICKeyChainStoreAccessibilityWhenUnlocked: + return kSecAttrAccessibleWhenUnlocked; + case AWSCognitoAuthUICKeyChainStoreAccessibilityAfterFirstUnlock: + return kSecAttrAccessibleAfterFirstUnlock; + case AWSCognitoAuthUICKeyChainStoreAccessibilityAlways: + return kSecAttrAccessibleAlways; + case AWSCognitoAuthUICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly: + return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly; + case AWSCognitoAuthUICKeyChainStoreAccessibilityWhenUnlockedThisDeviceOnly: + return kSecAttrAccessibleWhenUnlockedThisDeviceOnly; + case AWSCognitoAuthUICKeyChainStoreAccessibilityAfterFirstUnlockThisDeviceOnly: + return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + case AWSCognitoAuthUICKeyChainStoreAccessibilityAlwaysThisDeviceOnly: + return kSecAttrAccessibleAlwaysThisDeviceOnly; + default: + return nil; + } +} + ++ (NSError *)argumentError:(NSString *)message +{ + NSError *error = [NSError errorWithDomain:AWSCognitoAuthUICKeyChainStoreErrorDomain code:AWSCognitoAuthUICKeyChainStoreErrorInvalidArguments userInfo:@{NSLocalizedDescriptionKey: message}]; + NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription); + return error; +} + ++ (NSError *)conversionError:(NSString *)message +{ + NSError *error = [NSError errorWithDomain:AWSCognitoAuthUICKeyChainStoreErrorDomain code:-67594 userInfo:@{NSLocalizedDescriptionKey: message}]; + NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription); + return error; +} + ++ (NSError *)securityError:(OSStatus)status +{ + NSString *message = @"Security error has occurred."; +#if TARGET_OS_MAC && !TARGET_OS_IPHONE + CFStringRef description = SecCopyErrorMessageString(status, NULL); + if (description) { + message = (__bridge_transfer NSString *)description; + } +#endif + NSError *error = [NSError errorWithDomain:AWSCognitoAuthUICKeyChainStoreErrorDomain code:status userInfo:@{NSLocalizedDescriptionKey: message}]; + NSLog(@"OSStatus error: [%@] %@", @(error.code), error.localizedDescription); + return error; +} + ++ (NSError *)unexpectedError:(NSString *)message +{ + NSError *error = [NSError errorWithDomain:AWSCognitoAuthUICKeyChainStoreErrorDomain code:-99999 userInfo:@{NSLocalizedDescriptionKey: message}]; + NSLog(@"error: [%@] %@", @(error.code), error.localizedDescription); + return error; +} + +@end diff --git a/AWSCognitoAuth/Internal/UICKeyChainStore/LICENSE b/AWSCognitoAuth/Internal/UICKeyChainStore/LICENSE new file mode 100644 index 00000000000..98b0edc5b04 --- /dev/null +++ b/AWSCognitoAuth/Internal/UICKeyChainStore/LICENSE @@ -0,0 +1,9 @@ +The MIT License + +Copyright (c) 2011 kishikawa katsumi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/AWSCognitoAuth/Internal/UICKeyChainStore/README.md b/AWSCognitoAuth/Internal/UICKeyChainStore/README.md new file mode 100644 index 00000000000..ea122b4ccbc --- /dev/null +++ b/AWSCognitoAuth/Internal/UICKeyChainStore/README.md @@ -0,0 +1,543 @@ +# UICKeyChainStore +[![CI Status](http://img.shields.io/travis/kishikawakatsumi/UICKeyChainStore.svg?style=flat)](https://travis-ci.org/kishikawakatsumi/UICKeyChainStore) +[![Coverage Status](https://img.shields.io/coveralls/kishikawakatsumi/UICKeyChainStore.svg?style=flat)](https://coveralls.io/r/kishikawakatsumi/UICKeyChainStore?branch=master) +[![Carthage Compatibility](https://img.shields.io/badge/carthage-✓-f2a77e.svg?style=flat)](https://github.com/Carthage/Carthage/) +[![Version](https://img.shields.io/cocoapods/v/UICKeyChainStore.svg?style=flat)](http://cocoadocs.org/docsets/UICKeyChainStore) +[![License](https://img.shields.io/cocoapods/l/UICKeyChainStore.svg?style=flat)](http://cocoadocs.org/docsets/UICKeyChainStore) +[![Platform](https://img.shields.io/cocoapods/p/UICKeyChainStore.svg?style=flat)](http://cocoadocs.org/docsets/UICKeyChainStore) + +UICKeyChainStore is a simple wrapper for Keychain that works on iOS and OS X. Makes using Keychain APIs as easy as NSUserDefaults. + +## Looking for the library written in Swift? + +Try [KeychainAccess](https://github.com/kishikawakatsumi/KeychainAccess). +[KeychainAccess](https://github.com/kishikawakatsumi/KeychainAccess) is next generation of UICKeyChainStore. + +## Transitioning from 1.x to 2.0 + +**`synchronize` method is deprecated. Calling this method is no longer required (Just ignored).** + +## Features + +- Simple interface +- Support access group +- [Support accessibility](#accessibility) +- [Support iCloud sharing](#icloud_sharing) +- **[Support TouchID and Keychain integration (iOS 8+)](#touch_id_integration)** +- **[Support Shared Web Credentials (iOS 8+)](#shared_web_credentials)** +- Works on both iOS & OS X + +## Usage + +### Basics + +#### Saving Application Password + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; +keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"; +``` + +#### Saving Internet Password + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS]; +keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"; +``` + +### Instantiation + +#### Create Keychain for Application Password + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; +``` + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"kishikawakatsumi.git" + accessGroup:@"12ABCD3E4F.shared"]; +``` + +#### Create Keychain for Internet Password + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS]; +``` + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS + authenticationType:UICKeyChainStoreAuthenticationTypeHTMLForm]; +``` + +### Adding an item + +#### subscripting + +```objective-c +keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef" +``` + +#### set method + +```objective-c +[keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi"]; +``` + +#### error handling + +```objective-c +if (![keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi"]) { + // error has occurred +} +``` + +```objective-c +NSError *error; +[keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi" error:&error]; +if (error) { + NSLog(@"%@", error.localizedDescription); +} +``` + +### Obtaining an item + +#### subscripting (automatically converts to string) + +```objective-c +NSString *token = keychain["kishikawakatsumi"] +``` + +#### get methods + +##### as String + +```objective-c +NSString *token = [keychain stringForKey:@"kishikawakatsumi"]; +``` + +##### as NSData + +```objective-c +NSData *data = [keychain dataForKey:@"kishikawakatsumi"]; +``` + +#### error handling + +**First, get the `failable` (value or error) object** + +```objective-c +NSError *error; +NSString *token = [keychain stringForKey:@"" error:&error]; +if (error) { + NSLog(@"%@", error.localizedDescription); +} +``` + +### Removing an item + +#### subscripting + +```objective-c +keychain["kishikawakatsumi"] = nil +``` + +#### remove method + +```objective-c +[keychain removeItemForKey:@"kishikawakatsumi"]; +``` + +#### error handling + +```objective-c +if (![keychain removeItemForKey:@"kishikawakatsumi"]) { + // error has occurred +} +``` + +```objective-c +NSError *error; +[keychain removeItemForKey:@"kishikawakatsumi" error:&error]; +if (error) { + NSLog(@"%@", error.localizedDescription); +} +``` + +### Label and Comment + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS]; +[keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" + forKey:@"kishikawakatsumi" + label:@"github.com (kishikawakatsumi)" + comment:@"github access token"]; +``` + +### Configuration (Accessibility, Sharing, iCould Sync) + +#### Accessibility + +##### Default accessibility matches background application (=kSecAttrAccessibleAfterFirstUnlock) + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; +``` + +##### For background application + +###### Creating instance + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; +keychain.accessibility = UICKeyChainStoreAccessibilityAfterFirstUnlock; + +keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef" +``` + +##### For foreground application + +###### Creating instance + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; +keychain.accessibility = UICKeyChainStoreAccessibilityWhenUnlocked; + +keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef" +``` + +#### Sharing Keychain items + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"kishikawakatsumi.git" + accessGroup:@"12ABCD3E4F.shared"]; +``` + +#### Synchronizing Keychain items with iCloud + +###### Creating instance + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; +keychain.synchronizable = YES; + +keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef" +``` + +### Touch ID integration + +**Any Operation that require authentication must be run in the background thread.** +**If you run in the main thread, UI thread will lock for the system to try to display the authentication dialog.** + +#### Adding a Touch ID protected item + +If you want to store the Touch ID protected Keychain item, specify `accessibility` and `authenticationPolicy` attributes. + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; + +dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [keychain setAccessibility:UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly + authenticationPolicy:UICKeyChainStoreAuthenticationPolicyUserPresence]; + + keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef" +}); +``` + +#### Updating a Touch ID protected item + +The same way as when adding. + +**Do not run in the main thread if there is a possibility that the item you are trying to add already exists, and protected.** +**Because updating protected items requires authentication.** + +Additionally, you want to show custom authentication prompt message when updating, specify an `authenticationPrompt` attribute. +If the item not protected, the `authenticationPrompt` parameter just be ignored. + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; + +dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [keychain setAccessibility:UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly + authenticationPolicy:UICKeyChainStoreAuthenticationPolicyUserPresence]; + keychain.authenticationPrompt = @"Authenticate to update your access token"; + + keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef" +}); +``` + +#### Obtaining a Touch ID protected item + +The same way as when you get a normal item. It will be displayed automatically Touch ID or passcode authentication If the item you try to get is protected. +If you want to show custom authentication prompt message, specify an `authenticationPrompt` attribute. +If the item not protected, the `authenticationPrompt` parameter just be ignored. + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; + +dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [keychain setAccessibility:UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly + authenticationPolicy:UICKeyChainStoreAuthenticationPolicyUserPresence]; + keychain.authenticationPrompt = @"Authenticate to update your access token"; + + NSString *token = keychain[@"kishikawakatsumi"]; +}); +``` + +#### Removing a Touch ID protected item + +The same way as when you remove a normal item. +There is no way to show Touch ID or passcode authentication when removing Keychain items. + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"]; + +keychain[@"kishikawakatsumi"] = nil; +``` + +### Shared Web Credentials + +> Shared web credentials is a programming interface that enables native iOS apps to share credentials with their website counterparts. For example, a user may log in to a website in Safari, entering a user name and password, and save those credentials using the iCloud Keychain. Later, the user may run a native app from the same developer, and instead of the app requiring the user to reenter a user name and password, shared web credentials gives it access to the credentials that were entered earlier in Safari. The user can also create new accounts, update passwords, or delete her account from within the app. These changes are then saved and used by Safari. + + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://kishikawakatsumi.com"] +protocolType:UICKeyChainStoreProtocolTypeHTTPS]; +NSString *username = @"kishikawakatsumi@mac.com"; +NSString *password = keychain[username]; +if (password) { + // If found password in the Keychain, + // then log into the server +} else { + // If not found password in the Keychain, + // try to read from Shared Web Credentials + [keychain sharedPasswordForAccount:username completion:^(NSString *password, NSError *error) { + if (password) { + // If found password in the Shared Web Credentials, + // then log into the server + // and save the password to the Keychain + + keychain[username] = password + } else { + // If not found password either in the Keychain also Shared Web Credentials, + // prompt for username and password + + // Log into server + + // If the login is successful, + // save the credentials to both the Keychain and the Shared Web Credentials. + + keychain[username] = password + [keychain setSharedPassword:password forAccount:username completion:nil]; + } + }]; +} +``` + +#### Request all associated domain's credentials + +```objective-c +[UICKeyChainStore requestSharedWebCredentialWithCompletion:^(NSArray *credentials, NSError *error) { + +}]; +``` + +#### Generate strong random password + +Generate strong random password that is in the same format used by Safari autofill (xxx-xxx-xxx-xxx). + +```objective-c +NSString *password = [UICKeyChainStore generatePassword]; +NSLog(@"%@", password); // => Nhu-GKm-s3n-pMx +``` + +#### How to set up Shared Web Credentials + +> 1. Add a com.apple.developer.associated-domains entitlement to your app. This entitlement must include all the domains with which you want to share credentials. + +> 2. Add an apple-app-site-association file to your website. This file must include application identifiers for all the apps with which the site wants to share credentials, and it must be properly signed. + +> 3. When the app is installed, the system downloads and verifies the site association file for each of its associated domains. If the verification is successful, the app is associated with the domain. + +**More details:** + + +### Debugging + +#### Display all stored items if print keychain object + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS]; +NSLog(@"%@", keychain); +``` + +``` +=> +( +{ + accessibility = ak; + authenticationType = dflt; + class = InternetPassword; + key = kishikawakatsumi; + protocol = htps; + server = "github.com"; + synchronizable = 0; + value = "01234567-89ab-cdef-0123-456789abcdef"; +} { + accessibility = ck; + authenticationType = dflt; + class = InternetPassword; + key = hirohamada; + protocol = htps; + server = "github.com"; + synchronizable = 1; + value = "11111111-89ab-cdef-1111-456789abcdef"; +} { + accessibility = ak; + authenticationType = dflt; + class = InternetPassword; + key = honeylemon; + protocol = htps; + server = "github.com"; + synchronizable = 0; + value = "22222222-89ab-cdef-2222-456789abcdef"; +}) +``` + +#### Obtaining all stored keys + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS]; + +NSArray *keys = keychain.allKeys; +for (NSString *key in keys) { + NSLog(@"key: %@", key); +} +``` + +``` +=> +key: kishikawakatsumi +key: hirohamada +key: honeylemon +``` + +#### Obtaining all stored items + +```objective-c +UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"] + protocolType:UICKeyChainStoreProtocolTypeHTTPS]; + +NSArray *items = keychain.allItems; +for (NSString *item in items) { + NSLog(@"item: %@", item); +} +``` + +``` +=> + +item: { + accessibility = ak; + authenticationType = dflt; + class = InternetPassword; + key = kishikawakatsumi; + protocol = htps; + server = "github.com"; + synchronizable = 0; + value = "01234567-89ab-cdef-0123-456789abcdef"; +} +item: { + accessibility = ck; + authenticationType = dflt; + class = InternetPassword; + key = hirohamada; + protocol = htps; + server = "github.com"; + synchronizable = 1; + value = "11111111-89ab-cdef-1111-456789abcdef"; +} +item: { + accessibility = ak; + authenticationType = dflt; + class = InternetPassword; + key = honeylemon; + protocol = htps; + server = "github.com"; + synchronizable = 0; + value = "22222222-89ab-cdef-2222-456789abcdef"; +} +``` + +### Convienient class methods + +Add items using default service name (=bundle identifer). + +```objective-c +[UICKeyChainStore setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi"]; +``` + +Or specify the service name. + +```objective-c +[UICKeyChainStore setString:@"01234567-89ab-cdef-0123-456789abcdef" + forKey:@"kishikawakatsumi" + service:@"com.example.github-token"]; +``` + +--- +Remove items. + +```objective-c +[UICKeyChainStore removeItemForKey:@"kishikawakatsumi" service:@"com.example.github-token"]; +``` + +To set nil value also works remove item for the key. + +```objective-c +[UICKeyChainStore setString:nil forKey:@"kishikawakatsumi" service:@"com.example.github-token"]; +``` + +## Requirements + +iOS 4.3 or later +OS X 10.7 or later + +## Installation + +### CocoaPods + +UICKeyChainStore is available through [CocoaPods](http://cocoapods.org). To install +it, simply add the following line to your Podfile: + +`pod 'UICKeyChainStore'` + +### Carthage + +UICKeyChainStore is available through [Carthage](https://github.com/Carthage/Carthage). To install +it, simply add the following line to your Cartfile: + +`github "kishikawakatsumi/UICKeyChainStore"` + +### To manually add to your project + +1. Add `Security.framework` to your target. +2. Copy files in Lib (`UICKeyChainStore.h` and `UICKeyChainStore.m`) to your project. + +## Author + +kishikawa katsumi, kishikawakatsumi@mac.com + +## License + +[Apache]: http://www.apache.org/licenses/LICENSE-2.0 +[MIT]: http://www.opensource.org/licenses/mit-license.php +[GPL]: http://www.gnu.org/licenses/gpl.html +[BSD]: http://opensource.org/licenses/bsd-license.php + +UICKeyChainStore is available under the [MIT license][MIT]. See the LICENSE file for more info. diff --git a/AWSCognitoAuthTests/AWSCognitoAuthTests.m b/AWSCognitoAuthTests/AWSCognitoAuthTests.m new file mode 100644 index 00000000000..432f97eef52 --- /dev/null +++ b/AWSCognitoAuthTests/AWSCognitoAuthTests.m @@ -0,0 +1,24 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import + +@interface AWSCognitoAuthTests : XCTestCase + +@end + +@implementation AWSCognitoAuthTests + +@end diff --git a/AWSCognitoAuthTests/Info.plist b/AWSCognitoAuthTests/Info.plist new file mode 100644 index 00000000000..f53b496c44b --- /dev/null +++ b/AWSCognitoAuthTests/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + LSApplicationCategoryType + + NSAppTransportSecurity + + NSExceptionDomains + + corp.amazon.com + + NSThirdPartyExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + NSIncludesSubdomains + + + + + + diff --git a/AWSCognitoAuthUnitTests/AWSCognitoAuthUnitTests.m b/AWSCognitoAuthUnitTests/AWSCognitoAuthUnitTests.m new file mode 100644 index 00000000000..c98279f7db4 --- /dev/null +++ b/AWSCognitoAuthUnitTests/AWSCognitoAuthUnitTests.m @@ -0,0 +1,34 @@ +// +// Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/apache2.0 +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. +// + +#import + +@interface AWSCognitoAuthUnitTests : XCTestCase + +@end + +@implementation AWSCognitoAuthUnitTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +@end diff --git a/AWSCognitoAuthUnitTests/Info.plist b/AWSCognitoAuthUnitTests/Info.plist new file mode 100644 index 00000000000..ba72822e872 --- /dev/null +++ b/AWSCognitoAuthUnitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/AWSCognitoIdentityProvider.podspec b/AWSCognitoIdentityProvider.podspec index 85c983f236a..bfc88ece660 100644 --- a/AWSCognitoIdentityProvider.podspec +++ b/AWSCognitoIdentityProvider.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSCognitoIdentityProvider' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Cognito Identity Provider SDK for iOS (Beta)' s.description = 'Amazon Cognito Identity Provider enables sign up and authentication of your end users' @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSCognitoIdentityProvider/**/*.{h,m,c}' s.public_header_files = 'AWSCognitoIdentityProvider/*.h', 'AWSCognitoIdentityProvider/CognitoIdentityProvider/*.h' s.private_header_files = 'AWSCognitoIdentityProvider/Internal/*.h' diff --git a/AWSCognitoIdentityProvider/AWSCognitoIdentityUserPool.m b/AWSCognitoIdentityProvider/AWSCognitoIdentityUserPool.m index 054f63c20ab..c2b4b3a60f3 100644 --- a/AWSCognitoIdentityProvider/AWSCognitoIdentityUserPool.m +++ b/AWSCognitoIdentityProvider/AWSCognitoIdentityUserPool.m @@ -247,7 +247,7 @@ - (NSString *) calculateSecretHash: (NSString*) userName; return nil; const char *cKey = [self.userPoolConfiguration.clientSecret cStringUsingEncoding:NSASCIIStringEncoding]; - const char *cData = [[userName stringByAppendingString:self.userPoolConfiguration.clientId] cStringUsingEncoding:NSASCIIStringEncoding]; + const char *cData = [[userName stringByAppendingString:self.userPoolConfiguration.clientId] cStringUsingEncoding:NSUTF8StringEncoding]; unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; diff --git a/AWSCognitoIdentityProvider/CognitoIdentityProvider/AWSCognitoIdentityProviderService.m b/AWSCognitoIdentityProvider/CognitoIdentityProvider/AWSCognitoIdentityProviderService.m index 05e7a328448..ac5bb668a3a 100644 --- a/AWSCognitoIdentityProvider/CognitoIdentityProvider/AWSCognitoIdentityProviderService.m +++ b/AWSCognitoIdentityProvider/CognitoIdentityProvider/AWSCognitoIdentityProviderService.m @@ -26,7 +26,7 @@ #import "AWSCognitoIdentityProviderResources.h" static NSString *const AWSInfoCognitoIdentityProvider = @"CognitoIdentityProvider"; -static NSString *const AWSCognitoIdentityProviderSDKVersion = @"2.5.7"; +static NSString *const AWSCognitoIdentityProviderSDKVersion = @"2.5.8"; @interface AWSCognitoIdentityProviderResponseSerializer : AWSJSONResponseSerializer @@ -116,7 +116,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSCognitoIdentityProvider/Info.plist b/AWSCognitoIdentityProvider/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSCognitoIdentityProvider/Info.plist +++ b/AWSCognitoIdentityProvider/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSCognitoSync.podspec b/AWSCognitoSync.podspec index f22608f053b..56c9e1dd0fd 100644 --- a/AWSCognitoSync.podspec +++ b/AWSCognitoSync.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'AWSCognitoSync' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Cognito SDK for iOS' s.description = 'Amazon Cognito offers multi device data synchronization with offline access' @@ -14,7 +14,7 @@ Pod::Spec.new do |s| :tag => s.version} s.requires_arc = true s.library = 'sqlite3' - s.dependency 'AWSCognito', '2.5.7' + s.dependency 'AWSCognito', '2.5.8' s.deprecated = true s.deprecated_in_favor_of = 'AWSCognito' diff --git a/AWSCognitoTests/CognitoTestUtils.m b/AWSCognitoTests/CognitoTestUtils.m index a068505ba8e..95359770550 100644 --- a/AWSCognitoTests/CognitoTestUtils.m +++ b/AWSCognitoTests/CognitoTestUtils.m @@ -79,13 +79,12 @@ + (void)createFBAccount { // Get the FB APP access token NSString *raw_response = [NSString stringWithContentsOfURL:[NSURL URLWithString:accessURI] encoding:NSUTF8StringEncoding error:nil]; - NSRange startOfToken = [raw_response rangeOfString:@"="]; - // Strip the 'access_token=' so we can easily encode result - _facebookAppToken = [[raw_response substringFromIndex:startOfToken.location + 1] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + NSDictionary *accessTokenDictionary = [NSJSONSerialization JSONObjectWithData:[raw_response dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:nil]; + NSString *accessToken = accessTokenDictionary[@"access_token"]; // Add a new test user, the result contains an access key we can use to test assume role - NSString *addUserURI = [NSString stringWithFormat:@"https://graph.facebook.com/%@/accounts/test-users?installed=true&name=Foo%%20Bar&locale=en_US&permissions=read_stream&method=post&access_token=%@", AWSCognitoClientTestsFacebookAppID, _facebookAppToken]; - + NSString *addUserURI = [NSString stringWithFormat:@"https://graph.facebook.com/%@/accounts/test-users?installed=true&name=Foo%%20Bar&locale=en_US&permissions=read_stream&method=post&access_token=%@", AWSCognitoClientTestsFacebookAppID, [accessToken aws_stringWithURLEncodingPath]]; + NSString *newUser = [NSString stringWithContentsOfURL:[NSURL URLWithString:addUserURI] encoding:NSASCIIStringEncoding error:nil]; NSDictionary *user = [NSJSONSerialization JSONObjectWithData: [newUser dataUsingEncoding:NSUTF8StringEncoding] options: NSJSONReadingMutableContainers diff --git a/AWSCore.podspec b/AWSCore.podspec index 967159fa68c..b1d85176878 100644 --- a/AWSCore.podspec +++ b/AWSCore.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'AWSCore' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' diff --git a/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m b/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m index 70584c305c6..161e5f41628 100644 --- a/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m +++ b/AWSCore/CognitoIdentity/AWSCognitoIdentityService.m @@ -98,7 +98,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSCore/Info.plist b/AWSCore/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSCore/Info.plist +++ b/AWSCore/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSCore/STS/AWSSTSService.m b/AWSCore/STS/AWSSTSService.m index 148be42ccf6..211d872a21a 100644 --- a/AWSCore/STS/AWSSTSService.m +++ b/AWSCore/STS/AWSSTSService.m @@ -63,23 +63,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSSTSErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSSTSErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSSTSErrorDomain + code:AWSSTSErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -95,7 +96,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSCore/Service/AWSService.m b/AWSCore/Service/AWSService.m index 4208cbe8771..57e26494fe8 100644 --- a/AWSCore/Service/AWSService.m +++ b/AWSCore/Service/AWSService.m @@ -21,7 +21,7 @@ #import "AWSCocoaLumberjack.h" #import "AWSCategory.h" -NSString *const AWSiOSSDKVersion = @"2.5.7"; +NSString *const AWSiOSSDKVersion = @"2.5.8"; NSString *const AWSServiceErrorDomain = @"com.amazonaws.AWSServiceErrorDomain"; static NSString *const AWSServiceConfigurationUnknown = @"Unknown"; diff --git a/AWSDynamoDB.podspec b/AWSDynamoDB.podspec index 521dedbd168..8ee08584543 100644 --- a/AWSDynamoDB.podspec +++ b/AWSDynamoDB.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSDynamoDB' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSDynamoDB/*.{h,m}' end diff --git a/AWSDynamoDB/AWSDynamoDBService.m b/AWSDynamoDB/AWSDynamoDBService.m index caf7f8e4716..07b4f1d77d4 100644 --- a/AWSDynamoDB/AWSDynamoDBService.m +++ b/AWSDynamoDB/AWSDynamoDBService.m @@ -27,7 +27,7 @@ #import "AWSDynamoDBRequestRetryHandler.h" static NSString *const AWSInfoDynamoDB = @"DynamoDB"; -static NSString *const AWSDynamoDBSDKVersion = @"2.5.7"; +static NSString *const AWSDynamoDBSDKVersion = @"2.5.8"; @interface AWSDynamoDBResponseSerializer : AWSJSONResponseSerializer @@ -96,7 +96,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSDynamoDB/Info.plist b/AWSDynamoDB/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSDynamoDB/Info.plist +++ b/AWSDynamoDB/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSEC2.podspec b/AWSEC2.podspec index 8ec1fadea64..19f1910856f 100644 --- a/AWSEC2.podspec +++ b/AWSEC2.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSEC2' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSEC2/*.{h,m}' end diff --git a/AWSEC2/AWSEC2Service.m b/AWSEC2/AWSEC2Service.m index ccb0de99f99..c736025e80f 100644 --- a/AWSEC2/AWSEC2Service.m +++ b/AWSEC2/AWSEC2Service.m @@ -27,7 +27,7 @@ #import "AWSEC2Serializer.h" static NSString *const AWSInfoEC2 = @"EC2"; -static NSString *const AWSEC2SDKVersion = @"2.5.7"; +static NSString *const AWSEC2SDKVersion = @"2.5.8"; @interface AWSEC2ResponseSerializer : AWSXMLResponseSerializer @@ -89,7 +89,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSEC2/Info.plist b/AWSEC2/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSEC2/Info.plist +++ b/AWSEC2/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSElasticLoadBalancing.podspec b/AWSElasticLoadBalancing.podspec index 82792f72ac3..b164085d699 100644 --- a/AWSElasticLoadBalancing.podspec +++ b/AWSElasticLoadBalancing.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSElasticLoadBalancing' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSElasticLoadBalancing/*.{h,m}' end diff --git a/AWSElasticLoadBalancing/AWSElasticLoadBalancingService.m b/AWSElasticLoadBalancing/AWSElasticLoadBalancingService.m index 6887865a4f5..2715f25910b 100644 --- a/AWSElasticLoadBalancing/AWSElasticLoadBalancingService.m +++ b/AWSElasticLoadBalancing/AWSElasticLoadBalancingService.m @@ -26,7 +26,7 @@ #import "AWSElasticLoadBalancingResources.h" static NSString *const AWSInfoElasticLoadBalancing = @"ElasticLoadBalancing"; -static NSString *const AWSElasticLoadBalancingSDKVersion = @"2.5.7"; +static NSString *const AWSElasticLoadBalancingSDKVersion = @"2.5.8"; @interface AWSElasticLoadBalancingResponseSerializer : AWSXMLResponseSerializer @@ -77,23 +77,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSElasticLoadBalancingErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSElasticLoadBalancingErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSElasticLoadBalancingErrorDomain + code:AWSElasticLoadBalancingErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -109,7 +110,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSElasticLoadBalancing/Info.plist b/AWSElasticLoadBalancing/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSElasticLoadBalancing/Info.plist +++ b/AWSElasticLoadBalancing/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSElasticLoadBalancingTests/AWSElasticLoadBalancingTests.m b/AWSElasticLoadBalancingTests/AWSElasticLoadBalancingTests.m index ef13d76d71e..33b6163d437 100644 --- a/AWSElasticLoadBalancingTests/AWSElasticLoadBalancingTests.m +++ b/AWSElasticLoadBalancingTests/AWSElasticLoadBalancingTests.m @@ -93,6 +93,9 @@ - (void)testConfigureHealthCheckFailed { [[[elb configureHealthCheck:healthCheckInput] continueWithBlock:^id(AWSTask *task) { XCTAssertNotNil(task.error, @"expected Validation Error, but got nil"); + XCTAssertEqual(task.error.code, 0); + XCTAssertTrue([@"ValidationError" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"LoadBalancer name cannot be empty" isEqualToString:task.error.userInfo[@"Message"]]); return nil; }] waitUntilFinished]; } diff --git a/AWSIoT.podspec b/AWSIoT.podspec index 92738530ad6..109b882845d 100644 --- a/AWSIoT.podspec +++ b/AWSIoT.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSIoT' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSIoT/*.{h,m}', 'AWSIoT/**/*.{h,m}' s.private_header_files = 'AWSIoT/Internal/*.h' end diff --git a/AWSIoT/AWSIoTDataManager.h b/AWSIoT/AWSIoTDataManager.h index 664bb47f575..0f00b250025 100644 --- a/AWSIoT/AWSIoTDataManager.h +++ b/AWSIoT/AWSIoTDataManager.h @@ -170,7 +170,7 @@ typedef void(^AWSIoTMQTTExtendedNewMessageBlock)(NSObject *mqttClient, NSString @return The default service client. */ -+ (instancetype)defaultIoTDataManager; ++ (instancetype)defaultIoTDataManager __attribute__ ((deprecated("Use `registerIoTDataManagerWithConfiguration:forKey:` with the custom endpoint to initialize AWSIoTDataManager"))); /** Creates a service client with the given service configuration and registers it for the key. diff --git a/AWSIoT/AWSIoTDataManager.m b/AWSIoT/AWSIoTDataManager.m index e40c3b653fc..d941e319065 100644 --- a/AWSIoT/AWSIoTDataManager.m +++ b/AWSIoT/AWSIoTDataManager.m @@ -182,6 +182,9 @@ + (void)registerIoTDataManagerWithConfiguration:(AWSServiceConfiguration *)confi dispatch_once(&onceToken, ^{ _serviceClients = [AWSSynchronizedMutableDictionary new]; }); + if( !configuration.endpoint){ + AWSDDLogWarn(@"The endpoint is not set. You should use custom endpoint when initializing AWSServiceConfiguration"); + } [_serviceClients setObject:[[AWSIoTDataManager alloc] initWithConfiguration:configuration] forKey:key]; } @@ -196,8 +199,9 @@ + (instancetype)IoTDataManagerForKey:(NSString *)key { AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] serviceInfo:AWSInfoIoTDataManager forKey:key]; if (serviceInfo) { - AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region - credentialsProvider:serviceInfo.cognitoCredentialsProvider]; + AWSServiceConfiguration *serviceConfiguration = + [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region + credentialsProvider:serviceInfo.cognitoCredentialsProvider]; [AWSIoTDataManager registerIoTDataManagerWithConfiguration:serviceConfiguration forKey:key]; } diff --git a/AWSIoT/AWSIoTDataService.h b/AWSIoT/AWSIoTDataService.h index ddf66bd962d..c3161309a9a 100644 --- a/AWSIoT/AWSIoTDataService.h +++ b/AWSIoT/AWSIoTDataService.h @@ -71,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN @return The default service client. */ -+ (instancetype)defaultIoTData; ++ (instancetype)defaultIoTData __attribute__ ((deprecated("Use `registerIoTDataManagerWithConfiguration:forKey:` with custom endpoint to initialize AWSIoTData"))); /** Creates a service client with the given service configuration and registers it for the key. diff --git a/AWSIoT/AWSIoTDataService.m b/AWSIoT/AWSIoTDataService.m index c3cd07e0f72..026f2dede53 100644 --- a/AWSIoT/AWSIoTDataService.m +++ b/AWSIoT/AWSIoTDataService.m @@ -26,7 +26,7 @@ #import "AWSIoTDataResources.h" static NSString *const AWSInfoIoTData = @"IoTData"; -static NSString *const AWSIoTDataSDKVersion = @"2.5.7"; +static NSString *const AWSIoTDataSDKVersion = @"2.5.8"; @interface AWSIoTDataResponseSerializer : AWSJSONResponseSerializer @@ -103,7 +103,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSIoT/AWSIoTService.m b/AWSIoT/AWSIoTService.m index e17a967fe1c..88c9cc9110e 100644 --- a/AWSIoT/AWSIoTService.m +++ b/AWSIoT/AWSIoTService.m @@ -26,7 +26,7 @@ #import "AWSIoTResources.h" static NSString *const AWSInfoIoT = @"IoT"; -static NSString *const AWSIoTSDKVersion = @"2.5.7"; +static NSString *const AWSIoTSDKVersion = @"2.5.8"; @interface AWSIoTResponseSerializer : AWSJSONResponseSerializer @@ -113,7 +113,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSIoT/Info.plist b/AWSIoT/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSIoT/Info.plist +++ b/AWSIoT/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSKMS.podspec b/AWSKMS.podspec index a988d050358..ee2f0d47b59 100644 --- a/AWSKMS.podspec +++ b/AWSKMS.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSKMS' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSKMS/*.{h,m}' end diff --git a/AWSKMS/AWSKMSService.m b/AWSKMS/AWSKMSService.m index 067cc309529..9ab391153b8 100644 --- a/AWSKMS/AWSKMSService.m +++ b/AWSKMS/AWSKMSService.m @@ -26,7 +26,7 @@ #import "AWSKMSResources.h" static NSString *const AWSInfoKMS = @"KMS"; -static NSString *const AWSKMSSDKVersion = @"2.5.7"; +static NSString *const AWSKMSSDKVersion = @"2.5.8"; @interface AWSKMSResponseSerializer : AWSJSONResponseSerializer @@ -109,7 +109,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSKMS/Info.plist b/AWSKMS/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSKMS/Info.plist +++ b/AWSKMS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSKinesis.podspec b/AWSKinesis.podspec index a861626bd1f..06ab0004326 100644 --- a/AWSKinesis.podspec +++ b/AWSKinesis.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSKinesis' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSKinesis/*.{h,m}' end diff --git a/AWSKinesis/AWSFirehoseService.m b/AWSKinesis/AWSFirehoseService.m index 69f48b33aa3..9d792d1684f 100644 --- a/AWSKinesis/AWSFirehoseService.m +++ b/AWSKinesis/AWSFirehoseService.m @@ -26,7 +26,7 @@ #import "AWSFirehoseResources.h" static NSString *const AWSInfoFirehose = @"Firehose"; -static NSString *const AWSFirehoseSDKVersion = @"2.5.7"; +static NSString *const AWSFirehoseSDKVersion = @"2.5.8"; @interface AWSFirehoseResponseSerializer : AWSJSONResponseSerializer @@ -94,7 +94,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSKinesis/AWSKinesisService.m b/AWSKinesis/AWSKinesisService.m index 69ef1c72ac9..1c1867ae31e 100644 --- a/AWSKinesis/AWSKinesisService.m +++ b/AWSKinesis/AWSKinesisService.m @@ -27,7 +27,7 @@ #import "AWSKinesisRequestRetryHandler.h" static NSString *const AWSInfoKinesis = @"Kinesis"; -static NSString *const AWSKinesisSDKVersion = @"2.5.7"; +static NSString *const AWSKinesisSDKVersion = @"2.5.8"; @interface AWSKinesisResponseSerializer : AWSJSONResponseSerializer @@ -95,7 +95,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSKinesis/Info.plist b/AWSKinesis/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSKinesis/Info.plist +++ b/AWSKinesis/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSLambda.podspec b/AWSLambda.podspec index 2166fc0a6f4..b36cfd68030 100644 --- a/AWSLambda.podspec +++ b/AWSLambda.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSLambda' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSLambda/*.{h,m}' end diff --git a/AWSLambda/AWSLambdaService.m b/AWSLambda/AWSLambdaService.m index edc45ef578c..925d374c830 100644 --- a/AWSLambda/AWSLambdaService.m +++ b/AWSLambda/AWSLambdaService.m @@ -27,7 +27,7 @@ #import "AWSLambdaRequestRetryHandler.h" static NSString *const AWSInfoLambda = @"Lambda"; -static NSString *const AWSLambdaSDKVersion = @"2.5.7"; +static NSString *const AWSLambdaSDKVersion = @"2.5.8"; @interface AWSLambdaResponseSerializer : AWSJSONResponseSerializer @@ -147,6 +147,7 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response @"responseDataSize" : @(data?[data length]:0), }; } + return responseObject; } diff --git a/AWSLambda/Info.plist b/AWSLambda/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSLambda/Info.plist +++ b/AWSLambda/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSLex.podspec b/AWSLex.podspec index 94c16b776b8..5222adf8787 100644 --- a/AWSLex.podspec +++ b/AWSLex.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSLex' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSLex/*.{h,m}', 'AWSLex/Bluefront/include/*.h' s.public_header_files = 'AWSLex/*.h' s.private_header_files = 'AWSLex/Bluefront/include/*.h' diff --git a/AWSLex/AWSLexInteractionKit.m b/AWSLex/AWSLexInteractionKit.m index 421b6df1b12..7a9a1f84ed6 100644 --- a/AWSLex/AWSLexInteractionKit.m +++ b/AWSLex/AWSLexInteractionKit.m @@ -22,7 +22,7 @@ #import NSString *const AWSInfoInteractionKit = @"LexInteractionKit"; -NSString *const AWSInteractionKitSDKVersion = @"2.5.7"; +NSString *const AWSInteractionKitSDKVersion = @"2.5.8"; NSString *const AWSInternalLexInteractionKit = @"LexInteractionKitClient"; NSString *const AWSLexInteractionKitUserAgent = @"interactionkit"; NSString *const AWSLexInteractionKitErrorDomain = @"com.amazonaws.AWSLexInteractionKitErrorDomain"; diff --git a/AWSLex/AWSLexService.m b/AWSLex/AWSLexService.m index 6df0aa7a623..b9ba7e8a968 100644 --- a/AWSLex/AWSLexService.m +++ b/AWSLex/AWSLexService.m @@ -28,7 +28,7 @@ #import "AWSLexSignature.h" static NSString *const AWSInfoLex = @"Lex"; -static NSString *const AWSLexSDKVersion = @"2.5.7"; +static NSString *const AWSLexSDKVersion = @"2.5.8"; @interface AWSLexResponseSerializer : AWSJSONResponseSerializer @@ -106,7 +106,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSLex/Info.plist b/AWSLex/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSLex/Info.plist +++ b/AWSLex/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSLogs.podspec b/AWSLogs.podspec index 14faf4c59aa..d3ded77ad16 100644 --- a/AWSLogs.podspec +++ b/AWSLogs.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSLogs' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSLogs/*.{h,m}' end diff --git a/AWSLogs/AWSLogsService.m b/AWSLogs/AWSLogsService.m index baf151f733e..6a82f24c66b 100644 --- a/AWSLogs/AWSLogsService.m +++ b/AWSLogs/AWSLogsService.m @@ -26,7 +26,7 @@ #import "AWSLogsResources.h" static NSString *const AWSInfoLogs = @"Logs"; -static NSString *const AWSLogsSDKVersion = @"2.5.7"; +static NSString *const AWSLogsSDKVersion = @"2.5.8"; @interface AWSLogsResponseSerializer : AWSJSONResponseSerializer @@ -97,7 +97,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSLogs/Info.plist b/AWSLogs/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSLogs/Info.plist +++ b/AWSLogs/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSMachineLearning.podspec b/AWSMachineLearning.podspec index af97a7bacda..c9949679e7f 100644 --- a/AWSMachineLearning.podspec +++ b/AWSMachineLearning.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSMachineLearning' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSMachineLearning/*.{h,m}' end diff --git a/AWSMachineLearning/AWSMachineLearningService.m b/AWSMachineLearning/AWSMachineLearningService.m index 5a259035206..272c0b69383 100644 --- a/AWSMachineLearning/AWSMachineLearningService.m +++ b/AWSMachineLearning/AWSMachineLearningService.m @@ -26,7 +26,7 @@ #import "AWSMachineLearningResources.h" static NSString *const AWSInfoMachineLearning = @"MachineLearning"; -static NSString *const AWSMachineLearningSDKVersion = @"2.5.7"; +static NSString *const AWSMachineLearningSDKVersion = @"2.5.8"; diff --git a/AWSMachineLearning/Info.plist b/AWSMachineLearning/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSMachineLearning/Info.plist +++ b/AWSMachineLearning/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSMobileAnalytics.podspec b/AWSMobileAnalytics.podspec index c1d808927ba..1e5f5a8cc09 100644 --- a/AWSMobileAnalytics.podspec +++ b/AWSMobileAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSMobileAnalytics' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSMobileAnalytics/*.{h,m}', 'AWSMobileAnalytics/**/*.{h,m}' s.private_header_files = 'AWSMobileAnalytics/Internal/*.h' end diff --git a/AWSMobileAnalytics/AWSMobileAnalyticsERS/AWSMobileAnalyticsERSService.m b/AWSMobileAnalytics/AWSMobileAnalyticsERS/AWSMobileAnalyticsERSService.m index 5855654317e..d3b2c43a1bd 100644 --- a/AWSMobileAnalytics/AWSMobileAnalyticsERS/AWSMobileAnalyticsERSService.m +++ b/AWSMobileAnalytics/AWSMobileAnalyticsERS/AWSMobileAnalyticsERSService.m @@ -26,7 +26,7 @@ #import "AWSMobileAnalyticsERSResources.h" static NSString *const AWSInfoMobileAnalyticsERS = @"MobileAnalyticsERS"; -static NSString *const AWSMobileAnalyticsERSSDKVersion = @"2.5.7"; +static NSString *const AWSMobileAnalyticsERSSDKVersion = @"2.5.8"; @interface AWSMobileAnalyticsERSResponseSerializer : AWSJSONResponseSerializer @@ -129,6 +129,7 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response @"responseDataSize" : @(data?[data length]:0), }; } + return responseObject; } diff --git a/AWSMobileAnalytics/Info.plist b/AWSMobileAnalytics/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSMobileAnalytics/Info.plist +++ b/AWSMobileAnalytics/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSPinpoint.podspec b/AWSPinpoint.podspec index 35c092df93f..be8f47fa8dc 100644 --- a/AWSPinpoint.podspec +++ b/AWSPinpoint.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSPinpoint' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSPinpoint/*.{h,m}', 'AWSPinpoint/**/*.{h,m}' s.private_header_files = 'AWSPinpoint/Internal/*.h' end diff --git a/AWSPinpoint/AWSPinpointAnalytics/AWSPinpointAnalyticsService.m b/AWSPinpoint/AWSPinpointAnalytics/AWSPinpointAnalyticsService.m index 56a08c004f8..6af445f7479 100644 --- a/AWSPinpoint/AWSPinpointAnalytics/AWSPinpointAnalyticsService.m +++ b/AWSPinpoint/AWSPinpointAnalytics/AWSPinpointAnalyticsService.m @@ -26,7 +26,7 @@ #import "AWSPinpointAnalyticsResources.h" static NSString *const AWSInfoPinpointAnalytics = @"PinpointAnalytics"; -static NSString *const AWSPinpointAnalyticsSDKVersion = @"2.5.7"; +static NSString *const AWSPinpointAnalyticsSDKVersion = @"2.5.8"; @interface AWSPinpointAnalyticsResponseSerializer : AWSJSONResponseSerializer @@ -129,6 +129,7 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response @"responseDataSize" : @(data?[data length]:0), }; } + return responseObject; } diff --git a/AWSPinpoint/AWSPinpointConfiguration.h b/AWSPinpoint/AWSPinpointConfiguration.h index c3c312fd624..7b82d6c5873 100644 --- a/AWSPinpoint/AWSPinpointConfiguration.h +++ b/AWSPinpoint/AWSPinpointConfiguration.h @@ -69,6 +69,16 @@ typedef void(^AWSInitializationCompletionBlock)(AWSPinpoint * _Nonnull pinpoint) */ @property (nonatomic, assign) BOOL enableAutoSessionRecording; +/** + Optional block that indicates whether or not targeting client should set application level OptOut. + Use this block to configure whether or not client should receive push notifications at an application level. + If system level notifications for this application are disabled, the result of this block will be ignored. + Defaults to NULL. + + @returns YES/NO indicating if application level OptOut is set + */ +@property (nonatomic, copy) BOOL (^isApplicationLevelOptOut)(void); + /** A service configuration object to be used for Pinpoint Analytics. Defaults to [AWSServiceManager defaultServiceManager].defaultServiceConfiguration diff --git a/AWSPinpoint/AWSPinpointEndpointProfile.h b/AWSPinpoint/AWSPinpointEndpointProfile.h index 0f5ae2f53d3..20ff7bf873a 100644 --- a/AWSPinpoint/AWSPinpointEndpointProfile.h +++ b/AWSPinpoint/AWSPinpointEndpointProfile.h @@ -88,6 +88,12 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype) initWithApplicationId:(NSString*) applicationId endpointId:(NSString*) endpointId; +/** + An AWSPinpointEndpointProfile object with the specified context + @returns AWSPinpointEndpointProfile + */ +- (instancetype)initWithContext:(AWSPinpointContext *) context; + /** Adds an attribute to this AWSPinpointEndpointProfile with the specified key. Only 40 attributes/metrics are allowed to be added to an AWSPinpointEndpointProfile. If 40 attributes/metrics already exist on this AWSPinpointEndpointProfile, the call is ignored. diff --git a/AWSPinpoint/AWSPinpointEndpointProfile.m b/AWSPinpoint/AWSPinpointEndpointProfile.m index 51830f84a0b..40387bd0cb6 100644 --- a/AWSPinpoint/AWSPinpointEndpointProfile.m +++ b/AWSPinpoint/AWSPinpointEndpointProfile.m @@ -16,6 +16,7 @@ #import #import "AWSPinpointEndpointProfile.h" #import "AWSPinpointContext.h" +#import "AWSPinpointConfiguration.h" #import "AWSPinpointNotificationManager.h" #import "AWSPinpointStringUtils.h" #import "AWSPinpointDateUtils.h" @@ -41,16 +42,12 @@ @implementation AWSPinpointEndpointProfile NSString *CHANNEL_TYPE = @"APNS"; - (instancetype) initWithApplicationId:(NSString*) applicationId - endpointId:(NSString*) endpointId { + endpointId:(NSString*) endpointId + applicationLevelOptOut:(BOOL) applicationLevelOptOut { if (self = [super init]) { //Remove spaces and brackets from token NSString *deviceTokenString = [[[[[NSUserDefaults standardUserDefaults] objectForKey:AWSDeviceTokenKey] description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""]; - - BOOL optOut = ![[UIApplication sharedApplication] isRegisteredForRemoteNotifications]; - if ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone) { - optOut = YES; - } - + _applicationId = applicationId; _endpointId = endpointId; _channelType = CHANNEL_TYPE; @@ -58,7 +55,7 @@ - (instancetype) initWithApplicationId:(NSString*) applicationId _location = [AWSPinpointEndpointProfileLocation new]; _demographic = [AWSPinpointEndpointProfileDemographic defaultAWSPinpointEndpointProfileDemographic]; _effectiveDate = [AWSPinpointDateUtils utcTimeMillisNow]; - _optOut = (optOut)?@"ALL":@"NONE"; + _optOut = (applicationLevelOptOut || [self isSystemLevelOptOut])?@"ALL":@"NONE"; _attributes = [NSMutableDictionary dictionary]; _metrics = [NSMutableDictionary dictionary]; _user = [AWSPinpointEndpointProfileUser new]; @@ -66,6 +63,35 @@ - (instancetype) initWithApplicationId:(NSString*) applicationId return self; } +- (instancetype)initWithApplicationId:(NSString*) applicationId + endpointId:(NSString*) endpointId { + return [self initWithApplicationId: applicationId endpointId:endpointId applicationLevelOptOut:NO]; +} + +- (instancetype)initWithContext:(AWSPinpointContext *) context { + BOOL applicationLevelOptOut = [self isApplicationLevelOptOut:context]; + + return [self initWithApplicationId: context.configuration.appId endpointId:context.uniqueId applicationLevelOptOut:applicationLevelOptOut]; +} + +- (BOOL) isApplicationLevelOptOut:(AWSPinpointContext *) context { + if (context.configuration.isApplicationLevelOptOut != NULL && context.configuration.isApplicationLevelOptOut() == YES){ + return YES; + } + + return NO; +} + +- (BOOL) isSystemLevelOptOut { + BOOL optOut = ![[UIApplication sharedApplication] isRegisteredForRemoteNotifications]; + + if ([[UIApplication sharedApplication] currentUserNotificationSettings].types == UIUserNotificationTypeNone) { + optOut = YES; + } + + return optOut; +} + + (NSArray*) processAttributeValues:(NSArray*) values { NSMutableArray *trimmedValues = [NSMutableArray arrayWithCapacity:MAX_ENDPOINT_ATTRIBUTE_VALUES]; int valuesCount = 0; diff --git a/AWSPinpoint/AWSPinpointTargeting/AWSPinpointTargetingService.m b/AWSPinpoint/AWSPinpointTargeting/AWSPinpointTargetingService.m index 9e32cc6c3fa..7de7ff51304 100644 --- a/AWSPinpoint/AWSPinpointTargeting/AWSPinpointTargetingService.m +++ b/AWSPinpoint/AWSPinpointTargeting/AWSPinpointTargetingService.m @@ -26,7 +26,7 @@ #import "AWSPinpointTargetingResources.h" static NSString *const AWSInfoPinpointTargeting = @"PinpointTargeting"; -static NSString *const AWSPinpointTargetingSDKVersion = @"2.5.7"; +static NSString *const AWSPinpointTargetingSDKVersion = @"2.5.8"; @interface AWSPinpointTargetingResponseSerializer : AWSJSONResponseSerializer @@ -134,6 +134,7 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response @"responseDataSize" : @(data?[data length]:0), }; } + return responseObject; } diff --git a/AWSPinpoint/AWSPinpointTargetingClient.m b/AWSPinpoint/AWSPinpointTargetingClient.m index 3d712f7f2e8..0e3f95097fc 100644 --- a/AWSPinpoint/AWSPinpointTargetingClient.m +++ b/AWSPinpoint/AWSPinpointTargetingClient.m @@ -56,8 +56,8 @@ - (instancetype)initWithContext:(AWSPinpointContext *) context { } - (AWSPinpointEndpointProfile *) currentEndpointProfile { - AWSPinpointEndpointProfile *endpointProfile = [[AWSPinpointEndpointProfile alloc] initWithApplicationId:self.context.configuration.appId - endpointId:self.context.uniqueId]; + AWSPinpointEndpointProfile *endpointProfile = [[AWSPinpointEndpointProfile alloc] initWithContext: self.context]; + //Add attributes if (self.globalAttributes.count > 0) { AWSDDLogVerbose(@"Applying Global Endpoint Attributes: %@", self.globalAttributes); diff --git a/AWSPinpoint/Info.plist b/AWSPinpoint/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSPinpoint/Info.plist +++ b/AWSPinpoint/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSPinpointTests/AWSPinpointTargetingClientTests.m b/AWSPinpointTests/AWSPinpointTargetingClientTests.m index c47179f381d..ee25cd60b11 100644 --- a/AWSPinpointTests/AWSPinpointTargetingClientTests.m +++ b/AWSPinpointTests/AWSPinpointTargetingClientTests.m @@ -16,35 +16,89 @@ #import #import "AWSTestUtility.h" #import "AWSPinpoint.h" +#import "OCMock.h" NSString *const AWSPinpointTargetingClientErrorDomain = @"com.amazonaws.AWSPinpointAnalyticsClientErrorDomain"; @interface AWSPinpointTargetingClientTests : XCTestCase @property (nonatomic, strong) AWSPinpoint *pinpoint; -@property (nonatomic, strong) NSDictionary *credentialsJson; +@property (nonatomic, strong) AWSPinpointConfiguration *configuration; +@property (nonatomic, strong) UIApplication *application; @end @implementation AWSPinpointTargetingClientTests - - (void)setUp { [super setUp]; [AWSTestUtility setupCognitoCredentialsProvider]; - + [self initializeMockApplicationWithOptOut:YES]; + [self initializePinpointWithConfiguration:[self getDefaultAWSPinpointConfiguration] forceCreate:NO]; +} + +- (AWSPinpointConfiguration *)getDefaultAWSPinpointConfiguration { NSString *filePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"credentials" ofType:@"json"]; - self.credentialsJson = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] + NSDictionary *credentialsJson = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:filePath] options:NSJSONReadingMutableContainers error:nil]; - - AWSPinpointConfiguration *configuration = [[AWSPinpointConfiguration alloc] initWithAppId:self.credentialsJson[@"pinpointAppId"] launchOptions:@{}]; - + + return [[AWSPinpointConfiguration alloc] initWithAppId:credentialsJson[@"pinpointAppId"] launchOptions:@{}]; +} + +- (AWSPinpointConfiguration *)getAWSPinpointConfigurationWithOptOut:(BOOL)optOut { + AWSPinpointConfiguration *configuration = [self getDefaultAWSPinpointConfiguration]; + + [self setApplicationLevelOptOut:configuration withOptOut:optOut]; + + return configuration; +} + +- (void)setApplicationLevelOptOut:(AWSPinpointConfiguration *)configuration withOptOut:(BOOL)optOut { + configuration.isApplicationLevelOptOut = ^BOOL{ + return optOut; + }; +} + +- (void)setApplicationLevelOptOut:(BOOL)optOut { + [self initializePinpointWithConfiguration:[self getAWSPinpointConfigurationWithOptOut:optOut]]; +} + +- (void)initializePinpointWithConfiguration:(AWSPinpointConfiguration *)configuration forceCreate:(BOOL)forceCreate { + self.configuration = configuration; + // If the Pinpoint AppId exists already, pinpointWithConfiguration will not create a new instance of Pinpoint and ignore the configuration + // forceCreate generates a random AppId which allows us to create Pinpoint from configuration, even if it exists already. + if (forceCreate == YES) { + self.configuration.appId = [[NSUUID UUID] UUIDString]; + } self.pinpoint = [AWSPinpoint pinpointWithConfiguration:configuration]; } +- (void)initializePinpointWithConfiguration:(AWSPinpointConfiguration *)configuration { + [self initializePinpointWithConfiguration:configuration forceCreate:YES]; +} + +- (void)initializeMockApplicationWithOptOut:(BOOL)optOut { + id mockApplication = OCMClassMock([UIApplication class]); + + OCMStub([mockApplication sharedApplication]).andReturn(mockApplication); + + [self setSystemLevelOptOut:mockApplication withOptOut:optOut]; +} + +- (void)setSystemLevelOptOut:(UIApplication *)application withOptOut:(BOOL)optOut { + UIUserNotificationType notificationType = optOut ? UIUserNotificationTypeNone : UIUserNotificationTypeAlert; + UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:notificationType categories:nil]; + OCMStub([application currentUserNotificationSettings]).andReturn(notificationSettings); + OCMStub([application isRegisteredForRemoteNotifications]).andReturn(optOut == NO); +} + +- (void)setSystemLevelOptOut:(BOOL)optOut { + [self initializeMockApplicationWithOptOut:optOut]; +} + - (void)tearDown { [super tearDown]; } @@ -59,11 +113,63 @@ - (void)testConstructors { } } +- (void)testCurrentProfileWithSystemOptOutAndApplicationOptOut { + [self setSystemLevelOptOut:YES]; + [self setApplicationLevelOptOut:YES]; + + AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; + + XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); +} + +- (void)testCurrentProfileWithSystemOptOutAndApplicationOptIn { + [self setSystemLevelOptOut:YES]; + [self setApplicationLevelOptOut:NO]; + + AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; + + XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); +} + +- (void)testCurrentProfileWithSystemOptOutAndApplicationOptOutUnset { + [self setSystemLevelOptOut:YES]; + + AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; + + XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); +} + +- (void)testCurrentProfileWithSystemOptInAndApplicationOptOut { + [self setSystemLevelOptOut:NO]; + [self setApplicationLevelOptOut:YES]; + + AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; + + XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); +} + +- (void)testCurrentProfileWithSystemOptInAndApplicationOptIn { + [self setSystemLevelOptOut:NO]; + [self setApplicationLevelOptOut:NO]; + + AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; + + XCTAssertTrue([profile.optOut isEqualToString:@"NONE"]); +} + +- (void)testCurrentProfileWithSystemOptInAndApplicationOptOutUnset { + [self setSystemLevelOptOut:NO]; + + AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; + + XCTAssertTrue([profile.optOut isEqualToString:@"NONE"]); +} + - (void)testCurrentProfile { AWSPinpointEndpointProfile *profile = [self.pinpoint.targetingClient currentEndpointProfile]; XCTAssertNotNil(profile); XCTAssertNotNil(profile.endpointId); - XCTAssertTrue([profile.applicationId isEqualToString:self.credentialsJson[@"pinpointAppId"]]); + XCTAssertTrue([profile.applicationId isEqualToString:self.configuration.appId]); XCTAssertTrue([profile.channelType isEqualToString:@"APNS"]); XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); XCTAssertNil(profile.address); @@ -110,7 +216,7 @@ - (void) testGlobalAttribute { XCTAssertNotNil(profile); XCTAssertNotNil(profile.endpointId); - XCTAssertTrue([profile.applicationId isEqualToString:self.credentialsJson[@"pinpointAppId"]]); + XCTAssertTrue([profile.applicationId isEqualToString:self.configuration.appId]); XCTAssertTrue([profile.channelType isEqualToString:@"APNS"]); XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); XCTAssertNil(profile.address); @@ -205,7 +311,7 @@ - (void) testGlobalMetric { XCTAssertNotNil(profile); XCTAssertNotNil(profile.endpointId); - XCTAssertTrue([profile.applicationId isEqualToString:self.credentialsJson[@"pinpointAppId"]]); + XCTAssertTrue([profile.applicationId isEqualToString:self.configuration.appId]); XCTAssertTrue([profile.channelType isEqualToString:@"APNS"]); XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); XCTAssertNil(profile.address); @@ -300,7 +406,7 @@ - (void) testGlobalAttributeAndMetric { XCTAssertNotNil(profile); XCTAssertNotNil(profile.endpointId); - XCTAssertTrue([profile.applicationId isEqualToString:self.credentialsJson[@"pinpointAppId"]]); + XCTAssertTrue([profile.applicationId isEqualToString:self.configuration.appId]); XCTAssertTrue([profile.channelType isEqualToString:@"APNS"]); XCTAssertTrue([profile.optOut isEqualToString:@"ALL"]); XCTAssertNil(profile.address); diff --git a/AWSPolly.podspec b/AWSPolly.podspec index c322e695a54..ab2f04c1134 100644 --- a/AWSPolly.podspec +++ b/AWSPolly.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSPolly' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSPolly/*.{h,m}' end diff --git a/AWSPolly/AWSPollyService.m b/AWSPolly/AWSPollyService.m index 191fbeac1d3..679f2036547 100644 --- a/AWSPolly/AWSPollyService.m +++ b/AWSPolly/AWSPollyService.m @@ -26,7 +26,7 @@ #import "AWSPollyResources.h" static NSString *const AWSInfoPolly = @"Polly"; -static NSString *const AWSPollySDKVersion = @"2.5.7"; +static NSString *const AWSPollySDKVersion = @"2.5.8"; @interface AWSPollyResponseSerializer : AWSJSONResponseSerializer @@ -107,7 +107,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSPolly/AWSPollySynthesizeSpeechURLBuilder.m b/AWSPolly/AWSPollySynthesizeSpeechURLBuilder.m index 105a810864f..45655623cfb 100644 --- a/AWSPolly/AWSPollySynthesizeSpeechURLBuilder.m +++ b/AWSPolly/AWSPollySynthesizeSpeechURLBuilder.m @@ -16,7 +16,7 @@ #import "AWSPollySynthesizeSpeechURLBuilder.h" static NSString *const AWSInfoPollySynthesizeSpeechURLBuilder = @"PollySynthesizeSpeechUrlBuilder"; -static NSString *const AWSPollySDKVersion = @"2.5.7"; +static NSString *const AWSPollySDKVersion = @"2.5.8"; NSString *const AWSPollySynthesizeSpeechURLBuilderErrorDomain = @"com.amazonaws.AWSPollySynthesizeSpeechURLBuilderErrorDomain"; NSString *const AWSPollyPresignedUrlPath = @"v1/speech"; diff --git a/AWSPolly/Info.plist b/AWSPolly/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSPolly/Info.plist +++ b/AWSPolly/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSRekognition.podspec b/AWSRekognition.podspec index 4921e775879..34b3482ed05 100644 --- a/AWSRekognition.podspec +++ b/AWSRekognition.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSRekognition' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSRekognition/*.{h,m}' end diff --git a/AWSRekognition/AWSRekognitionService.m b/AWSRekognition/AWSRekognitionService.m index bbaf8d5c07b..728deaa4cea 100644 --- a/AWSRekognition/AWSRekognitionService.m +++ b/AWSRekognition/AWSRekognitionService.m @@ -26,7 +26,7 @@ #import "AWSRekognitionResources.h" static NSString *const AWSInfoRekognition = @"Rekognition"; -static NSString *const AWSRekognitionSDKVersion = @"2.5.7"; +static NSString *const AWSRekognitionSDKVersion = @"2.5.8"; @interface AWSRekognitionResponseSerializer : AWSJSONResponseSerializer @@ -99,7 +99,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSRekognition/Info.plist b/AWSRekognition/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSRekognition/Info.plist +++ b/AWSRekognition/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSS3.podspec b/AWSS3.podspec index 22070b17124..b1aa43ee296 100644 --- a/AWSS3.podspec +++ b/AWSS3.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSS3' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSS3/*.{h,m}' end diff --git a/AWSS3/AWSS3PreSignedURL.m b/AWSS3/AWSS3PreSignedURL.m index 970560428eb..fca5bd4a29f 100644 --- a/AWSS3/AWSS3PreSignedURL.m +++ b/AWSS3/AWSS3PreSignedURL.m @@ -26,7 +26,7 @@ static NSString *const AWSS3PreSignedURLBuilderAcceleratedEndpoint = @"s3-accelerate.amazonaws.com"; static NSString *const AWSInfoS3PreSignedURLBuilder = @"S3PreSignedURLBuilder"; -static NSString *const AWSS3PreSignedURLBuilderSDKVersion = @"2.5.7"; +static NSString *const AWSS3PreSignedURLBuilderSDKVersion = @"2.5.8"; @interface AWSS3PreSignedURLBuilder() diff --git a/AWSS3/AWSS3Service.m b/AWSS3/AWSS3Service.m index aed4d1d6eee..d14e68248c2 100644 --- a/AWSS3/AWSS3Service.m +++ b/AWSS3/AWSS3Service.m @@ -28,7 +28,7 @@ #import "AWSS3Serializer.h" static NSString *const AWSInfoS3 = @"S3"; -static NSString *const AWSS3SDKVersion = @"2.5.7"; +static NSString *const AWSS3SDKVersion = @"2.5.8"; diff --git a/AWSS3/Info.plist b/AWSS3/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSS3/Info.plist +++ b/AWSS3/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSSES.podspec b/AWSSES.podspec index 965ff52ea44..8f4128069c4 100644 --- a/AWSSES.podspec +++ b/AWSSES.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSSES' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSSES/*.{h,m}' end diff --git a/AWSSES/AWSSESService.m b/AWSSES/AWSSESService.m index b68d454776c..e07afcb6b6e 100644 --- a/AWSSES/AWSSESService.m +++ b/AWSSES/AWSSESService.m @@ -26,7 +26,7 @@ #import "AWSSESResources.h" static NSString *const AWSInfoSES = @"SES"; -static NSString *const AWSSESSDKVersion = @"2.5.7"; +static NSString *const AWSSESSDKVersion = @"2.5.8"; @interface AWSSESResponseSerializer : AWSXMLResponseSerializer @@ -67,23 +67,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSSESErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSSESErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSSESErrorDomain + code:AWSSESErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -99,7 +100,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSSES/Info.plist b/AWSSES/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSSES/Info.plist +++ b/AWSSES/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSSESTests/AWSSESTests.m b/AWSSESTests/AWSSESTests.m index 728f5be4283..cd327ff56de 100644 --- a/AWSSESTests/AWSSESTests.m +++ b/AWSSESTests/AWSSESTests.m @@ -142,7 +142,10 @@ - (void)testVerifyEmailIdentityFailed { identityRequest.emailAddress = @""; //email address is empty [[[ses verifyEmailIdentity:identityRequest] continueWithBlock:^id(AWSTask *task) { - XCTAssertNotNil(task.error, @"expected EmailAddressNotValid Error but got nil"); + XCTAssertNotNil(task.error, @"expected InvalidParameterValue Error but got nil"); + XCTAssertEqual(task.error.code, 0); + XCTAssertTrue([@"InvalidParameterValue" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"Email address not specified." isEqualToString:task.error.userInfo[@"Message"]]); return nil; }] waitUntilFinished]; } diff --git a/AWSSNS.podspec b/AWSSNS.podspec index 2b301bb4efa..850cdbb077b 100644 --- a/AWSSNS.podspec +++ b/AWSSNS.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSSNS' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSSNS/*.{h,m}' end diff --git a/AWSSNS/AWSSNSService.m b/AWSSNS/AWSSNSService.m index eb9a5712db3..b113ac84bd0 100644 --- a/AWSSNS/AWSSNSService.m +++ b/AWSSNS/AWSSNSService.m @@ -26,7 +26,7 @@ #import "AWSSNSResources.h" static NSString *const AWSInfoSNS = @"SNS"; -static NSString *const AWSSNSSDKVersion = @"2.5.7"; +static NSString *const AWSSNSSDKVersion = @"2.5.8"; @interface AWSSNSResponseSerializer : AWSXMLResponseSerializer @@ -66,23 +66,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSSNSErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSSNSErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSSNSErrorDomain + code:AWSSNSErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -98,7 +99,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSSNS/Info.plist b/AWSSNS/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSSNS/Info.plist +++ b/AWSSNS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSSNSTests/AWSSNSTests.m b/AWSSNSTests/AWSSNSTests.m index 5c2d5dc6a90..3870816dd9d 100644 --- a/AWSSNSTests/AWSSNSTests.m +++ b/AWSSNSTests/AWSSNSTests.m @@ -92,7 +92,10 @@ - (void)testGetEndpointAttributesFailed { input.endpointArn = @""; //endPointARN is empty [[[sns getEndpointAttributes:input] continueWithBlock:^id(AWSTask *task) { - XCTAssertNotNil(task.error, @"expected MissingParameters Error but got nil"); + XCTAssertNotNil(task.error, @"expected InvalidParameters Error but got nil"); + XCTAssertEqual(task.error.code, 4); + XCTAssertTrue([@"InvalidParameter" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"Invalid parameter: EndpointArn Reason: An ARN must have at least 6 elements, not 1" isEqualToString:task.error.userInfo[@"Message"]]); return nil; }] waitUntilFinished]; } diff --git a/AWSSQS.podspec b/AWSSQS.podspec index d1ca46856cd..1ee237da766 100644 --- a/AWSSQS.podspec +++ b/AWSSQS.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSSQS' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSSQS/*.{h,m}' end diff --git a/AWSSQS/AWSSQSService.m b/AWSSQS/AWSSQSService.m index 560cb1cee7b..3f5981b6f2a 100644 --- a/AWSSQS/AWSSQSService.m +++ b/AWSSQS/AWSSQSService.m @@ -26,7 +26,7 @@ #import "AWSSQSResources.h" static NSString *const AWSInfoSQS = @"SQS"; -static NSString *const AWSSQSSDKVersion = @"2.5.7"; +static NSString *const AWSSQSSDKVersion = @"2.5.8"; @interface AWSSQSResponseSerializer : AWSXMLResponseSerializer @@ -72,23 +72,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSSQSErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSSQSErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSSQSErrorDomain + code:AWSSQSErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -104,7 +105,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSSQS/Info.plist b/AWSSQS/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSSQS/Info.plist +++ b/AWSSQS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSSQSTests/AWSSQSTests.m b/AWSSQSTests/AWSSQSTests.m index 59daf7e4518..b98e7e7b752 100644 --- a/AWSSQSTests/AWSSQSTests.m +++ b/AWSSQSTests/AWSSQSTests.m @@ -86,14 +86,17 @@ - (void)testListQueuesRequest { }] waitUntilFinished]; } -- (void)testGetQueueAttributesRequest { +- (void)testGetQueueAttributesRequestFailure { AWSSQS *sqs = [AWSSQS defaultSQS]; AWSSQSGetQueueAttributesRequest *attributesRequest = [AWSSQSGetQueueAttributesRequest new]; attributesRequest.queueUrl = @""; //queueURL is empty [[[sqs getQueueAttributes:attributesRequest] continueWithBlock:^id(AWSTask *task) { - XCTAssertNotNil(task.error, @"expected WrongQueueURL Error but got nil"); + XCTAssertNotNil(task.error, @"expected InvalidAddress Error but got nil"); + XCTAssertEqual(task.error.code, 0); + XCTAssertTrue([@"InvalidAddress" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"The address is not valid for this endpoint." isEqualToString:task.error.userInfo[@"Message"]]); return nil; }] waitUntilFinished]; } diff --git a/AWSSimpleDB.podspec b/AWSSimpleDB.podspec index 7d1eed405e5..db486bcd71b 100644 --- a/AWSSimpleDB.podspec +++ b/AWSSimpleDB.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'AWSSimpleDB' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/aws/aws-sdk-ios.git', :tag => s.version} s.requires_arc = true - s.dependency 'AWSCore', '2.5.7' + s.dependency 'AWSCore', '2.5.8' s.source_files = 'AWSSimpleDB/*.{h,m}' end diff --git a/AWSSimpleDB/AWSSimpleDBService.m b/AWSSimpleDB/AWSSimpleDBService.m index 0faa12901f6..738dadbe158 100644 --- a/AWSSimpleDB/AWSSimpleDBService.m +++ b/AWSSimpleDB/AWSSimpleDBService.m @@ -26,7 +26,7 @@ #import "AWSSimpleDBResources.h" static NSString *const AWSInfoSimpleDB = @"SimpleDB"; -static NSString *const AWSSimpleDBSDKVersion = @"2.5.7"; +static NSString *const AWSSimpleDBSDKVersion = @"2.5.8"; @interface AWSSimpleDBResponseSerializer : AWSXMLResponseSerializer @@ -73,23 +73,24 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:data error:error]; if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if (!*error && [responseObject isKindOfClass:[NSDictionary class]]) { - if ([errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]]) { - if (error) { - *error = [NSError errorWithDomain:AWSSimpleDBErrorDomain - code:[[errorCodeDictionary objectForKey:[[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]] integerValue] - userInfo:responseObject]; - } - return responseObject; - } else if ([[[responseObject objectForKey:@"__type"] componentsSeparatedByString:@"#"] lastObject]) { - if (error) { - *error = [NSError errorWithDomain:AWSCognitoIdentityErrorDomain - code:AWSCognitoIdentityErrorUnknown - userInfo:responseObject]; - } - return responseObject; - } - } + + NSDictionary *errorInfo = responseObject[@"Error"]; + if (errorInfo[@"Code"] && errorCodeDictionary[errorInfo[@"Code"]]) { + if (error) { + *error = [NSError errorWithDomain:AWSSimpleDBErrorDomain + code:[errorCodeDictionary[errorInfo[@"Code"]] integerValue] + userInfo:errorInfo + ]; + return responseObject; + } + } else if (errorInfo) { + if (error) { + *error = [NSError errorWithDomain:AWSSimpleDBErrorDomain + code:AWSSimpleDBErrorUnknown + userInfo:errorInfo]; + return responseObject; + } + } } if (!*error && response.statusCode/100 != 2) { @@ -105,7 +106,8 @@ - (id)responseObjectForResponse:(NSHTTPURLResponse *)response error:error]; } } - return responseObject; + + return responseObject; } @end diff --git a/AWSSimpleDB/Info.plist b/AWSSimpleDB/Info.plist index 9c0df6fd678..999abdbbc83 100644 --- a/AWSSimpleDB/Info.plist +++ b/AWSSimpleDB/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.5.7 + 2.5.8 CFBundleSignature ???? CFBundleVersion diff --git a/AWSSimpleDBTests/AWSSimpleDBTests.m b/AWSSimpleDBTests/AWSSimpleDBTests.m index b5879520e4a..0bab82f7b1f 100644 --- a/AWSSimpleDBTests/AWSSimpleDBTests.m +++ b/AWSSimpleDBTests/AWSSimpleDBTests.m @@ -322,7 +322,10 @@ - (void)testDomainMetaDataFailed { metaDataRequest.domainName = @""; //domainName is empty [[[sdb domainMetadata:metaDataRequest] continueWithBlock:^id(AWSTask *task) { - XCTAssertNotNil(task.error, @"expected InvalidDomainName error but got nil"); + XCTAssertNotNil(task.error, @"expected InvalidParameterValue error but got nil"); + XCTAssertEqual(task.error.code, 6); + XCTAssertTrue([@"InvalidParameterValue" isEqualToString:task.error.userInfo[@"Code"]]); + XCTAssertTrue([@"Value () for parameter DomainName is invalid. " isEqualToString: (NSString *)task.error.userInfo[@"Message"]]); return nil; }]waitUntilFinished]; } diff --git a/AWSiOSSDKv2.podspec b/AWSiOSSDKv2.podspec index d0c35c86f18..36389d060fa 100644 --- a/AWSiOSSDKv2.podspec +++ b/AWSiOSSDKv2.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'AWSiOSSDKv2' - s.version = '2.5.7' + s.version = '2.5.8' s.summary = 'Amazon Web Services SDK for iOS.' s.description = 'The AWS SDK for iOS provides a library, code samples, and documentation for developers to build connected mobile applications using AWS.' @@ -15,103 +15,107 @@ Pod::Spec.new do |s| s.requires_arc = true s.subspec 'AWSCore' do |aws| - aws.dependency 'AWSCore', '2.5.7' + aws.dependency 'AWSCore', '2.5.8' end s.subspec 'AWSAPIGateway' do |apigateway| - apigateway.dependency 'AWSAPIGateway', '2.5.7' + apigateway.dependency 'AWSAPIGateway', '2.5.8' end s.subspec 'AutoScaling' do |autoscaling| - autoscaling.dependency 'AWSAutoScaling', '2.5.7' + autoscaling.dependency 'AWSAutoScaling', '2.5.8' end s.subspec 'CloudWatch' do |cloudwatch| - cloudwatch.dependency 'AWSCloudWatch', '2.5.7' + cloudwatch.dependency 'AWSCloudWatch', '2.5.8' end s.subspec 'Pinpoint' do |pp| - pp.dependency 'AWSPinpoint', '2.5.7' + pp.dependency 'AWSPinpoint', '2.5.8' end s.subspec 'AWSCognito' do |cognito| - cognito.dependency 'AWSCognito', '2.5.7' + cognito.dependency 'AWSCognito', '2.5.8' end s.subspec 'AWSCognitoIdentityProvider' do |cognitoidentityprovider| - cognitoidentityprovider.dependency 'AWSCognitoIdentityProvider', '2.5.7' + cognitoidentityprovider.dependency 'AWSCognitoIdentityProvider', '2.5.8' + end + + s.subspec 'AWSCognitoAuth' do |cognitoauth| + cognitoauth.dependency 'AWSCognitoAuth', '2.5.8' end s.subspec 'DynamoDB' do |ddb| - ddb.dependency 'AWSDynamoDB', '2.5.7' + ddb.dependency 'AWSDynamoDB', '2.5.8' end s.subspec 'EC2' do |ec2| - ec2.dependency 'AWSEC2', '2.5.7' + ec2.dependency 'AWSEC2', '2.5.8' end s.subspec 'ElasticLoadBalancing' do |elasticloadbalancing| - elasticloadbalancing.dependency 'AWSElasticLoadBalancing', '2.5.7' + elasticloadbalancing.dependency 'AWSElasticLoadBalancing', '2.5.8' end s.subspec 'AWSIoT' do |iot| - iot.dependency 'AWSIoT', '2.5.7' + iot.dependency 'AWSIoT', '2.5.8' end s.subspec 'Kinesis' do |kinesis| - kinesis.dependency 'AWSKinesis', '2.5.7' + kinesis.dependency 'AWSKinesis', '2.5.8' end s.subspec 'AWSKMS' do |kms| - kms.dependency 'AWSKMS', '2.5.7' + kms.dependency 'AWSKMS', '2.5.8' end s.subspec 'AWSLambda' do |lambda| - lambda.dependency 'AWSLambda', '2.5.7' + lambda.dependency 'AWSLambda', '2.5.8' end s.subspec 'AWSLex' do |lex| - lex.dependency 'AWSLex', '2.5.7' + lex.dependency 'AWSLex', '2.5.8' end s.subspec 'AWSLogs' do |log| - log.dependency 'AWSLogs', '2.5.7' + log.dependency 'AWSLogs', '2.5.8' end s.subspec 'AWSMachineLearning' do |machinelearning| - machinelearning.dependency 'AWSMachineLearning', '2.5.7' + machinelearning.dependency 'AWSMachineLearning', '2.5.8' end s.subspec 'AWSPolly' do |polly| - polly.dependency 'AWSPolly', '2.5.7' + polly.dependency 'AWSPolly', '2.5.8' end s.subspec 'MobileAnalytics' do |mobileanalytics| - mobileanalytics.dependency 'AWSMobileAnalytics', '2.5.7' + mobileanalytics.dependency 'AWSMobileAnalytics', '2.5.8' end s.subspec 'AWSRekognition' do |rekognition| - rekognition.dependency 'AWSRekognition', '2.5.7' + rekognition.dependency 'AWSRekognition', '2.5.8' end s.subspec 'AWSS3' do |s3| - s3.dependency 'AWSS3', '2.5.7' + s3.dependency 'AWSS3', '2.5.8' end s.subspec 'AWSSES' do |ses| - ses.dependency 'AWSSES', '2.5.7' + ses.dependency 'AWSSES', '2.5.8' end s.subspec 'AWSSimpleDB' do |simpledb| - simpledb.dependency 'AWSSimpleDB', '2.5.7' + simpledb.dependency 'AWSSimpleDB', '2.5.8' end s.subspec 'AWSSNS' do |sns| - sns.dependency 'AWSSNS', '2.5.7' + sns.dependency 'AWSSNS', '2.5.8' end s.subspec 'AWSSQS' do |sqs| - sqs.dependency 'AWSSQS', '2.5.7' + sqs.dependency 'AWSSQS', '2.5.8' end diff --git a/AWSiOSSDKv2.xcodeproj/project.pbxproj b/AWSiOSSDKv2.xcodeproj/project.pbxproj index 8871347c63a..ed58049056d 100644 --- a/AWSiOSSDKv2.xcodeproj/project.pbxproj +++ b/AWSiOSSDKv2.xcodeproj/project.pbxproj @@ -72,6 +72,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 170C2D471EDFAE43008A2E52 /* AWSCognitoAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EFDE85AC1ED203D9008841EC /* AWSCognitoAuthTests.m */; }; 173641DE1ECBBABC00512239 /* AWSLambdaRequestRetryHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 173641DC1ECBBABC00512239 /* AWSLambdaRequestRetryHandler.h */; }; 173641DF1ECBBABC00512239 /* AWSLambdaRequestRetryHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 173641DD1ECBBABC00512239 /* AWSLambdaRequestRetryHandler.m */; }; 174A59F01D89D7DB008C7D52 /* AWSLambdaMicroserviceClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 174A59EF1D89D7DB008C7D52 /* AWSLambdaMicroserviceClient.m */; }; @@ -990,9 +991,24 @@ E4E1DA5C1E5F5BF50080F769 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8EF551C6A6A2E0098B15B /* libOCMock.a */; }; E4E1DA5D1E5F5C080080F769 /* credentials.json in Resources */ = {isa = PBXBuildFile; fileRef = CEB8EF3E1C6A69AB0098B15B /* credentials.json */; }; E4E1DA5E1E5F91690080F769 /* AWSTestUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB8EF2E1C6A69A00098B15B /* AWSTestUtility.m */; }; + EF0FEB3B1ED218E300D763BC /* AWSCognitoAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = EFDE85B01ED203D9008841EC /* AWSCognitoAuth.m */; }; + EF0FEB3D1ED2192600D763BC /* AWSCognitoAuthTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EFDE85AC1ED203D9008841EC /* AWSCognitoAuthTests.m */; }; + EF0FEB3E1ED2194400D763BC /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = EFDE85AD1ED203D9008841EC /* Info.plist */; }; + EF0FEB401ED2196000D763BC /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = EFDE85AA1ED203D9008841EC /* Info.plist */; }; + EF0FEB411ED2696700D763BC /* AWSCognitoAuth.h in Headers */ = {isa = PBXBuildFile; fileRef = EFDE85AF1ED203D9008841EC /* AWSCognitoAuth.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF0FEB421ED2698300D763BC /* AWSCognitoAuth_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = EFDE85B31ED203D9008841EC /* AWSCognitoAuth_Internal.h */; }; + EF0FEB451ED26A1200D763BC /* AWSCognitoAuth.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = EFDE85E51ED2046E008841EC /* AWSCognitoAuth.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EF1D80071CBC924D007AC243 /* AWSCognitoIdentityProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = EF1D80031CBC924D007AC243 /* AWSCognitoIdentityProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF2211881ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.h in Headers */ = {isa = PBXBuildFile; fileRef = EF2211841ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.h */; }; + EF2211891ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.m in Sources */ = {isa = PBXBuildFile; fileRef = EF2211851ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.m */; }; + EF22118A1ED75A0400F432F7 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = EF2211861ED75A0400F432F7 /* LICENSE */; }; + EF22118B1ED75A0400F432F7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = EF2211871ED75A0400F432F7 /* README.md */; }; EF76F9C91C9A121100F881D3 /* NSData+AWSCognitoIdentityProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = EFDF14891C98B0C4002CCFE2 /* NSData+AWSCognitoIdentityProvider.h */; }; EF76F9CA1C9A121100F881D3 /* NSData+AWSCognitoIdentityProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = EFDF148A1C98B0C4002CCFE2 /* NSData+AWSCognitoIdentityProvider.m */; }; + EFDE85ED1ED2050C008841EC /* AWSTestUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB8EF2E1C6A69A00098B15B /* AWSTestUtility.m */; }; + EFDE85F01ED2050C008841EC /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8EF551C6A6A2E0098B15B /* libOCMock.a */; }; + EFDE85F21ED2050C008841EC /* credentials.json in Resources */ = {isa = PBXBuildFile; fileRef = CEB8EF3E1C6A69AB0098B15B /* credentials.json */; }; + EFDE86021ED20517008841EC /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8EF551C6A6A2E0098B15B /* libOCMock.a */; }; EFDF14D71C993015002CCFE2 /* AWSCognitoIdentityUser.h in Headers */ = {isa = PBXBuildFile; fileRef = EFDF14BF1C9929AE002CCFE2 /* AWSCognitoIdentityUser.h */; settings = {ATTRIBUTES = (Public, ); }; }; EFDF14D81C993015002CCFE2 /* AWSCognitoIdentityUser.m in Sources */ = {isa = PBXBuildFile; fileRef = EFDF14C01C9929AE002CCFE2 /* AWSCognitoIdentityUser.m */; }; EFDF14D91C993015002CCFE2 /* AWSCognitoIdentityUserPool.h in Headers */ = {isa = PBXBuildFile; fileRef = EFDF147A1C98A79C002CCFE2 /* AWSCognitoIdentityUserPool.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -2151,6 +2167,20 @@ remoteGlobalIDString = 181154751E201403008F184C; remoteInfo = AWSAllTestsHost; }; + EF0FEB431ED269E900D763BC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CE0D41541C6A66A9006B91B5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EFDE85BC1ED2046E008841EC; + remoteInfo = AWSCognitoAuth; + }; + EF0FEB461ED26A7600D763BC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CE0D41541C6A66A9006B91B5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EFDE85BC1ED2046E008841EC; + remoteInfo = AWSCognitoAuth; + }; EF77D2261CBC65BE005F8F15 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = CE0D41541C6A66A9006B91B5 /* Project object */; @@ -2158,6 +2188,20 @@ remoteGlobalIDString = CE0D416C1C6A66E5006B91B5; remoteInfo = AWSCore; }; + EFDE85EB1ED2050C008841EC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CE0D41541C6A66A9006B91B5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 181154751E201403008F184C; + remoteInfo = AWSAllTestsHost; + }; + EFDE85FC1ED20517008841EC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CE0D41541C6A66A9006B91B5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 181154751E201403008F184C; + remoteInfo = AWSAllTestsHost; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -2445,6 +2489,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EFDE86041ED20517008841EC /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + EF0FEB451ED26A1200D763BC /* AWSCognitoAuth.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -3379,6 +3433,21 @@ E4E1DA511E5F5BBD0080F769 /* AWSKMSTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AWSKMSTests.m; sourceTree = ""; }; E4E1DA531E5F5BBD0080F769 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; EF1D80031CBC924D007AC243 /* AWSCognitoIdentityProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AWSCognitoIdentityProvider.h; sourceTree = ""; }; + EF2211841ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AWSCognitoAuthUICKeyChainStore.h; sourceTree = ""; }; + EF2211851ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AWSCognitoAuthUICKeyChainStore.m; sourceTree = ""; }; + EF2211861ED75A0400F432F7 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + EF2211871ED75A0400F432F7 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + EFDE85A91ED203D9008841EC /* AWSCognitoAuthUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AWSCognitoAuthUnitTests.m; sourceTree = ""; }; + EFDE85AA1ED203D9008841EC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EFDE85AC1ED203D9008841EC /* AWSCognitoAuthTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AWSCognitoAuthTests.m; sourceTree = ""; }; + EFDE85AD1ED203D9008841EC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EFDE85AF1ED203D9008841EC /* AWSCognitoAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AWSCognitoAuth.h; sourceTree = ""; }; + EFDE85B01ED203D9008841EC /* AWSCognitoAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AWSCognitoAuth.m; sourceTree = ""; }; + EFDE85B11ED203D9008841EC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EFDE85B31ED203D9008841EC /* AWSCognitoAuth_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AWSCognitoAuth_Internal.h; sourceTree = ""; }; + EFDE85E51ED2046E008841EC /* AWSCognitoAuth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AWSCognitoAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EFDE85F61ED2050C008841EC /* AWSCognitoAuthTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AWSCognitoAuthTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + EFDE860A1ED20517008841EC /* AWSCognitoAuthUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AWSCognitoAuthUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; EFDF14761C986D7E002CCFE2 /* AWSCognitoIdentityUserPool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AWSCognitoIdentityUserPool.m; sourceTree = ""; }; EFDF147A1C98A79C002CCFE2 /* AWSCognitoIdentityUserPool.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AWSCognitoIdentityUserPool.h; sourceTree = ""; }; EFDF14891C98B0C4002CCFE2 /* NSData+AWSCognitoIdentityProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+AWSCognitoIdentityProvider.h"; sourceTree = ""; }; @@ -4016,6 +4085,29 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EFDE85CC1ED2046E008841EC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFDE85EF1ED2050C008841EC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EFDE85F01ED2050C008841EC /* libOCMock.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFDE86011ED20517008841EC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EFDE86021ED20517008841EC /* libOCMock.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -4348,9 +4440,8 @@ CE0D41531C6A66A9006B91B5 = { isa = PBXGroup; children = ( - CE0D416E1C6A66E5006B91B5 /* AWSCore */, - CE0D417A1C6A66E5006B91B5 /* AWSCoreTests */, - CE5603D31C6BC74500B4E00B /* AWSCoreUnitTests */, + CE6983C11CEE52D40092640F /* AWSAllTests */, + 181154771E201403008F184C /* AWSAllTestsHost */, CE9DEB1F1C6A81160060793F /* AWSAPIGateway */, CE9DEB2B1C6A81160060793F /* AWSAPIGatewayTests */, CE5603EA1C6BC86C00B4E00B /* AWSAPIGatewayUnitTests */, @@ -4361,11 +4452,17 @@ CE9DEB6D1C6A9F3D0060793F /* AWSCloudWatchTests */, CE56040A1C6BC8CE00B4E00B /* AWSCloudWatchUnitTests */, CE9DEABE1C6A7FDF0060793F /* AWSCognito */, - CE9DEACA1C6A7FDF0060793F /* AWSCognitoTests */, - CE5604191C6BC8DF00B4E00B /* AWSCognitoUnitTests */, + EFDE85AE1ED203D9008841EC /* AWSCognitoAuth */, + EFDE85AB1ED203D9008841EC /* AWSCognitoAuthTests */, + EFDE85A81ED203D9008841EC /* AWSCognitoAuthUnitTests */, CEA316991C93A0EA002A9F58 /* AWSCognitoIdentityProvider */, CEA316A51C93A0EA002A9F58 /* AWSCognitoIdentityProviderTests */, CEA316C11C93A415002A9F58 /* AWSCognitoIdentityProviderUnitTests */, + CE9DEACA1C6A7FDF0060793F /* AWSCognitoTests */, + CE5604191C6BC8DF00B4E00B /* AWSCognitoUnitTests */, + CE0D416E1C6A66E5006B91B5 /* AWSCore */, + CE0D417A1C6A66E5006B91B5 /* AWSCoreTests */, + CE5603D31C6BC74500B4E00B /* AWSCoreUnitTests */, CE9DE5711C6A763E0060793F /* AWSDynamoDB */, CE9DE57D1C6A763E0060793F /* AWSDynamoDBTests */, CE5604281C6BC8EE00B4E00B /* AWSDynamoDBUnitTests */, @@ -4396,8 +4493,8 @@ CE9DE71C1C6A7A690060793F /* AWSMachineLearningTests */, CE5604821C6BC94D00B4E00B /* AWSMachineLearningUnitTests */, CE9DE73F1C6A7AE30060793F /* AWSMobileAnalytics */, - CE9DE74B1C6A7AE40060793F /* AWSMobileAnalyticsTests */, CE9E501C1C72C19800B60FD7 /* AWSMobileAnalyticsLegacyTests */, + CE9DE74B1C6A7AE40060793F /* AWSMobileAnalyticsTests */, CE5604911C6BC96500B4E00B /* AWSMobileAnalyticsUnitTests */, 18798F7F1DEF9EA900BC419B /* AWSPinpoint */, 18798F8B1DEF9EAA00BC419B /* AWSPinpointTests */, @@ -4407,6 +4504,7 @@ 18E2F58F1DED31D300BD4608 /* AWSPollyUnitTests */, 188321031DFF11B8003FBE9F /* AWSRekognition */, 1883210F1DFF11B9003FBE9F /* AWSRekognitionUnitTests */, + 1813F65C1DB5A0B9009486D6 /* AWSResources */, CE9DE9BE1C6A7C2D0060793F /* AWSS3 */, CE9DE9CA1C6A7C2E0060793F /* AWSS3Tests */, CE5604A01C6BC97600B4E00B /* AWSS3UnitTests */, @@ -4422,9 +4520,6 @@ CE9DEA8E1C6A7F460060793F /* AWSSQS */, CE9DEA9A1C6A7F460060793F /* AWSSQSTests */, CE5604DC1C6BC9B200B4E00B /* AWSSQSUnitTests */, - CE6983C11CEE52D40092640F /* AWSAllTests */, - 1813F65C1DB5A0B9009486D6 /* AWSResources */, - 181154771E201403008F184C /* AWSAllTestsHost */, CE0D415E1C6A66AA006B91B5 /* Products */, ); sourceTree = ""; @@ -4508,6 +4603,9 @@ E4E1DA4F1E5F5BBD0080F769 /* AWSKMSTests.xctest */, 181270C11E8EB53900174785 /* AWSLogs.framework */, 181270C91E8EB53A00174785 /* AWSLogsUnitTests.xctest */, + EFDE85E51ED2046E008841EC /* AWSCognitoAuth.framework */, + EFDE85F61ED2050C008841EC /* AWSCognitoAuthTests.xctest */, + EFDE860A1ED20517008841EC /* AWSCognitoAuthUnitTests.xctest */, ); name = Products; sourceTree = ""; @@ -5892,6 +5990,17 @@ path = AWSKMSTests; sourceTree = ""; }; + EF2211831ED75A0400F432F7 /* UICKeyChainStore */ = { + isa = PBXGroup; + children = ( + EF2211841ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.h */, + EF2211851ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.m */, + EF2211861ED75A0400F432F7 /* LICENSE */, + EF2211871ED75A0400F432F7 /* README.md */, + ); + path = UICKeyChainStore; + sourceTree = ""; + }; EF76F9C41C9A11C900F881D3 /* Internal */ = { isa = PBXGroup; children = ( @@ -5909,6 +6018,44 @@ path = ../AWSCognitoIdentityProvider/Internal; sourceTree = ""; }; + EFDE85A81ED203D9008841EC /* AWSCognitoAuthUnitTests */ = { + isa = PBXGroup; + children = ( + EFDE85A91ED203D9008841EC /* AWSCognitoAuthUnitTests.m */, + EFDE85AA1ED203D9008841EC /* Info.plist */, + ); + path = AWSCognitoAuthUnitTests; + sourceTree = ""; + }; + EFDE85AB1ED203D9008841EC /* AWSCognitoAuthTests */ = { + isa = PBXGroup; + children = ( + EFDE85AC1ED203D9008841EC /* AWSCognitoAuthTests.m */, + EFDE85AD1ED203D9008841EC /* Info.plist */, + ); + path = AWSCognitoAuthTests; + sourceTree = ""; + }; + EFDE85AE1ED203D9008841EC /* AWSCognitoAuth */ = { + isa = PBXGroup; + children = ( + EFDE85AF1ED203D9008841EC /* AWSCognitoAuth.h */, + EFDE85B01ED203D9008841EC /* AWSCognitoAuth.m */, + EFDE85B11ED203D9008841EC /* Info.plist */, + EFDE85B21ED203D9008841EC /* Internal */, + ); + path = AWSCognitoAuth; + sourceTree = ""; + }; + EFDE85B21ED203D9008841EC /* Internal */ = { + isa = PBXGroup; + children = ( + EF2211831ED75A0400F432F7 /* UICKeyChainStore */, + EFDE85B31ED203D9008841EC /* AWSCognitoAuth_Internal.h */, + ); + path = Internal; + sourceTree = ""; + }; EFDF14A11C99269D002CCFE2 /* JKBigInteger */ = { isa = PBXGroup; children = ( @@ -6464,6 +6611,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EFDE85CE1ED2046E008841EC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EF2211881ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.h in Headers */, + EF0FEB411ED2696700D763BC /* AWSCognitoAuth.h in Headers */, + EF0FEB421ED2698300D763BC /* AWSCognitoAuth_Internal.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -7932,6 +8089,63 @@ productReference = E4E1DA4F1E5F5BBD0080F769 /* AWSKMSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + EFDE85BC1ED2046E008841EC /* AWSCognitoAuth */ = { + isa = PBXNativeTarget; + buildConfigurationList = EFDE85E21ED2046E008841EC /* Build configuration list for PBXNativeTarget "AWSCognitoAuth" */; + buildPhases = ( + EFDE85BF1ED2046E008841EC /* Sources */, + EFDE85CC1ED2046E008841EC /* Frameworks */, + EFDE85CE1ED2046E008841EC /* Headers */, + EFDE85E11ED2046E008841EC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AWSCognitoAuth; + productName = AWSCognitoSignIn; + productReference = EFDE85E51ED2046E008841EC /* AWSCognitoAuth.framework */; + productType = "com.apple.product-type.framework"; + }; + EFDE85E71ED2050C008841EC /* AWSCognitoAuthTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = EFDE85F31ED2050C008841EC /* Build configuration list for PBXNativeTarget "AWSCognitoAuthTests" */; + buildPhases = ( + EFDE85EC1ED2050C008841EC /* Sources */, + EFDE85EF1ED2050C008841EC /* Frameworks */, + EFDE85F11ED2050C008841EC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + EF0FEB441ED269E900D763BC /* PBXTargetDependency */, + EFDE85EA1ED2050C008841EC /* PBXTargetDependency */, + ); + name = AWSCognitoAuthTests; + productName = AWSCognitoSignInTests; + productReference = EFDE85F61ED2050C008841EC /* AWSCognitoAuthTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + EFDE85F81ED20517008841EC /* AWSCognitoAuthUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = EFDE86071ED20517008841EC /* Build configuration list for PBXNativeTarget "AWSCognitoAuthUnitTests" */; + buildPhases = ( + EFDE85FD1ED20517008841EC /* Sources */, + EFDE86011ED20517008841EC /* Frameworks */, + EFDE86031ED20517008841EC /* Resources */, + EFDE86041ED20517008841EC /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + EF0FEB471ED26A7600D763BC /* PBXTargetDependency */, + EFDE85FB1ED20517008841EC /* PBXTargetDependency */, + ); + name = AWSCognitoAuthUnitTests; + productName = AWSCognitoSignInUnitTests; + productReference = EFDE860A1ED20517008841EC /* AWSCognitoAuthUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -8233,6 +8447,9 @@ CE9DEABC1C6A7FDF0060793F /* AWSCognito */, CE9DEAC51C6A7FDF0060793F /* AWSCognitoTests */, CE5604171C6BC8DF00B4E00B /* AWSCognitoUnitTests */, + EFDE85BC1ED2046E008841EC /* AWSCognitoAuth */, + EFDE85E71ED2050C008841EC /* AWSCognitoAuthTests */, + EFDE85F81ED20517008841EC /* AWSCognitoAuthUnitTests */, CEA316971C93A0EA002A9F58 /* AWSCognitoIdentityProvider */, CEA316A01C93A0EA002A9F58 /* AWSCognitoIdentityProviderTests */, CEA316BF1C93A415002A9F58 /* AWSCognitoIdentityProviderUnitTests */, @@ -8876,6 +9093,32 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EFDE85E11ED2046E008841EC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EF22118A1ED75A0400F432F7 /* LICENSE in Resources */, + EF22118B1ED75A0400F432F7 /* README.md in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFDE85F11ED2050C008841EC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EF0FEB3E1ED2194400D763BC /* Info.plist in Resources */, + EFDE85F21ED2050C008841EC /* credentials.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFDE86031ED20517008841EC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EF0FEB401ED2196000D763BC /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -9852,6 +10095,32 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + EFDE85BF1ED2046E008841EC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EF2211891ED75A0400F432F7 /* AWSCognitoAuthUICKeyChainStore.m in Sources */, + EF0FEB3B1ED218E300D763BC /* AWSCognitoAuth.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFDE85EC1ED2050C008841EC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EFDE85ED1ED2050C008841EC /* AWSTestUtility.m in Sources */, + EF0FEB3D1ED2192600D763BC /* AWSCognitoAuthTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFDE85FD1ED20517008841EC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 170C2D471EDFAE43008A2E52 /* AWSCognitoAuthTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -10665,11 +10934,31 @@ target = 181154751E201403008F184C /* AWSAllTestsHost */; targetProxy = E4E1DA5A1E5F5BDC0080F769 /* PBXContainerItemProxy */; }; + EF0FEB441ED269E900D763BC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EFDE85BC1ED2046E008841EC /* AWSCognitoAuth */; + targetProxy = EF0FEB431ED269E900D763BC /* PBXContainerItemProxy */; + }; + EF0FEB471ED26A7600D763BC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = EFDE85BC1ED2046E008841EC /* AWSCognitoAuth */; + targetProxy = EF0FEB461ED26A7600D763BC /* PBXContainerItemProxy */; + }; EF77D2271CBC65BE005F8F15 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = CE0D416C1C6A66E5006B91B5 /* AWSCore */; targetProxy = EF77D2261CBC65BE005F8F15 /* PBXContainerItemProxy */; }; + EFDE85EA1ED2050C008841EC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 181154751E201403008F184C /* AWSAllTestsHost */; + targetProxy = EFDE85EB1ED2050C008841EC /* PBXContainerItemProxy */; + }; + EFDE85FB1ED20517008841EC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 181154751E201403008F184C /* AWSAllTestsHost */; + targetProxy = EFDE85FC1ED20517008841EC /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -13524,6 +13813,110 @@ }; name = Release; }; + EFDE85E31ED2046E008841EC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = AWSCognitoAuth/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.amazonaws.sdk.ios.AWSCognitoAuth; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + EFDE85E41ED2046E008841EC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = AWSCognitoAuth/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.amazonaws.sdk.ios.AWSCognitoAuth; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + EFDE85F41ED2050C008841EC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = AWSCognitoAuth/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AWSCoreTests/OCMock", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.amazonaws.AWSCognitoAuthTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AWSAllTestsHost.app/AWSAllTestsHost"; + }; + name = Debug; + }; + EFDE85F51ED2050C008841EC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = AWSCognitoAuth/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AWSCoreTests/OCMock", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.amazonaws.AWSCognitoAuthTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AWSAllTestsHost.app/AWSAllTestsHost"; + }; + name = Release; + }; + EFDE86081ED20517008841EC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = AWSCognitoAuth/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AWSCoreTests/OCMock", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = com.amazonaws.AWSCognitoAuthUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + EFDE86091ED20517008841EC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = AWSCognitoAuth/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/AWSCoreTests/OCMock", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = com.amazonaws.AWSCognitoAuthUnitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -14238,6 +14631,33 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + EFDE85E21ED2046E008841EC /* Build configuration list for PBXNativeTarget "AWSCognitoAuth" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EFDE85E31ED2046E008841EC /* Debug */, + EFDE85E41ED2046E008841EC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EFDE85F31ED2050C008841EC /* Build configuration list for PBXNativeTarget "AWSCognitoAuthTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EFDE85F41ED2050C008841EC /* Debug */, + EFDE85F51ED2050C008841EC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EFDE86071ED20517008841EC /* Build configuration list for PBXNativeTarget "AWSCognitoAuthUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EFDE86081ED20517008841EC /* Debug */, + EFDE86091ED20517008841EC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = CE0D41541C6A66A9006B91B5 /* Project object */; diff --git a/AWSiOSSDKv2.xcodeproj/xcshareddata/xcschemes/AWSCognitoAuth.xcscheme b/AWSiOSSDKv2.xcodeproj/xcshareddata/xcschemes/AWSCognitoAuth.xcscheme new file mode 100644 index 00000000000..c9bc664568a --- /dev/null +++ b/AWSiOSSDKv2.xcodeproj/xcshareddata/xcschemes/AWSCognitoAuth.xcscheme @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fe88c7d3f5..823f941285e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,35 @@ # AWS Mobile SDK for iOS CHANGELOG +## 2.5.8 + +### New Features +* **Amazon Cognito Auth (Beta)** + * A new SDK that enables sign-up and sign-in for Amazon Cognito Your User Pools via a lightweight hosted ui. + +### Enhancements + +* **Amazon Pinpoint** + * Introduce `isApplicationLevelOptOut` block to `AWSPinpointConfiguration`. Use this to configure whether or not client should receive push notifications, at an application level. + +### Bug fixes + +* **Amazon SNS** + * Fixed error parsing for service responses. **Note:** This change also fixes error response parsing for `AutoScaling`, `CloudWatch`, `ELB`, `SES`, `SimpleDB`, `SQS` and `STS`. [Github Issue #676](https://github.com/aws/aws-sdk-ios/issues/676) and [Github Issue #671](https://github.com/aws/aws-sdk-ios/issues/671) + +* **Amazon Cognito Identity Provider** + * Fixed crash with AWSCognitoIdentityUserPool.calculateSecretHash when username contained non ASCII characters. [Github Issue #679](https://github.com/aws/aws-sdk-ios/issues/679) + +### Misc changes + +* **AWS IoT** + * Deprecating default endpoint for AWSIoTDataService. Client should use custom endpoint when initializing AWSServiceConfiguration to be used for AWSIoTDataManager. + ## 2.5.7 ### Enhancements * **Amazon Polly** - * Added support for new German voice id - `Vicki`. + * Added support for new voice id - `Vicki`. ### Bug fixes diff --git a/Scripts/GenerateAppleDocs.sh b/Scripts/GenerateAppleDocs.sh index 15026b823c7..8806c5a84f9 100644 --- a/Scripts/GenerateAppleDocs.sh +++ b/Scripts/GenerateAppleDocs.sh @@ -9,7 +9,7 @@ function cleanup } -VERSION="2.5.7" +VERSION="2.5.8" if [ -n $1 ] && [ "$1" == "clean" ]; then cleanup @@ -51,6 +51,7 @@ else cp -r AWSSimpleDB ./docs_tmp/AWSSimpleDB cp -r AWSSNS ./docs_tmp/AWSSNS cp -r AWSSQS ./docs_tmp/AWSSQS + cp -r AWSCognitoAuth ./docs_tmp/AWSCognitoAuth rm -rf ./docs_tmp/AWSCore/Bolts rm -rf ./docs_tmp/AWSCore/Fabric @@ -66,6 +67,7 @@ else rm -rf ./docs_tmp/AWSCognito/Internal rm -rf ./docs_tmp/AWSCognito/Fabric rm -rf ./docs_tmp/AWSCognitoIdentityProvider/Internal + rm -rf ./docs_tmp/AWSCognitoAuth/Internal rm -rf ./docs_tmp/AWSMobileAnalytics/Internal rm -rf ./docs_tmp/AWSIoT/Internal rm -rf ./docs_tmp/AWSLex/Bluefront diff --git a/Scripts/Package.sh b/Scripts/Package.sh index f2980d65d5b..e2b2784383a 100644 --- a/Scripts/Package.sh +++ b/Scripts/Package.sh @@ -25,6 +25,7 @@ if [ -x "Scripts/SdkPackage.sh" ]; then Scripts/SdkPackage.sh AWSAutoScaling Scripts/SdkPackage.sh AWSCognito Scripts/SdkPackage.sh AWSCognitoIdentityProvider + Scripts/SdkPackage.sh AWSCognitoAuth Scripts/SdkPackage.sh AWSCloudWatch Scripts/SdkPackage.sh AWSDeepSense Scripts/SdkPackage.sh AWSDynamoDB