From e696ff315ef099d525c4b97dd5477ea2feca8667 Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Sat, 28 Sep 2019 15:14:09 -0400 Subject: [PATCH 01/10] wip --- .../STPAPIClient+PushProvisioning.h | 24 +++++ .../STPPushProvisioningContext.h | 30 ++++++ .../STPPushProvisioningDetails.h | 28 ++++++ .../STPPushProvisioningDetailsParams.h | 27 ++++++ Stripe/PublicHeaders/Stripe.h | 4 + Stripe/STPAPIClient+PushProvisioning.m | 61 ++++++++++++ Stripe/STPPushProvisioningContext.m | 69 ++++++++++++++ Stripe/STPPushProvisioningDetails.m | 92 +++++++++++++++++++ Stripe/STPPushProvisioningDetailsParams.m | 34 +++++++ ...STPPushProvisioningDetailsFunctionalTest.m | 45 +++++++++ ...K91WoXa9u_push_provisioning_details_0.tail | 27 ++++++ 11 files changed, 441 insertions(+) create mode 100644 Stripe/PublicHeaders/STPAPIClient+PushProvisioning.h create mode 100644 Stripe/PublicHeaders/STPPushProvisioningContext.h create mode 100644 Stripe/PublicHeaders/STPPushProvisioningDetails.h create mode 100644 Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h create mode 100644 Stripe/STPAPIClient+PushProvisioning.m create mode 100644 Stripe/STPPushProvisioningContext.m create mode 100644 Stripe/STPPushProvisioningDetails.m create mode 100644 Stripe/STPPushProvisioningDetailsParams.m create mode 100644 Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m create mode 100644 Tests/recorded_network_traffic/STPPushProvisioningDetailsFunctionalTest/testRetrievePushProvisioningDetails/get_v1_issuing_cards_ic_1C0Xig4JYtv6MPZK91WoXa9u_push_provisioning_details_0.tail diff --git a/Stripe/PublicHeaders/STPAPIClient+PushProvisioning.h b/Stripe/PublicHeaders/STPAPIClient+PushProvisioning.h new file mode 100644 index 00000000000..a0bc7ac1fe8 --- /dev/null +++ b/Stripe/PublicHeaders/STPAPIClient+PushProvisioning.h @@ -0,0 +1,24 @@ +// +// STPAPIClient+PushProvisioning.h +// Stripe +// +// Created by Jack Flintermann on 9/27/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import +#import "STPPushProvisioningDetails.h" +#import "STPPushProvisioningDetailsParams.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^STPPushProvisioningDetailsCompletionBlock)(STPPushProvisioningDetails * __nullable details, NSError * __nullable error); + +@interface STPAPIClient (PushProvisioning) + +- (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsParams *)params + completion:(STPPushProvisioningDetailsCompletionBlock)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/STPPushProvisioningContext.h b/Stripe/PublicHeaders/STPPushProvisioningContext.h new file mode 100644 index 00000000000..7799dccf95b --- /dev/null +++ b/Stripe/PublicHeaders/STPPushProvisioningContext.h @@ -0,0 +1,30 @@ +// +// STPPushProvisioningContext.h +// Stripe +// +// Created by Jack Flintermann on 9/27/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import +#import +#import "STPEphemeralKeyProvider.h" +#import "STPCard.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface STPPushProvisioningContext : NSObject + ++ (PKAddPaymentPassRequestConfiguration *)requestConfigurationWithName:(NSString *)name + description:(nullable NSString *)description + last4:(nullable NSString *)last4 + brand:(STPCardBrand)brand; +- (instancetype)initWithKeyProvider:(id)keyProvider; +- (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller + generateRequestWithCertificateChain:(NSArray *)certificates + nonce:(NSData *)nonce + nonceSignature:(NSData *)nonceSignature + completionHandler:(void (^)(PKAddPaymentPassRequest *))handler; +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetails.h b/Stripe/PublicHeaders/STPPushProvisioningDetails.h new file mode 100644 index 00000000000..b6bc3ef898f --- /dev/null +++ b/Stripe/PublicHeaders/STPPushProvisioningDetails.h @@ -0,0 +1,28 @@ +// +// STPPushProvisioningDetails.h +// Stripe +// +// Created by Jack Flintermann on 9/26/18 +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import +#import "STPAPIResponseDecodable.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface STPPushProvisioningDetails : NSObject + +@property (nonatomic, readonly) NSString *cardId; +@property (nonatomic, readonly) NSData *encryptedPassData; +@property (nonatomic, readonly) NSData *activationData; +@property (nonatomic, readonly) NSData *ephemeralPublicKey; + ++ (instancetype)detailsWithCardId:(NSString *)cardId + encryptedPassData:(NSData *)encryptedPassData + activationData:(NSData *)activationData + ephemeralPublicKey:(NSData *)ephemeralPublicKey; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h new file mode 100644 index 00000000000..ac4e242f560 --- /dev/null +++ b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h @@ -0,0 +1,27 @@ +// +// STPPushProvisioningDetailsParams.h +// Stripe +// +// Created by Jack Flintermann on 9/26/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface STPPushProvisioningDetailsParams : NSObject + +@property (nonatomic, readonly) NSString *cardId; +@property (nonatomic, readonly) NSArray *certificates; +@property (nonatomic, readonly) NSData *nonce; +@property (nonatomic, readonly) NSData *nonceSignature; + ++(instancetype)paramsWithCardId:(NSString *)cardId + certificates:(NSArray*)certificates + nonce:(NSData *)nonce + nonceSignature:(NSData *)nonceSignature; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/Stripe.h b/Stripe/PublicHeaders/Stripe.h index 5614f644fb5..716e9a6e8e1 100644 --- a/Stripe/PublicHeaders/Stripe.h +++ b/Stripe/PublicHeaders/Stripe.h @@ -76,6 +76,10 @@ #import "STPPaymentOption.h" #import "STPPaymentOptionsViewController.h" #import "STPPaymentResult.h" +#import "STPPushProvisioningContext.h" +#import "STPPushProvisioningDetails.h" +#import "STPPushProvisioningDetailsParams.h" +#import "STPAPIClient+PushProvisioning.h" #import "STPRedirectContext.h" #import "STPSetupIntent.h" #import "STPSetupIntentConfirmParams.h" diff --git a/Stripe/STPAPIClient+PushProvisioning.m b/Stripe/STPAPIClient+PushProvisioning.m new file mode 100644 index 00000000000..4fe43e5a9fc --- /dev/null +++ b/Stripe/STPAPIClient+PushProvisioning.m @@ -0,0 +1,61 @@ +// +// STPAPIClient+PushProvisioning.m +// Stripe +// +// Created by Jack Flintermann on 9/27/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPAPIClient+PushProvisioning.h" +#import "STPAPIRequest.h" + +@implementation STPAPIClient (PushProvisioning) + +- (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsParams *)params + completion:(STPPushProvisioningDetailsCompletionBlock)completion { + + NSString *endpoint = [NSString stringWithFormat:@"issuing/cards/%@/push_provisioning_details", params.cardId]; + NSMutableArray* base64Certificates = [NSMutableArray arrayWithCapacity:params.certificates.count]; + for (NSData *certificate in params.certificates) { + NSString *base64Certificate = [certificate base64EncodedStringWithOptions:kNilOptions]; + [base64Certificates addObject:base64Certificate]; + } + + NSString *nonceHexString = [self hexadecimalStringForData:params.nonce]; + NSString *nonceSignatureHexString = [self hexadecimalStringForData:params.nonceSignature]; + + NSDictionary *parameters = @{ + @"ios": @{ + @"certificates": base64Certificates, + @"nonce": nonceHexString, + @"nonce_signature": nonceSignatureHexString, + }, + }; + + [STPAPIRequest getWithAPIClient:self + endpoint:endpoint + parameters:parameters + deserializer:[STPPushProvisioningDetails new] + completion:^(STPPushProvisioningDetails *details, __unused NSHTTPURLResponse *response, NSError *error) { + completion(details, error); + }]; +} + +- (NSString *)hexadecimalStringForData:(NSData *)data { + /* Returns hexadecimal string of NSData. Empty string if data is empty. */ + + const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; + + if (!dataBuffer) + return [NSString string]; + + NSUInteger dataLength = [data length]; + NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)]; + + for (NSUInteger i = 0; i < dataLength; ++i) + [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]]; + + return [NSString stringWithString:hexString]; +} + +@end diff --git a/Stripe/STPPushProvisioningContext.m b/Stripe/STPPushProvisioningContext.m new file mode 100644 index 00000000000..a84ea5542c2 --- /dev/null +++ b/Stripe/STPPushProvisioningContext.m @@ -0,0 +1,69 @@ +// +// STPPushProvisioningContext.m +// Stripe +// +// Created by Jack Flintermann on 9/27/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPPushProvisioningContext.h" +#import "STPEphemeralKeyManager.h" +#import "STPAPIClient+Private.h" +#import "STPAPIClient+PushProvisioning.m" +#import "STPEphemeralKey.h" + +@interface STPPushProvisioningContext() +@property (nonatomic, strong) STPEphemeralKeyManager *keyManager; +@property (nonatomic, strong, nullable) STPEphemeralKey *ephemeralKey; +@end + +@implementation STPPushProvisioningContext + +- (instancetype)initWithKeyProvider:(id)keyProvider { + self = [super init]; + if (self) { + _keyManager = [[STPEphemeralKeyManager alloc] initWithKeyProvider:keyProvider apiVersion:[STPAPIClient apiVersion] performsEagerFetching:NO]; + } + return self; +} + ++ (PKAddPaymentPassRequestConfiguration *)requestConfigurationWithName:(NSString *)name + description:(nullable NSString *)description + last4:(nullable NSString *)last4 + brand:(STPCardBrand)brand { + PKAddPaymentPassRequestConfiguration *config = [[PKAddPaymentPassRequestConfiguration alloc] initWithEncryptionScheme:PKEncryptionSchemeECC_V2]; + config.cardholderName = name; + config.primaryAccountSuffix = last4; + config.localizedDescription = description; + if (@available(iOS 12.0, *)) { + config.style = PKAddPaymentPassStylePayment; + } + if (brand == STPCardBrandVisa) { + config.paymentNetwork = PKPaymentNetworkVisa; + } + return config; +} + +- (void)addPaymentPassViewController:(__unused PKAddPaymentPassViewController *)controller generateRequestWithCertificateChain:(NSArray *)certificates nonce:(NSData *)nonce nonceSignature:(NSData *)nonceSignature completionHandler:(void (^)(PKAddPaymentPassRequest *))handler { + [self.keyManager getOrCreateKey:^(STPEphemeralKey * _Nullable ephemeralKey, NSError * _Nullable keyError) { + if (keyError != nil) { + handler([PKAddPaymentPassRequest new]); + return; + } + STPPushProvisioningDetailsParams *params = [STPPushProvisioningDetailsParams paramsWithCardId:ephemeralKey.issuingCardID certificates:certificates nonce:nonce nonceSignature:nonceSignature]; + STPAPIClient *client = [STPAPIClient apiClientWithEphemeralKey:ephemeralKey]; + [client retrievePushProvisioningDetailsWithParams:params completion:^(STPPushProvisioningDetails * _Nullable details, NSError * _Nullable error) { + if (error != nil) { + handler([PKAddPaymentPassRequest new]); + return; + } + PKAddPaymentPassRequest *request = [[PKAddPaymentPassRequest alloc] init]; + request.activationData = details.activationData; + request.encryptedPassData = details.encryptedPassData; + request.ephemeralPublicKey = details.ephemeralPublicKey; + handler(request); + }]; + }]; +} + +@end diff --git a/Stripe/STPPushProvisioningDetails.m b/Stripe/STPPushProvisioningDetails.m new file mode 100644 index 00000000000..8e53c60fffb --- /dev/null +++ b/Stripe/STPPushProvisioningDetails.m @@ -0,0 +1,92 @@ +// +// STPPushProvisioningDetails.m +// Stripe +// +// Created by Jack Flintermann on 9/26/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPPushProvisioningDetails.h" + +#import "NSDictionary+Stripe.h" + +@interface STPPushProvisioningDetails () + +@property (nonatomic, readwrite) NSString *cardId; +@property (nonatomic, readwrite) NSData *encryptedPassData; +@property (nonatomic, readwrite) NSData *activationData; +@property (nonatomic, readwrite) NSData *ephemeralPublicKey; +@property (nonatomic, readwrite, copy) NSDictionary *allResponseFields; + +@end + +@implementation STPPushProvisioningDetails + ++ (instancetype)detailsWithCardId:(NSString *)cardId + encryptedPassData:(NSData *)encryptedPassData + activationData:(NSData *)activationData + ephemeralPublicKey:(NSData *)ephemeralPublicKey { + STPPushProvisioningDetails *details = [[self alloc] init]; + details.cardId = cardId; + details.encryptedPassData = encryptedPassData; + details.activationData = activationData; + details.ephemeralPublicKey = ephemeralPublicKey; + return details; +} + +#pragma mark - STPAPIResponseDecodable + ++ (instancetype)decodedObjectFromAPIResponse:(NSDictionary *)response { + NSDictionary *dict = [response stp_dictionaryByRemovingNulls]; + if (!dict) { + return nil; + } + + // required fields + NSString *cardId = [dict stp_stringForKey:@"card"]; + NSString *encryptedPassString = [dict stp_stringForKey:@"contents"]; + NSData *encryptedPassData = encryptedPassString ? [[NSData alloc] initWithBase64EncodedString:encryptedPassString options:0] : nil; + + NSString *activationString = [dict stp_stringForKey:@"activation_data"]; + NSData *activationData = activationString ? [[NSData alloc] initWithBase64EncodedString:activationString options:0] : nil; + + NSString *ephemeralPublicKeyString = [dict stp_stringForKey:@"ephemeral_public_key"]; + NSData *ephemeralPublicKeyData = ephemeralPublicKeyString ? [[NSData alloc] initWithBase64EncodedString:ephemeralPublicKeyString options:0] : nil; + + if (cardId == nil || encryptedPassData == nil || activationData == nil || ephemeralPublicKeyData == nil) { + return nil; + } + + STPPushProvisioningDetails *details = [self detailsWithCardId:cardId + encryptedPassData:encryptedPassData + activationData:activationData + ephemeralPublicKey:ephemeralPublicKeyData]; + details.allResponseFields = dict; + + return details; +} + + +#pragma mark - Equality + +- (BOOL)isEqual:(STPPushProvisioningDetails *)details { + return [self isEqualToDetails:details]; +} + +- (NSUInteger)hash { + return [self.activationData hash]; +} + +- (BOOL)isEqualToDetails:(STPPushProvisioningDetails *)details { + if (self == details) { + return YES; + } + + if (!details || ![details isKindOfClass:self.class]) { + return NO; + } + + return [self.activationData isEqualToData:details.activationData]; +} + +@end diff --git a/Stripe/STPPushProvisioningDetailsParams.m b/Stripe/STPPushProvisioningDetailsParams.m new file mode 100644 index 00000000000..e5fd9e3b721 --- /dev/null +++ b/Stripe/STPPushProvisioningDetailsParams.m @@ -0,0 +1,34 @@ +// +// STPPushProvisioningDetailsParams.m +// Stripe +// +// Created by Jack Flintermann on 9/26/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPPushProvisioningDetailsParams.h" + +@interface STPPushProvisioningDetailsParams () + +@property (nonatomic, readwrite) NSString *cardId; +@property (nonatomic, readwrite) NSArray *certificates; +@property (nonatomic, readwrite) NSData *nonce; +@property (nonatomic, readwrite) NSData *nonceSignature; + +@end + +@implementation STPPushProvisioningDetailsParams + ++(instancetype)paramsWithCardId:(NSString *)cardId + certificates:(NSArray*)certificates + nonce:(NSData *)nonce + nonceSignature:(NSData *)nonceSignature { + STPPushProvisioningDetailsParams *params = [[self alloc] init]; + params.cardId = cardId; + params.certificates = certificates; + params.nonce = nonce; + params.nonceSignature = nonceSignature; + return params; +} + +@end diff --git a/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m b/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m new file mode 100644 index 00000000000..783b5fcc046 --- /dev/null +++ b/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m @@ -0,0 +1,45 @@ +// +// STPPushProvisioningDetailsFunctionalTest.m +// StripeiOS Tests +// +// Created by Jack Flintermann on 11/30/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import +#import +#import "STPAPIClient+PushProvisioning.h" +#import "STPNetworkStubbingTestCase.h" + +@interface STPPushProvisioningDetailsFunctionalTest : STPNetworkStubbingTestCase +@end + +@implementation STPPushProvisioningDetailsFunctionalTest + +- (void)setUp { + [super setUp]; +} + +- (void)testRetrievePushProvisioningDetails { + // this API requires a secret key - replace the key below if you need to re-record the network traffic. + STPAPIClient *client = [[STPAPIClient alloc] initWithPublishableKey:@"pk_test_REPLACEME"]; + NSString *cardId = @"ic_1C0Xig4JYtv6MPZK91WoXa9u"; + NSString *cert1 = @"MIID/TCCA6OgAwIBAgIIGM2CpiS9WyYwCgYIKoZIzj0EAwIwgYAxNDAyBgNVBAMMK0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xODA2MDEyMjE0MTVaFw0yMDA2MzAyMjE0MTVaMGwxMjAwBgNVBAMMKWVjYy1jcnlwdG8tc2VydmljZXMtZW5jaXBoZXJtZW50X1VDNi1QUk9EMRQwEgYDVQQLDAtpT1MgU3lzdGVtczETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASzCVyQGX3syyW2aI6nyfNQe+vjjzjU4rLO0ZiWiVZZSmEzYfACFI8tuDFiDLv9XWrHEeX0/yNtGVjwAzpanWb/o4ICGDCCAhQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSEtoTMOoZichZZlOgao71I3zrfCzBHBggrBgEFBQcBAQQ7MDkwNwYIKwYBBQUHMAGGK2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtYXBwbGV3d2RyY2EyMDUwggEdBgNVHSAEggEUMIIBEDCCAQwGCSqGSIb3Y2QFATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxld3dkcmNhMi5jcmwwHQYDVR0OBBYEFI5aYtQKaJCRpvI1Dgh+Ra4x2iCrMA4GA1UdDwEB/wQEAwIDKDASBgkqhkiG92NkBicBAf8EAgUAMAoGCCqGSM49BAMCA0gAMEUCIAY/9gwN/KAAw3EtW3NyeX1UVM3fO+wVt0cbeHL8eM/mAiEAppLm5O/2Ox8uHkxI4U/kU5vDhJA21DRbzm2rsYN+EcQ="; + NSString *cert2 = @"MIIC9zCCAnygAwIBAgIIb+/Y9emjp+4wCgYIKoZIzj0EAwIwZzEbMBkGA1UEAwwSQXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcNMTQwNTA2MjM0MzI0WhcNMjkwNTA2MjM0MzI0WjCBgDE0MDIGA1UEAwwrQXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ0EgLSBHMjEmMCQGA1UECwwdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3fC3BkvP3XMEE8RDiQOTgPte9nStQmFSWAImUxnIYyIHCVJhysTZV+9tJmiLdJGMxPmAaCj8CWjwENrp0C7JGqOB9zCB9DBGBggrBgEFBQcBAQQ6MDgwNgYIKwYBBQUHMAGGKmh0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDQtYXBwbGVyb290Y2FnMzAdBgNVHQ4EFgQUhLaEzDqGYnIWWZToGqO9SN863wswDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS7sN6hWDOImqSKmd6+veuv2sskqzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmFwcGxlLmNvbS9hcHBsZXJvb3RjYWczLmNybDAOBgNVHQ8BAf8EBAMCAQYwEAYKKoZIhvdjZAYCDwQCBQAwCgYIKoZIzj0EAwIDaQAwZgIxANmxxzHGI/ZPTdDZR8V9GGkRh3En02it4Jtlmr5s3z9GppAJvm6hOyywUYlBPIfSvwIxAPxkUolLPF2/axzCiZgvcq61m6oaCyNUd1ToFUOixRLal1BzfF7QbrJcYlDXUfE6Wg=="; + NSString *nonce = @"ea85a73a"; + NSString *nonceSignature = @"QBfCqTvDhmRcwqxJF3fDqzhXezIpwrpHFcOMw7/DvGVBwpfCuicwwqHCmMKYMD06w754wrjChcObwqjDr8K9wqxxUydQaMOyfsKGZMK4AcKMwqNfwoHDlcKLHsO5w7JqQiHDln7Du8KUNMOnwqpGwq/CqcKswo1Lw7s="; + NSArray *certs = @[ + [[NSData alloc] initWithBase64EncodedString:cert1 options:0], + [[NSData alloc] initWithBase64EncodedString:cert2 options:0], + ]; + XCTestExpectation *expectation = [self expectationWithDescription:@"Push provisioning details"]; + STPPushProvisioningDetailsParams *params = [STPPushProvisioningDetailsParams paramsWithCardId:@"ic_1C0Xig4JYtv6MPZK91WoXa9u" certificates:certs nonce:[[NSData alloc] initWithBase64EncodedString:nonce options:0] nonceSignature:[[NSData alloc] initWithBase64EncodedString:nonceSignature options:0]]; + [client retrievePushProvisioningDetailsWithParams:params completion:^(STPPushProvisioningDetails * _Nullable details, NSError * _Nullable error) { + [expectation fulfill]; + XCTAssertNil(error); + XCTAssert([details.cardId isEqualToString:cardId]); + }]; + [self waitForExpectationsWithTimeout:5.0f handler:nil]; +} + +@end diff --git a/Tests/recorded_network_traffic/STPPushProvisioningDetailsFunctionalTest/testRetrievePushProvisioningDetails/get_v1_issuing_cards_ic_1C0Xig4JYtv6MPZK91WoXa9u_push_provisioning_details_0.tail b/Tests/recorded_network_traffic/STPPushProvisioningDetailsFunctionalTest/testRetrievePushProvisioningDetails/get_v1_issuing_cards_ic_1C0Xig4JYtv6MPZK91WoXa9u_push_provisioning_details_0.tail new file mode 100644 index 00000000000..6095a2845d8 --- /dev/null +++ b/Tests/recorded_network_traffic/STPPushProvisioningDetailsFunctionalTest/testRetrievePushProvisioningDetails/get_v1_issuing_cards_ic_1C0Xig4JYtv6MPZK91WoXa9u_push_provisioning_details_0.tail @@ -0,0 +1,27 @@ +GET +/v1/issuing/cards/ic_1C0Xig4JYtv6MPZK91WoXa9u/push_provisioning_details\?ios%5Bcertificates%5D%5B0%5D=.*&ios%5Bcertificates%5D%5B1%5D=.*&ios%5Bnonce%5D=.*&ios%5Bnonce_signature%5D=.*$ +200 +application/json +Content-Type: application/json +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS, DELETE +Server: nginx +Access-Control-Expose-Headers: Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required +Access-Control-Max-Age: 300 +Stripe-Issuing-Push-Provisioning-Platform: ios +Cache-Control: no-cache, no-store +Date: Fri, 30 Nov 2018 23:12:54 GMT +Stripe-Version: 2015-10-12 +Access-Control-Allow-Credentials: true +Content-Length: 1278 +Connection: keep-alive +Strict-Transport-Security: max-age=31556926; includeSubDomains; preload +Request-Id: req_QTDJy3AYaxI1tL + +{ + "activation_data" : "TUJQQUMtMS1GSy00MDU1NTEuMS0tVERFQS1FNUVCNUJCQjhGMENDMjdCQjU5MUNCRTdCMTVDN0U2RjBENTQ5RDM1NkZERTRDQUZBNDBGOUNCMTA1MzI5NUQ4N0RBRTk0MTE0QTQyNENDQTY0NDAxRTFCQTExOTRBRDM=", + "object" : "issuing.push_provisioning_details", + "ephemeral_public_key" : "BHdLb5BNpoPrh9Btay8LwQ5oELoziQwJL7HagE3xB5mrbdgLa5iiwogu34Y32\/xBEviaN31s\/ONRXSetYT745ig=", + "card" : "ic_1C0Xig4JYtv6MPZK91WoXa9u", + "contents" : "UYeMxRqiYrjVzwqKcCGRVbgFXRspbDIKkWWly8e55caWkHYmO2DNnFtqD3y5S6bvGbe+bkNPCIkT1UzQQChCQOkb0P+cbVDBLaFGaDeJW0Mhca8\/6GwbUx9lp4H3czqszG504PkiA89dNvnbtwUmlQOpk+B\/IAMnkaXjD2xUBUtPX9xEr5EvckkDSHHFmpy5rbGfqnWsPbJNPwUiE+6mYbt643DqF9RpmgdFN84DImuMU1W0xshbkN7voq63L\/6UgTW7liTzWVzKUT36TtaTw5TGKVf1Niqu5CHNu2NpDEnzrvcwUCgphxRVgezJyFfq1NjhZVlGA2nUKZuRvc\/XjBwdE0fr4Enw5XfHbRQHorpv\/S2rX4Cmn4VHJE1JDHWK3Wrn4HmMOCH+psVi+T5hPvy6+\/v+0zRRmGGeFKQEx0soItHiQauN2\/zO4QoC2DCQOAKGj1KSzqHhTgdxBcBu4TIOQRsIXu6zk1ItenHIdq4thD8vF8m3wgJ8Y3KcG3TwwgbjomxOjO4rX0AA9q2V6w0TXWQ1eWC8WfX11J30Zt\/SbyYHoU8KrIdM2ANcOvIFHENnUNBcL7AO0+tjv9lVO7M9w7hKMiVJOnDGMeH2OQfnTBOJI8SEHGm2kDRNw\/5+VGJ7pHA1wZ9y2IS6EvY8IeNhqZ7HdBXhn18X4AWThZqmNvGuZoEU\/ZlPmfed\/c0BgqSw5x6K9GuC5G9Nyee3O1E6wETf4Z3goNbFnRYNJ8m+A4DxUKbvhhRSNva4d\/lRkoNuQj2ztPiLSAPVt1H7Dk3ryeyXCrqprHsjn5T35jXFOlm5whuyeGgeXWt3DUxsYXZGTiohZyU3bZELqW3EUSwjwQ==" +} \ No newline at end of file From f49f799ad26c0f5b989b176091ce4ba459a558fb Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Sat, 28 Sep 2019 15:36:10 -0400 Subject: [PATCH 02/10] fix --- Stripe.xcodeproj/project.pbxproj | 48 ++++++++++++++++++++++++++ Stripe/STPAPIClient+PushProvisioning.m | 6 ++-- Stripe/STPPushProvisioningContext.m | 2 +- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index 82f93a64107..1cf87ec5617 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -24,6 +24,22 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 0413CB22233FECD5006429EA /* STPPushProvisioningContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB1A233FECD4006429EA /* STPPushProvisioningContext.m */; }; + 0413CB23233FECD5006429EA /* STPPushProvisioningContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB1A233FECD4006429EA /* STPPushProvisioningContext.m */; }; + 0413CB24233FECD5006429EA /* STPPushProvisioningDetailsParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB1B233FECD4006429EA /* STPPushProvisioningDetailsParams.m */; }; + 0413CB25233FECD5006429EA /* STPPushProvisioningDetailsParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB1B233FECD4006429EA /* STPPushProvisioningDetailsParams.m */; }; + 0413CB26233FECD5006429EA /* STPPushProvisioningDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */; }; + 0413CB27233FECD5006429EA /* STPPushProvisioningDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */; }; + 0413CB28233FECD5006429EA /* STPPushProvisioningDetailsParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB29233FECD5006429EA /* STPPushProvisioningDetailsParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2A233FECD5006429EA /* STPPushProvisioningContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2B233FECD5006429EA /* STPPushProvisioningContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2C233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2D233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2E233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2F233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB30233FECD5006429EA /* STPAPIClient+PushProvisioning.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */; }; + 0413CB31233FECD5006429EA /* STPAPIClient+PushProvisioning.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */; }; 0426B96E1CEADC98006AC8DD /* STPColorUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0426B96C1CEADC98006AC8DD /* STPColorUtils.h */; }; 0426B96F1CEADC98006AC8DD /* STPColorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 0426B96D1CEADC98006AC8DD /* STPColorUtils.m */; }; 0426B9721CEAE3EB006AC8DD /* UITableViewCell+Stripe_Borders.h in Headers */ = {isa = PBXBuildFile; fileRef = 0426B9701CEAE3EB006AC8DD /* UITableViewCell+Stripe_Borders.h */; }; @@ -1345,6 +1361,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0413CB1A233FECD4006429EA /* STPPushProvisioningContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPushProvisioningContext.m; sourceTree = ""; }; + 0413CB1B233FECD4006429EA /* STPPushProvisioningDetailsParams.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPushProvisioningDetailsParams.m; sourceTree = ""; }; + 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPushProvisioningDetails.m; sourceTree = ""; }; + 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPPushProvisioningDetailsParams.h; path = PublicHeaders/STPPushProvisioningDetailsParams.h; sourceTree = ""; }; + 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPPushProvisioningContext.h; path = PublicHeaders/STPPushProvisioningContext.h; sourceTree = ""; }; + 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "STPAPIClient+PushProvisioning.h"; path = "PublicHeaders/STPAPIClient+PushProvisioning.h"; sourceTree = ""; }; + 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPPushProvisioningDetails.h; path = PublicHeaders/STPPushProvisioningDetails.h; sourceTree = ""; }; + 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STPAPIClient+PushProvisioning.m"; sourceTree = ""; }; 0426B96C1CEADC98006AC8DD /* STPColorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPColorUtils.h; sourceTree = ""; }; 0426B96D1CEADC98006AC8DD /* STPColorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPColorUtils.m; sourceTree = ""; }; 0426B9701CEAE3EB006AC8DD /* UITableViewCell+Stripe_Borders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableViewCell+Stripe_Borders.h"; sourceTree = ""; }; @@ -2884,6 +2908,14 @@ 04633B061CD44F47009D4FB5 /* STPAPIClient+ApplePay.h */, 04633B041CD44F1C009D4FB5 /* STPAPIClient+ApplePay.m */, C184107A1EC2539F00178149 /* STPEphemeralKeyProvider.h */, + 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */, + 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */, + 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */, + 0413CB1A233FECD4006429EA /* STPPushProvisioningContext.m */, + 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */, + 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */, + 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */, + 0413CB1B233FECD4006429EA /* STPPushProvisioningDetailsParams.m */, F152321F1EA92FCF00D65C67 /* STPRedirectContext.h */, F152321C1EA92FC100D65C67 /* STPRedirectContext.m */, 0731328D2277A3F60019CE3F /* STPPinManagementService.h */, @@ -3289,6 +3321,7 @@ C159933D1D8808970047950D /* STPShippingMethodsViewController.h in Headers */, F15232251EA9303800D65C67 /* STPURLCallbackHandler.h in Headers */, B3A2413A1FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */, + 0413CB2D233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */, B6F16097223351C20088C970 /* STPPaymentIntentActionRedirectToURL.h in Headers */, B32B176620F80442000D6EF8 /* STPRedirectContext+Private.h in Headers */, 319A608722E9186B00AACF66 /* STDSChallengeStatusReceiver.h in Headers */, @@ -3333,10 +3366,12 @@ 319A609122E9186B00AACF66 /* STDSJSONEncoder.h in Headers */, 319A608222E9186B00AACF66 /* STDSAlreadyInitializedException.h in Headers */, 04F94DD11D22A239004FC826 /* STPPromise.h in Headers */, + 0413CB2F233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */, C1BD9B351E3940C400CEE925 /* STPSourceVerification.h in Headers */, 36E582FD22B456760044F82C /* STPAuthenticationContext.h in Headers */, F1A0197D1EA5733200354301 /* STPSourceParams+Private.h in Headers */, 04633B161CD45222009D4FB5 /* STPAPIClient+ApplePay.h in Headers */, + 0413CB2B233FECD5006429EA /* STPPushProvisioningContext.h in Headers */, 0438EF2E1B7416BB00D506CC /* STPFormTextField.h in Headers */, B66AC61522C6E6590064C551 /* STPPaymentHandlerActionParams.h in Headers */, 04A4C38A1C4F25F900B3B290 /* NSArray+Stripe.h in Headers */, @@ -3358,6 +3393,7 @@ C1717DB11CC00ED60009CF4A /* STPAddress.h in Headers */, 04B31DE71D09D25F00EF1631 /* STPPaymentOptionsInternalViewController.h in Headers */, 3604007A22C18DA9004CF80B /* STPThreeDSSelectionCustomization.h in Headers */, + 0413CB29233FECD5006429EA /* STPPushProvisioningDetailsParams.h in Headers */, 3604007D22C18DBA004CF80B /* STPThreeDSButtonCustomization.h in Headers */, 3604007622C18D93004CF80B /* STPThreeDSCustomization+Private.h in Headers */, F152322B1EA9306100D65C67 /* NSURLComponents+Stripe.h in Headers */, @@ -3530,6 +3566,7 @@ 04EBC7571B7533C300A0E6AE /* STPCardValidator.h in Headers */, 046FE9A11CE55D1D00DA6A7B /* STPPaymentActivityIndicatorView.h in Headers */, C11810861CC6AF4C0022FB55 /* STPPaymentOption.h in Headers */, + 0413CB28233FECD5006429EA /* STPPushProvisioningDetailsParams.h in Headers */, B640DB1222C58E82003C8810 /* STPSetupIntentConfirmParams.h in Headers */, 3635C33322B03E00004298B8 /* STPEmptyStripeResponse.h in Headers */, B690DDEC222F01BF000B902D /* STPPaymentMethodBillingDetails.h in Headers */, @@ -3562,6 +3599,7 @@ C1A06F101E1D8A7F004DCA06 /* STPCard+Private.h in Headers */, F1D3A24C1EB012010095BFA9 /* STPMultipartFormDataEncoder.h in Headers */, C113D2191EBB9A36006FACC2 /* STPEphemeralKey.h in Headers */, + 0413CB2A233FECD5006429EA /* STPPushProvisioningContext.h in Headers */, 04E39F6A1CED48D500AF3B96 /* UIBarButtonItem+Stripe.h in Headers */, 31B9609022FE128C00DC6FD9 /* STPBankSelectionViewController.h in Headers */, F1FA6F951E25960500EB444D /* STPCoreScrollViewController+Private.h in Headers */, @@ -3622,11 +3660,13 @@ 315CB8CE22E7D96000E612A3 /* STDSAuthenticationRequestParameters.h in Headers */, 315CB8CF22E7D96000E612A3 /* STDSRuntimeErrorEvent.h in Headers */, 315CB8D022E7D96000E612A3 /* STDSErrorMessage.h in Headers */, + 0413CB2C233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */, 315CB8D122E7D96000E612A3 /* STDSCompletionEvent.h in Headers */, 315CB8D222E7D96000E612A3 /* STDSThreeDSProtocolVersion.h in Headers */, 315CB8D322E7D96000E612A3 /* STDSAuthenticationResponse.h in Headers */, 315CB8D422E7D96100E612A3 /* STDSThreeDS2Service.h in Headers */, 315CB8D522E7D96100E612A3 /* STDSFooterCustomization.h in Headers */, + 0413CB2E233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */, 315CB8D622E7D96100E612A3 /* STDSAlreadyInitializedException.h in Headers */, 315CB8D722E7D96100E612A3 /* STDSJSONEncoder.h in Headers */, 31F5A50B22F0EFB10033663B /* STPPaymentMethodFPX.h in Headers */, @@ -4509,6 +4549,7 @@ 04A4C3901C4F25F900B3B290 /* UIViewController+Stripe_ParentViewController.m in Sources */, 04F94DA01D229F0B004FC826 /* STPPostalCodeValidator.m in Sources */, C124A17F1CCAA0C2007D42EE /* NSMutableURLRequest+Stripe.m in Sources */, + 0413CB31233FECD5006429EA /* STPAPIClient+PushProvisioning.m in Sources */, C15993411D8808A10047950D /* STPShippingMethodTableViewCell.m in Sources */, B690DDEF222F01BF000B902D /* STPPaymentMethodBillingDetails.m in Sources */, B690DDFB222F0564000B902D /* STPPaymentMethodCard.m in Sources */, @@ -4553,6 +4594,7 @@ 04633B011CD129CB009D4FB5 /* STPPhoneNumberValidator.m in Sources */, F152322D1EA9306100D65C67 /* NSURLComponents+Stripe.m in Sources */, C159933F1D88089B0047950D /* STPShippingMethodsViewController.m in Sources */, + 0413CB27233FECD5006429EA /* STPPushProvisioningDetails.m in Sources */, 04A488451CA3580700506E53 /* UINavigationController+Stripe_Completion.m in Sources */, 049E84CF1A605DE0000B66CD /* STPBankAccount.m in Sources */, 049E84D01A605DE0000B66CD /* STPCard.m in Sources */, @@ -4588,12 +4630,14 @@ 0451CC471C49AE1C003B2CA6 /* STPPaymentResult.m in Sources */, 049E84D11A605DE0000B66CD /* STPToken.m in Sources */, C1BD9B371E3940C400CEE925 /* STPSourceVerification.m in Sources */, + 0413CB23233FECD5006429EA /* STPPushProvisioningContext.m in Sources */, B68D52E622A739FF00D4E8BA /* STPSourceWeChatPayDetails.m in Sources */, 049E84D21A605DE0000B66CD /* StripeError.m in Sources */, 04B31DD71D08E6E200EF1631 /* STPCustomer.m in Sources */, C19226A01EBA9A0B00BED563 /* STPCustomerContext.m in Sources */, B690DDF5222F0211000B902D /* STPPaymentMethodAddress.m in Sources */, 049952D81BCF14990088C703 /* STPAPIRequest.m in Sources */, + 0413CB25233FECD5006429EA /* STPPushProvisioningDetailsParams.m in Sources */, 04F94DBE1D229F98004FC826 /* UITableViewCell+Stripe_Borders.m in Sources */, 0426B9791CEBD001006AC8DD /* UINavigationBar+Stripe_Theme.m in Sources */, C192268A1EBA228900BED563 /* STPTelemetryClient.m in Sources */, @@ -4622,6 +4666,7 @@ C1080F4A1CBECF7B007B2D89 /* STPAddress.m in Sources */, 04B31DE81D09D25F00EF1631 /* STPPaymentOptionsInternalViewController.m in Sources */, F1D3A25C1EB014BD0095BFA9 /* UIImage+Stripe.m in Sources */, + 0413CB30233FECD5006429EA /* STPAPIClient+PushProvisioning.m in Sources */, 31F5A51122F0EFDC0033663B /* STPPaymentMethodFPXParams.m in Sources */, B613DD3322C536C900C7603F /* STPSetupIntent.m in Sources */, F1DEB8921E2052150066B8E8 /* STPCoreScrollViewController.m in Sources */, @@ -4629,6 +4674,7 @@ 0438EF2F1B7416BB00D506CC /* STPFormTextField.m in Sources */, 045D71101CEEE30500F6CD65 /* STPAspects.m in Sources */, F152321D1EA92FC100D65C67 /* STPRedirectContext.m in Sources */, + 0413CB24233FECD5006429EA /* STPPushProvisioningDetailsParams.m in Sources */, B32B176020F6D2C4000D6EF8 /* STPGenericStripeObject.m in Sources */, B621F055223454E9002141B7 /* STPPaymentMethodCardWallet.m in Sources */, 04B31E011D131D9000EF1631 /* STPPaymentCardTextFieldCell.m in Sources */, @@ -4704,6 +4750,7 @@ F148ABC81D5D334B0014FD92 /* STPLocalizationUtils.m in Sources */, 04A4C38B1C4F25F900B3B290 /* NSArray+Stripe.m in Sources */, 3691EB722119111A008C49E1 /* STPCardValidator+Private.m in Sources */, + 0413CB22233FECD5006429EA /* STPPushProvisioningContext.m in Sources */, F19491E41E60DD72001E1FC2 /* STPSourceSEPADebitDetails.m in Sources */, 04A4C38F1C4F25F900B3B290 /* UIViewController+Stripe_ParentViewController.m in Sources */, 31B9609222FE128C00DC6FD9 /* STPBankSelectionViewController.m in Sources */, @@ -4737,6 +4784,7 @@ 3635C33422B03E00004298B8 /* STPEmptyStripeResponse.m in Sources */, 0451CC461C49AE1C003B2CA6 /* STPPaymentResult.m in Sources */, 04E39F551CECF7A100AF3B96 /* STPPaymentOptionTuple.m in Sources */, + 0413CB26233FECD5006429EA /* STPPushProvisioningDetails.m in Sources */, C11810961CC6C4700022FB55 /* PKPaymentAuthorizationViewController+Stripe_Blocks.m in Sources */, 0439B9891C454F97005A1ED5 /* STPPaymentOptionsViewController.m in Sources */, 04A488441CA3580700506E53 /* UINavigationController+Stripe_Completion.m in Sources */, diff --git a/Stripe/STPAPIClient+PushProvisioning.m b/Stripe/STPAPIClient+PushProvisioning.m index 4fe43e5a9fc..3fba70671e8 100644 --- a/Stripe/STPAPIClient+PushProvisioning.m +++ b/Stripe/STPAPIClient+PushProvisioning.m @@ -21,8 +21,8 @@ - (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsPar [base64Certificates addObject:base64Certificate]; } - NSString *nonceHexString = [self hexadecimalStringForData:params.nonce]; - NSString *nonceSignatureHexString = [self hexadecimalStringForData:params.nonceSignature]; + NSString *nonceHexString = [self.class hexadecimalStringForData:params.nonce]; + NSString *nonceSignatureHexString = [self.class hexadecimalStringForData:params.nonceSignature]; NSDictionary *parameters = @{ @"ios": @{ @@ -41,7 +41,7 @@ - (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsPar }]; } -- (NSString *)hexadecimalStringForData:(NSData *)data { ++ (NSString *)hexadecimalStringForData:(NSData *)data { /* Returns hexadecimal string of NSData. Empty string if data is empty. */ const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; diff --git a/Stripe/STPPushProvisioningContext.m b/Stripe/STPPushProvisioningContext.m index a84ea5542c2..7d8626afd9a 100644 --- a/Stripe/STPPushProvisioningContext.m +++ b/Stripe/STPPushProvisioningContext.m @@ -9,7 +9,7 @@ #import "STPPushProvisioningContext.h" #import "STPEphemeralKeyManager.h" #import "STPAPIClient+Private.h" -#import "STPAPIClient+PushProvisioning.m" +#import "STPAPIClient+PushProvisioning.h" #import "STPEphemeralKey.h" @interface STPPushProvisioningContext() From d80267add1671efedfa6e62dca10826b671db68d Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Sat, 28 Sep 2019 15:47:39 -0400 Subject: [PATCH 03/10] tests --- Stripe.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index 1cf87ec5617..b4fc4818611 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -299,6 +299,7 @@ 04E39F5C1CECFAFD00AF3B96 /* STPPaymentContext+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E39F5A1CECFAFD00AF3B96 /* STPPaymentContext+Private.h */; }; 04E39F6A1CED48D500AF3B96 /* UIBarButtonItem+Stripe.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E39F681CED48D500AF3B96 /* UIBarButtonItem+Stripe.h */; }; 04E39F6B1CED48D500AF3B96 /* UIBarButtonItem+Stripe.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E39F691CED48D500AF3B96 /* UIBarButtonItem+Stripe.m */; }; + 04E7D4BA233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E7D4B9233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m */; }; 04EBC7531B7533C300A0E6AE /* STPCardValidationState.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */; settings = {ATTRIBUTES = (Public, ); }; }; 04EBC7561B7533C300A0E6AE /* STPCardValidationState.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */; settings = {ATTRIBUTES = (Public, ); }; }; 04EBC7571B7533C300A0E6AE /* STPCardValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EBC7521B7533C300A0E6AE /* STPCardValidator.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1541,6 +1542,7 @@ 04E39F5A1CECFAFD00AF3B96 /* STPPaymentContext+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "STPPaymentContext+Private.h"; sourceTree = ""; }; 04E39F681CED48D500AF3B96 /* UIBarButtonItem+Stripe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIBarButtonItem+Stripe.h"; sourceTree = ""; }; 04E39F691CED48D500AF3B96 /* UIBarButtonItem+Stripe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIBarButtonItem+Stripe.m"; sourceTree = ""; }; + 04E7D4B9233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPushProvisioningDetailsFunctionalTest.m; sourceTree = ""; }; 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPCardValidationState.h; path = PublicHeaders/STPCardValidationState.h; sourceTree = ""; }; 04EBC7521B7533C300A0E6AE /* STPCardValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPCardValidator.h; path = PublicHeaders/STPCardValidator.h; sourceTree = ""; }; 04F213301BCEAB61001D6F22 /* STPFormEncodable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPFormEncodable.h; path = PublicHeaders/STPFormEncodable.h; sourceTree = ""; }; @@ -2660,6 +2662,7 @@ C1CFCB6F1ED5E11500BE45DF /* STPFileFunctionalTest.m */, B3BDCACE20EEF4640034F7F5 /* STPPaymentIntentFunctionalTest.m */, B600F3C2223088F900264403 /* STPPaymentMethodFunctionalTest.m */, + 04E7D4B9233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m */, C1CFCB711ED5E11500BE45DF /* STPPIIFunctionalTest.m */, C1D7B5241E36C70D002181F5 /* STPSourceFunctionalTest.m */, 0731329A2277AA200019CE3F /* STPPinManagementServiceFunctionalTest.m */, @@ -4474,6 +4477,7 @@ 04415C6C1A6605B5001225ED /* STPBankAccountTest.m in Sources */, B664D65322B813EC00E6354B /* STPThreeDSButtonCustomizationTest.m in Sources */, C19D09931EAEAE5E00A4AB3E /* STPTelemetryClientTest.m in Sources */, + 04E7D4BA233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m in Sources */, F152321B1EA92F9D00D65C67 /* STPRedirectContextTest.m in Sources */, B6B41F73223476B90020BA7F /* STPPaymentMethodCardWalletVisaCheckoutTest.m in Sources */, 04415C6D1A6605B5001225ED /* STPCardFunctionalTest.m in Sources */, From 3517b699f8d53b53e31e9def19e7c15637b87d2c Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Sun, 29 Sep 2019 02:25:41 -0400 Subject: [PATCH 04/10] STPFakeAddPaymentPassViewController --- Stripe.xcodeproj/project.pbxproj | 24 ++ Stripe/PKAddPaymentPassRequest+Stripe_Error.h | 17 ++ Stripe/PKAddPaymentPassRequest+Stripe_Error.m | 21 ++ .../STPFakeAddPaymentPassViewController.h | 27 +++ .../STPPushProvisioningDetails.h | 2 + Stripe/PublicHeaders/Stripe.h | 1 + Stripe/STPCategoryLoader.m | 1 + Stripe/STPFakeAddPaymentPassViewController.m | 213 ++++++++++++++++++ Stripe/STPPushProvisioningContext.m | 10 +- Stripe/STPPushProvisioningDetails.m | 5 + 10 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 Stripe/PKAddPaymentPassRequest+Stripe_Error.h create mode 100644 Stripe/PKAddPaymentPassRequest+Stripe_Error.m create mode 100644 Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h create mode 100644 Stripe/STPFakeAddPaymentPassViewController.m diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index b4fc4818611..1daf0ea7d1d 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -300,6 +300,14 @@ 04E39F6A1CED48D500AF3B96 /* UIBarButtonItem+Stripe.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E39F681CED48D500AF3B96 /* UIBarButtonItem+Stripe.h */; }; 04E39F6B1CED48D500AF3B96 /* UIBarButtonItem+Stripe.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E39F691CED48D500AF3B96 /* UIBarButtonItem+Stripe.m */; }; 04E7D4BA233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E7D4B9233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m */; }; + 04E7D4BD233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E7D4BB233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 04E7D4BE233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E7D4BB233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 04E7D4BF233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E7D4BC233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m */; }; + 04E7D4C0233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E7D4BC233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m */; }; + 04E7D4C32340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E7D4C12340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h */; }; + 04E7D4C42340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h in Headers */ = {isa = PBXBuildFile; fileRef = 04E7D4C12340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h */; }; + 04E7D4C52340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E7D4C22340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m */; }; + 04E7D4C62340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m in Sources */ = {isa = PBXBuildFile; fileRef = 04E7D4C22340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m */; }; 04EBC7531B7533C300A0E6AE /* STPCardValidationState.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */; settings = {ATTRIBUTES = (Public, ); }; }; 04EBC7561B7533C300A0E6AE /* STPCardValidationState.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */; settings = {ATTRIBUTES = (Public, ); }; }; 04EBC7571B7533C300A0E6AE /* STPCardValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EBC7521B7533C300A0E6AE /* STPCardValidator.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1543,6 +1551,10 @@ 04E39F681CED48D500AF3B96 /* UIBarButtonItem+Stripe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIBarButtonItem+Stripe.h"; sourceTree = ""; }; 04E39F691CED48D500AF3B96 /* UIBarButtonItem+Stripe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIBarButtonItem+Stripe.m"; sourceTree = ""; }; 04E7D4B9233FEFDF00FC8C02 /* STPPushProvisioningDetailsFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPushProvisioningDetailsFunctionalTest.m; sourceTree = ""; }; + 04E7D4BB233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPFakeAddPaymentPassViewController.h; path = PublicHeaders/STPFakeAddPaymentPassViewController.h; sourceTree = ""; }; + 04E7D4BC233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPFakeAddPaymentPassViewController.m; sourceTree = ""; }; + 04E7D4C12340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PKAddPaymentPassRequest+Stripe_Error.h"; sourceTree = ""; }; + 04E7D4C22340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "PKAddPaymentPassRequest+Stripe_Error.m"; sourceTree = ""; }; 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPCardValidationState.h; path = PublicHeaders/STPCardValidationState.h; sourceTree = ""; }; 04EBC7521B7533C300A0E6AE /* STPCardValidator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPCardValidator.h; path = PublicHeaders/STPCardValidator.h; sourceTree = ""; }; 04F213301BCEAB61001D6F22 /* STPFormEncodable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPFormEncodable.h; path = PublicHeaders/STPFormEncodable.h; sourceTree = ""; }; @@ -2854,6 +2866,8 @@ 04633B091CD44F6C009D4FB5 /* PKPayment+Stripe.m */, C11810931CC6C4700022FB55 /* PKPaymentAuthorizationViewController+Stripe_Blocks.h */, C11810941CC6C4700022FB55 /* PKPaymentAuthorizationViewController+Stripe_Blocks.m */, + 04E7D4C12340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h */, + 04E7D4C22340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m */, 04E39F681CED48D500AF3B96 /* UIBarButtonItem+Stripe.h */, 04E39F691CED48D500AF3B96 /* UIBarButtonItem+Stripe.m */, F1D3A2581EB014BD0095BFA9 /* UIImage+Stripe.h */, @@ -3260,6 +3274,8 @@ 31B9608F22FE128C00DC6FD9 /* STPBankSelectionViewController.m */, C15993261D8808490047950D /* STPShippingAddressViewController.h */, C159932C1D8808680047950D /* STPShippingAddressViewController.m */, + 04E7D4BB233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h */, + 04E7D4BC233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m */, ); name = "View Controllers"; sourceTree = ""; @@ -3355,6 +3371,7 @@ B6A46F7722FCDB81001991B2 /* STPPaymentIntentLastPaymentError.h in Headers */, 0439B9881C454F97005A1ED5 /* STPPaymentOptionsViewController.h in Headers */, 319A609D22E9186B00AACF66 /* STDSTransaction.h in Headers */, + 04E7D4BE233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h in Headers */, 3604007B22C18DAE004CF80B /* STPThreeDSTextFieldCustomization.h in Headers */, B6F16091223350640088C970 /* STPPaymentIntentAction.h in Headers */, F1A2F92D1EEB6A70006B0456 /* NSCharacterSet+Stripe.h in Headers */, @@ -3423,6 +3440,7 @@ B690DDF9222F0564000B902D /* STPPaymentMethodCard.h in Headers */, 3604007822C18DA1004CF80B /* STPThreeDSLabelCustomization.h in Headers */, C1BD9B2F1E3940A200CEE925 /* STPSourceRedirect.h in Headers */, + 04E7D4C42340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h in Headers */, B690DDF3222F0211000B902D /* STPPaymentMethodAddress.h in Headers */, B36C6D742193676600D17575 /* STPPaymentIntentSourceActionAuthorizeWithURL.h in Headers */, 8B429AD91EF9D4B500F95F34 /* STPBankAccountParams+Private.h in Headers */, @@ -3629,6 +3647,7 @@ 049A3FB21CC9FEFC00F57DE7 /* UIToolbar+Stripe_InputAccessory.h in Headers */, F1FA6F981E25970F00EB444D /* STPCoreTableViewController+Private.h in Headers */, F1DEB8901E2052150066B8E8 /* STPCoreScrollViewController.h in Headers */, + 04E7D4BD233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.h in Headers */, 04A488331CA34D3000506E53 /* STPEmailAddressValidator.h in Headers */, C192269C1EBA99F900BED563 /* STPCustomerContext.h in Headers */, 04A4C38D1C4F25F900B3B290 /* UIViewController+Stripe_ParentViewController.h in Headers */, @@ -3653,6 +3672,7 @@ 315CB8C422E7D96000E612A3 /* STDSButtonCustomization.h in Headers */, 315CB8C522E7D96000E612A3 /* STDSWarning.h in Headers */, 315CB8C622E7D96000E612A3 /* STDSSelectionCustomization.h in Headers */, + 04E7D4C32340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.h in Headers */, 315CB8C722E7D96000E612A3 /* STDSException.h in Headers */, 315CB8C822E7D96000E612A3 /* STDSTextFieldCustomization.h in Headers */, 315CB8C922E7D96000E612A3 /* STDSUICustomization.h in Headers */, @@ -4517,6 +4537,7 @@ 04F94DA91D229F32004FC826 /* STPPaymentOptionTuple.m in Sources */, C15608E01FE08F2E0032AE66 /* UIView+Stripe_SafeAreaBounds.m in Sources */, F1A2F92F1EEB6A70006B0456 /* NSCharacterSet+Stripe.m in Sources */, + 04E7D4C0233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m in Sources */, 36A734282121F8A700784615 /* STPCardValidator+Private.m in Sources */, B604CF2422C56E9B00A23CC4 /* STPIntentActionRedirectToURL.m in Sources */, F19491E51E60DD72001E1FC2 /* STPSourceSEPADebitDetails.m in Sources */, @@ -4645,6 +4666,7 @@ 04F94DBE1D229F98004FC826 /* UITableViewCell+Stripe_Borders.m in Sources */, 0426B9791CEBD001006AC8DD /* UINavigationBar+Stripe_Theme.m in Sources */, C192268A1EBA228900BED563 /* STPTelemetryClient.m in Sources */, + 04E7D4C62340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m in Sources */, 045D71231CEFA57000F6CD65 /* UIViewController+Stripe_Promises.m in Sources */, 04BC29A11CD8412000318357 /* STPPaymentContext.m in Sources */, 04CDE5C71BC20AF800548833 /* STPBankAccountParams.m in Sources */, @@ -4731,6 +4753,7 @@ 0426B9731CEAE3EB006AC8DD /* UITableViewCell+Stripe_Borders.m in Sources */, B664D67222B96A1300E6354B /* STPThreeDSTextFieldCustomization.m in Sources */, C1BD9B241E393FFE00CEE925 /* STPSourceReceiver.m in Sources */, + 04E7D4C52340717400FC8C02 /* PKAddPaymentPassRequest+Stripe_Error.m in Sources */, 04B31DD61D08E6E200EF1631 /* STPCustomer.m in Sources */, 367B46D722A0969000730BE0 /* STPThreeDSCustomizationSettings.m in Sources */, B69FEC3F222EE8FE00273A16 /* STPPaymentMethod.m in Sources */, @@ -4747,6 +4770,7 @@ 049880FE1CED5A2300EA4FFD /* STPPaymentConfiguration.m in Sources */, 046FE9A21CE55D1D00DA6A7B /* STPPaymentActivityIndicatorView.m in Sources */, 31B9609622FE20DF00DC6FD9 /* STPBankSelectionTableViewCell.m in Sources */, + 04E7D4BF233FF29100FC8C02 /* STPFakeAddPaymentPassViewController.m in Sources */, B621F061223465EE002141B7 /* STPPaymentMethodCardWalletVisaCheckout.m in Sources */, 045D71221CEFA57000F6CD65 /* UIViewController+Stripe_Promises.m in Sources */, C124A1721CCA968B007D42EE /* STPAnalyticsClient.m in Sources */, diff --git a/Stripe/PKAddPaymentPassRequest+Stripe_Error.h b/Stripe/PKAddPaymentPassRequest+Stripe_Error.h new file mode 100644 index 00000000000..4037c9709bd --- /dev/null +++ b/Stripe/PKAddPaymentPassRequest+Stripe_Error.h @@ -0,0 +1,17 @@ +// +// PKAddPaymentPassRequest+Stripe_Error.h +// Stripe +// +// Created by Jack Flintermann on 9/29/19. +// Copyright © 2019 Stripe, Inc. All rights reserved. +// + +#import + +// This is used to store an error on a PKAddPaymentPassRequest +// so that STPFakeAddPaymentPassViewController can inspect it for debugging. +@interface PKAddPaymentPassRequest (Stripe_Error) +@property (nonatomic) NSError *stp_error; +@end + +void linkPKAddPaymentPassRequestCategory(void); diff --git a/Stripe/PKAddPaymentPassRequest+Stripe_Error.m b/Stripe/PKAddPaymentPassRequest+Stripe_Error.m new file mode 100644 index 00000000000..3406e6da968 --- /dev/null +++ b/Stripe/PKAddPaymentPassRequest+Stripe_Error.m @@ -0,0 +1,21 @@ +// +// PKAddPaymentPassRequest+Stripe_Error.m +// Stripe +// +// Created by Jack Flintermann on 9/29/19. +// Copyright © 2019 Stripe, Inc. All rights reserved. +// + +#import "PKAddPaymentPassRequest+Stripe_Error.h" +#import + +@implementation PKAddPaymentPassRequest (Stripe_Error) +- (NSError *)stp_error { + return objc_getAssociatedObject(self, @selector(stp_error)); +} + +- (void)setStp_error:(NSError *)stp_error { + objc_setAssociatedObject(self, @selector(stp_error), stp_error, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} +@end + diff --git a/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h b/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h new file mode 100644 index 00000000000..90a8659f9dd --- /dev/null +++ b/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h @@ -0,0 +1,27 @@ +// +// STPFakeAddPaymentPassViewController.h +// Stripe +// +// Created by Jack Flintermann on 9/28/19. +// Copyright © 2019 Stripe, Inc. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface STPFakeAddPaymentPassViewController : UIViewController + ++ (BOOL)canAddPaymentPass; + +- (nullable instancetype)initWithRequestConfiguration:(PKAddPaymentPassRequestConfiguration *)configuration + delegate:(nullable id)delegate NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, weak, nullable) id delegate; + +@end + + + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetails.h b/Stripe/PublicHeaders/STPPushProvisioningDetails.h index b6bc3ef898f..99394d8bb45 100644 --- a/Stripe/PublicHeaders/STPPushProvisioningDetails.h +++ b/Stripe/PublicHeaders/STPPushProvisioningDetails.h @@ -14,11 +14,13 @@ NS_ASSUME_NONNULL_BEGIN @interface STPPushProvisioningDetails : NSObject @property (nonatomic, readonly) NSString *cardId; +@property (nonatomic, readonly) BOOL livemode; @property (nonatomic, readonly) NSData *encryptedPassData; @property (nonatomic, readonly) NSData *activationData; @property (nonatomic, readonly) NSData *ephemeralPublicKey; + (instancetype)detailsWithCardId:(NSString *)cardId + livemode:(BOOL)livemode encryptedPassData:(NSData *)encryptedPassData activationData:(NSData *)activationData ephemeralPublicKey:(NSData *)ephemeralPublicKey; diff --git a/Stripe/PublicHeaders/Stripe.h b/Stripe/PublicHeaders/Stripe.h index 716e9a6e8e1..e7041e78c55 100644 --- a/Stripe/PublicHeaders/Stripe.h +++ b/Stripe/PublicHeaders/Stripe.h @@ -37,6 +37,7 @@ #import "STPCustomer.h" #import "STPCustomerContext.h" #import "STPEphemeralKeyProvider.h" +#import "STPFakeAddPaymentPassViewController.h" #import "STPFile.h" #import "STPFormEncodable.h" #import "STPFPXBankBrand.h" diff --git a/Stripe/STPCategoryLoader.m b/Stripe/STPCategoryLoader.m index bd5d6f654c2..06fc95fb448 100644 --- a/Stripe/STPCategoryLoader.m +++ b/Stripe/STPCategoryLoader.m @@ -53,6 +53,7 @@ + (void)loadCategories { linkNSURLComponentsCategory(); linkPKPaymentAuthorizationViewControllerBlocksCategory(); linkPKPaymentCategory(); + linkPKAddPaymentPassRequestCategory(); linkSTPAPIClientApplePayCategory(); linkSTPCardValidatorPrivateCategory(); linkUIBarButtonItemCategory(); diff --git a/Stripe/STPFakeAddPaymentPassViewController.m b/Stripe/STPFakeAddPaymentPassViewController.m new file mode 100644 index 00000000000..0ff32c1e508 --- /dev/null +++ b/Stripe/STPFakeAddPaymentPassViewController.m @@ -0,0 +1,213 @@ +// +// STPFakeAddPaymentPassViewController.m +// Stripe +// +// Created by Jack Flintermann on 9/28/19. +// Copyright © 2019 Stripe, Inc. All rights reserved. +// + +#import "STPFakeAddPaymentPassViewController.h" +#import "PKAddPaymentPassRequest+Stripe_Error.h" +#import "StripeError.h" + +typedef NS_ENUM(NSUInteger, STPFakeAddPaymentPassViewControllerState) { + STPFakeAddPaymentPassViewControllerStateInitial, + STPFakeAddPaymentPassViewControllerStateLoading, + STPFakeAddPaymentPassViewControllerStateError, + STPFakeAddPaymentPassViewControllerStateSuccess, +}; + +@interface STPFakeAddPaymentPassViewController () +@property(nonatomic)PKAddPaymentPassRequestConfiguration *configuration; +@property(nonatomic)STPFakeAddPaymentPassViewControllerState state; +@property(nonatomic)UILabel *contentLabel; +@property(nonatomic)NSString *errorText; +@end + +@implementation STPFakeAddPaymentPassViewController + ++ (BOOL)canAddPaymentPass { + return YES; +} + +- (nullable instancetype)initWithRequestConfiguration:(PKAddPaymentPassRequestConfiguration *)configuration + delegate:(nullable id)delegate { + self = [super initWithNibName:nil bundle:nil]; + NSCParameterAssert(delegate); + if (self) { + _state = STPFakeAddPaymentPassViewControllerStateInitial; + _delegate = delegate; + _configuration = configuration; + if (!configuration.primaryAccountSuffix && !configuration.cardholderName) { + NSCAssert(NO, @"Your PKAddPaymentPassRequestConfiguration must provide either a cardholderName or a primaryAccountSuffix."); + } + } + return self; +} + +- (instancetype)initWithNibName:(__unused NSString *)nibNameOrNil bundle:(__unused NSBundle *)nibBundleOrNil { + return [self initWithRequestConfiguration:[PKAddPaymentPassRequestConfiguration new] delegate:nil]; +} + +- (instancetype)initWithCoder:(__unused NSCoder *)aDecoder { + return [self initWithRequestConfiguration:[PKAddPaymentPassRequestConfiguration new] delegate:nil]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor whiteColor]; + + UINavigationBar *navBar = [[UINavigationBar alloc] init]; + [self.view addSubview:navBar]; + navBar.translucent = NO; + navBar.backgroundColor = [UIColor whiteColor]; + navBar.items = @[self.navigationItem]; + navBar.translatesAutoresizingMaskIntoConstraints = NO; + [navBar.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES; + [navBar.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES; + if (@available(iOS 11.0, *)) { + [navBar.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor].active = YES; + } else { + [navBar.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + } + + UILabel *contentLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.contentLabel = contentLabel; + contentLabel.textAlignment = NSTextAlignmentCenter; + contentLabel.textColor = [UIColor blackColor]; + contentLabel.numberOfLines = 0; + contentLabel.font = [UIFont systemFontOfSize:18]; + contentLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:contentLabel]; + [contentLabel.topAnchor constraintEqualToAnchor:navBar.bottomAnchor].active = YES; + [contentLabel.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES; + [contentLabel.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES; + [contentLabel.heightAnchor constraintEqualToConstant:150].active = YES; + + NSMutableArray *pairs = [NSMutableArray array]; + if (self.configuration.cardholderName) { + [pairs addObject:@[@"Name", self.configuration.cardholderName]]; + } + if (self.configuration.primaryAccountSuffix) { + [pairs addObject:@[@"Card Number", [NSString stringWithFormat:@"···· %@", self.configuration.primaryAccountSuffix]]]; + } + NSMutableArray *rows = [NSMutableArray array]; + for (NSArray *pair in pairs) { + UILabel *left = [[UILabel alloc] init]; + left.text = pair[0]; + left.textAlignment = NSTextAlignmentLeft; + [left setFont:[UIFont boldSystemFontOfSize:16]]; + UILabel *right = [[UILabel alloc] init]; + right.text = pair[1]; + right.textAlignment = NSTextAlignmentLeft; + right.textColor = [UIColor lightGrayColor]; + UIStackView *row = [[UIStackView alloc] initWithArrangedSubviews:@[left, right]]; + row.axis = UILayoutConstraintAxisHorizontal; + row.distribution = UIStackViewDistributionFillEqually; + row.alignment = UIStackViewAlignmentFill; + row.translatesAutoresizingMaskIntoConstraints = NO; + [rows addObject:row]; + } + UIStackView *pairsTable = [[UIStackView alloc] initWithArrangedSubviews:rows]; + pairsTable.layoutMarginsRelativeArrangement = YES; + pairsTable.layoutMargins = UIEdgeInsetsMake(20, 20, 20, 20); + pairsTable.axis = UILayoutConstraintAxisVertical; + pairsTable.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:pairsTable]; + + [pairsTable.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES; + [pairsTable.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES; + [pairsTable.topAnchor constraintEqualToAnchor:contentLabel.bottomAnchor].active = YES; + [pairsTable.heightAnchor constraintEqualToConstant:(rows.count * 50)].active = YES; + [self setState:STPFakeAddPaymentPassViewControllerStateInitial]; +} + +- (void)setState:(STPFakeAddPaymentPassViewControllerState)state { + _state = state; + UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)]; + UIButton *nextButton = [UIButton buttonWithType:UIButtonTypeSystem]; + [nextButton addTarget:self action:@selector(next:) forControlEvents:UIControlEventTouchUpInside]; + UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + [indicatorView startAnimating]; + UIBarButtonItem *loadingItem = [[UIBarButtonItem alloc] initWithCustomView:indicatorView]; + [nextButton setTitle:@"Next" forState:UIControlStateNormal]; + UIBarButtonItem *nextItem = [[UIBarButtonItem alloc] initWithCustomView:nextButton]; + UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)]; + + switch (state) { + case STPFakeAddPaymentPassViewControllerStateInitial: + self.contentLabel.text = @"This class simulates the delegate methods that PKAddPaymentPassViewController will call in your app. Press next to continue."; + self.navigationItem.leftBarButtonItem = cancelItem; + self.navigationItem.rightBarButtonItem = nextItem; + break; + case STPFakeAddPaymentPassViewControllerStateLoading: + self.contentLabel.text = @"Fetching encrypted card details..."; + cancelItem.enabled = NO; + self.navigationItem.leftBarButtonItem = cancelItem; + self.navigationItem.rightBarButtonItem = loadingItem; + break; + case STPFakeAddPaymentPassViewControllerStateError: + self.contentLabel.text = [@"Error: " stringByAppendingString:self.errorText]; + doneItem.enabled = NO; + self.navigationItem.leftBarButtonItem = cancelItem; + self.navigationItem.rightBarButtonItem = doneItem; + break; + case STPFakeAddPaymentPassViewControllerStateSuccess: + self.contentLabel.text = @"Success! In production, your card would now have been added to your Apple Pay wallet. Your app's success callback will be triggered when the user presses 'Done'."; + cancelItem.enabled = NO; + self.navigationItem.leftBarButtonItem = cancelItem; + self.navigationItem.rightBarButtonItem = doneItem; + } +} + +- (void)cancel:(__unused id)sender { + [self.delegate addPaymentPassViewController:(PKAddPaymentPassViewController *)self didFinishAddingPaymentPass:nil error:[NSError errorWithDomain:PKPassKitErrorDomain code:PKAddPaymentPassErrorUserCancelled userInfo:nil]]; +} + +- (void)next:(__unused id)sender { + [self setState:STPFakeAddPaymentPassViewControllerStateLoading]; + NSArray *certificates = @[ + [@"cert1" dataUsingEncoding:NSUTF8StringEncoding], + [@"cert2" dataUsingEncoding:NSUTF8StringEncoding], + ]; + NSData *nonce = [@"nonce" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *nonceSignature = [@"nonceSignature" dataUsingEncoding:NSUTF8StringEncoding]; + NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 repeats:NO block:^(__unused NSTimer * _Nonnull _timer2) { + self.errorText = @"You exceeded the timeout of 10 seconds to call the request completion handler. Please check your PKAddPaymentPassViewControllerDelegate implementation, and make sure you are calling the `completionHandler` in `addPaymentPassViewController:generateRequestWithCertificateChain:nonce:nonceSignature:completionHandler`."; + [self setState:STPFakeAddPaymentPassViewControllerStateError]; + }]; + [self.delegate addPaymentPassViewController:(PKAddPaymentPassViewController *)self + generateRequestWithCertificateChain:certificates + nonce:nonce + nonceSignature:nonceSignature + completionHandler:^(PKAddPaymentPassRequest * _Nonnull request) { + if (self.state == STPFakeAddPaymentPassViewControllerStateLoading) { + [timer invalidate]; + NSString *contents; + if (request.encryptedPassData) { + contents = [[NSString alloc] initWithData:request.encryptedPassData encoding:NSUTF8StringEncoding]; + } + if (request.stp_error) { + NSString *error = request.stp_error.userInfo[STPErrorMessageKey]; + if (!error) { + error = request.stp_error.userInfo[NSLocalizedDescriptionKey]; + } + self.errorText = error; + [self setState:STPFakeAddPaymentPassViewControllerStateError]; + } + else if ([contents isEqualToString:@"TESTMODE_CONTENTS_VALUE"]){ + [self setState:STPFakeAddPaymentPassViewControllerStateSuccess]; + } else { + self.errorText = @"Your server response contained the wrong encrypted card details. Please ensure that you are not modifying the response from the Stripe API in any way, and that your request is in testmode."; + [self setState:STPFakeAddPaymentPassViewControllerStateError]; + } + } +}]; +} + +- (void)done:(__unused id)sender { + PKPaymentPass *pass = [PKPaymentPass new]; + [self.delegate addPaymentPassViewController:(PKAddPaymentPassViewController *)self didFinishAddingPaymentPass:pass error:nil]; +} + +@end diff --git a/Stripe/STPPushProvisioningContext.m b/Stripe/STPPushProvisioningContext.m index 7d8626afd9a..0c25df944d3 100644 --- a/Stripe/STPPushProvisioningContext.m +++ b/Stripe/STPPushProvisioningContext.m @@ -11,6 +11,7 @@ #import "STPAPIClient+Private.h" #import "STPAPIClient+PushProvisioning.h" #import "STPEphemeralKey.h" +#import "PKAddPaymentPassRequest+Stripe_Error.h" @interface STPPushProvisioningContext() @property (nonatomic, strong) STPEphemeralKeyManager *keyManager; @@ -47,14 +48,19 @@ + (PKAddPaymentPassRequestConfiguration *)requestConfigurationWithName:(NSString - (void)addPaymentPassViewController:(__unused PKAddPaymentPassViewController *)controller generateRequestWithCertificateChain:(NSArray *)certificates nonce:(NSData *)nonce nonceSignature:(NSData *)nonceSignature completionHandler:(void (^)(PKAddPaymentPassRequest *))handler { [self.keyManager getOrCreateKey:^(STPEphemeralKey * _Nullable ephemeralKey, NSError * _Nullable keyError) { if (keyError != nil) { - handler([PKAddPaymentPassRequest new]); + PKAddPaymentPassRequest *request = [PKAddPaymentPassRequest new]; + request.stp_error = keyError; + // handler, bizarrely, cannot take an NSError, but passing an empty PKAddPaymentPassRequest causes roughly equivalent behavior. + handler(request); return; } STPPushProvisioningDetailsParams *params = [STPPushProvisioningDetailsParams paramsWithCardId:ephemeralKey.issuingCardID certificates:certificates nonce:nonce nonceSignature:nonceSignature]; STPAPIClient *client = [STPAPIClient apiClientWithEphemeralKey:ephemeralKey]; [client retrievePushProvisioningDetailsWithParams:params completion:^(STPPushProvisioningDetails * _Nullable details, NSError * _Nullable error) { if (error != nil) { - handler([PKAddPaymentPassRequest new]); + PKAddPaymentPassRequest *request = [PKAddPaymentPassRequest new]; + request.stp_error = error; + handler(request); return; } PKAddPaymentPassRequest *request = [[PKAddPaymentPassRequest alloc] init]; diff --git a/Stripe/STPPushProvisioningDetails.m b/Stripe/STPPushProvisioningDetails.m index 8e53c60fffb..45a1f59b252 100644 --- a/Stripe/STPPushProvisioningDetails.m +++ b/Stripe/STPPushProvisioningDetails.m @@ -13,6 +13,7 @@ @interface STPPushProvisioningDetails () @property (nonatomic, readwrite) NSString *cardId; +@property (nonatomic, readwrite) BOOL livemode; @property (nonatomic, readwrite) NSData *encryptedPassData; @property (nonatomic, readwrite) NSData *activationData; @property (nonatomic, readwrite) NSData *ephemeralPublicKey; @@ -23,11 +24,13 @@ @interface STPPushProvisioningDetails () @implementation STPPushProvisioningDetails + (instancetype)detailsWithCardId:(NSString *)cardId + livemode:(BOOL)livemode encryptedPassData:(NSData *)encryptedPassData activationData:(NSData *)activationData ephemeralPublicKey:(NSData *)ephemeralPublicKey { STPPushProvisioningDetails *details = [[self alloc] init]; details.cardId = cardId; + details.livemode = livemode; details.encryptedPassData = encryptedPassData; details.activationData = activationData; details.ephemeralPublicKey = ephemeralPublicKey; @@ -44,6 +47,7 @@ + (instancetype)decodedObjectFromAPIResponse:(NSDictionary *)response { // required fields NSString *cardId = [dict stp_stringForKey:@"card"]; + BOOL livemode = [dict stp_boolForKey:@"livemode" or:NO]; NSString *encryptedPassString = [dict stp_stringForKey:@"contents"]; NSData *encryptedPassData = encryptedPassString ? [[NSData alloc] initWithBase64EncodedString:encryptedPassString options:0] : nil; @@ -58,6 +62,7 @@ + (instancetype)decodedObjectFromAPIResponse:(NSDictionary *)response { } STPPushProvisioningDetails *details = [self detailsWithCardId:cardId + livemode:livemode encryptedPassData:encryptedPassData activationData:activationData ephemeralPublicKey:ephemeralPublicKeyData]; From 8248bd8771b025eb905e275debd695b4ded89238 Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Sun, 29 Sep 2019 22:48:01 -0400 Subject: [PATCH 05/10] code changes --- .../STPFakeAddPaymentPassViewController.h | 9 +++-- .../STPPushProvisioningContext.h | 20 +++++++++++ .../STPPushProvisioningDetailsParams.h | 11 ++++++ Stripe/PublicHeaders/Stripe.h | 2 -- .../STPAPIClient+PushProvisioning.h | 0 Stripe/STPAPIClient+PushProvisioning.m | 32 ++--------------- Stripe/STPEphemeralKeyManager.m | 2 +- Stripe/STPFakeAddPaymentPassViewController.m | 4 +-- Stripe/STPPushProvisioningContext.m | 3 ++ .../STPPushProvisioningDetails.h | 0 Stripe/STPPushProvisioningDetailsParams.m | 34 +++++++++++++++++++ ...STPPushProvisioningDetailsFunctionalTest.m | 2 +- 12 files changed, 81 insertions(+), 38 deletions(-) rename Stripe/{PublicHeaders => }/STPAPIClient+PushProvisioning.h (100%) rename Stripe/{PublicHeaders => }/STPPushProvisioningDetails.h (100%) diff --git a/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h b/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h index 90a8659f9dd..16285db4491 100644 --- a/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h +++ b/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h @@ -11,17 +11,20 @@ NS_ASSUME_NONNULL_BEGIN +/*! +This class is a piece of fake UI that is intended to mimic `PKAddPaymentPassViewController`. That class is restricted to apps with a special entitlement from Apple, and as such can be difficult to build and test against. This class implements the same public API as `PKAddPaymentPassViewController`, and can be used to develop against the Stripe API in *testmode only*. (Obviously it will not actually place cards into the user's Apple Pay wallet either.) When it's time to go to production, you may simply replace all references to `STPFakeAddPaymentPassViewController` in your app with `PKAddPaymentPassViewController` and it will continue to function. For more information on developing against this API, please see https://stripe.com/docs/issuing/cards/digital-wallets . + */ @interface STPFakeAddPaymentPassViewController : UIViewController +/// @see PKAddPaymentPassViewController + (BOOL)canAddPaymentPass; +/// @see PKAddPaymentPassViewController - (nullable instancetype)initWithRequestConfiguration:(PKAddPaymentPassRequestConfiguration *)configuration delegate:(nullable id)delegate NS_DESIGNATED_INITIALIZER; - +/// @see PKAddPaymentPassViewController @property (nonatomic, weak, nullable) id delegate; @end - - NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/STPPushProvisioningContext.h b/Stripe/PublicHeaders/STPPushProvisioningContext.h index 7799dccf95b..71192f2b392 100644 --- a/Stripe/PublicHeaders/STPPushProvisioningContext.h +++ b/Stripe/PublicHeaders/STPPushProvisioningContext.h @@ -13,13 +13,33 @@ NS_ASSUME_NONNULL_BEGIN +/** + This class makes it easier to implement "Push Provisioning", the process by which an end-user can add a card to their Apple Pay wallet without having to type their number. This process is mediated by an Apple class called `PKAddPaymentPassViewController`; this class will help you implement that class' delegate methods. Note that this flow requires a special entitlement from Apple; for more information please see https://stripe.com/docs/issuing/cards/digital-wallets . + */ @interface STPPushProvisioningContext : NSObject +/** + This is a helper method to generate a PKAddPaymentPassRequestConfiguration that will work with + Stripe's Issuing APIs. Pass the returned configuration object to `PKAddPaymentPassViewController`'s `initWithRequestConfiguration:delegate:` initializer. + + @param name Your cardholder's name. Example: John Appleseed + @param description A localized description of your card's name. This will appear in Apple's UI as "{description} will be available in Wallet". Example: Platinum Rewards Card + @param last4 The last 4 of the card to be added to the user's Apple Pay wallet. Example: 4242 + @param brand The brand of the card. Example: `STPCardBrandVisa` + */ + (PKAddPaymentPassRequestConfiguration *)requestConfigurationWithName:(NSString *)name description:(nullable NSString *)description last4:(nullable NSString *)last4 brand:(STPCardBrand)brand; + +/*! + In order to retreive the encrypted payload that PKAddPaymentPassViewController expects, the Stripe SDK must talk to the Stripe API. As this requires privileged access, you must write a "key provider" that generates an Ephemeral Key on your backend and provides it to the SDK when requested. For more information, see https://stripe.com/docs/mobile/ios/standard#prepare-your-api + */ - (instancetype)initWithKeyProvider:(id)keyProvider; + +/*! + This method lines up with the method of the same name on `PKAddPaymentPassViewControllerDelegate`. You should implement that protocol in your own app, and when that method is called, call this method on your `STPPushProvisioningContext`. This in turn will first initiate a call to your `keyProvider` (see above) to obtain an Ephemeral Key, then make a call to the Stripe Issuing API to fetch an encrypted payload for the card in question, then return that payload to iOS. + */ - (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller generateRequestWithCertificateChain:(NSArray *)certificates nonce:(NSData *)nonce diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h index ac4e242f560..06cc6d1e1c1 100644 --- a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h +++ b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h @@ -10,12 +10,23 @@ NS_ASSUME_NONNULL_BEGIN +/*! + A helper class for turning the raw certificate array, nonce, and nonce signature emitted by PKAddPaymentPassViewController into a format that is understandable by the Stripe API. + If you are using STPPushProvisioningContext to implement your integration, you do not need to use this class. + */ @interface STPPushProvisioningDetailsParams : NSObject @property (nonatomic, readonly) NSString *cardId; @property (nonatomic, readonly) NSArray *certificates; @property (nonatomic, readonly) NSData *nonce; @property (nonatomic, readonly) NSData *nonceSignature; + +/// Implemented for convenience - the Stripe API expects the certificate chain as an array of base64-encoded strings. +@property (nonatomic, readonly) NSArray *certificatesBase64; +/// Implemented for convenience - the Stripe API expects the nonce as a hex-encoded string. +@property (nonatomic, readonly) NSString *nonceHex; +/// Implemented for convenience - the Stripe API expects the nonce signature as a hex-encoded string. +@property (nonatomic, readonly) NSString *nonceSignatureHex; +(instancetype)paramsWithCardId:(NSString *)cardId certificates:(NSArray*)certificates diff --git a/Stripe/PublicHeaders/Stripe.h b/Stripe/PublicHeaders/Stripe.h index e7041e78c55..be497a7b64a 100644 --- a/Stripe/PublicHeaders/Stripe.h +++ b/Stripe/PublicHeaders/Stripe.h @@ -78,9 +78,7 @@ #import "STPPaymentOptionsViewController.h" #import "STPPaymentResult.h" #import "STPPushProvisioningContext.h" -#import "STPPushProvisioningDetails.h" #import "STPPushProvisioningDetailsParams.h" -#import "STPAPIClient+PushProvisioning.h" #import "STPRedirectContext.h" #import "STPSetupIntent.h" #import "STPSetupIntentConfirmParams.h" diff --git a/Stripe/PublicHeaders/STPAPIClient+PushProvisioning.h b/Stripe/STPAPIClient+PushProvisioning.h similarity index 100% rename from Stripe/PublicHeaders/STPAPIClient+PushProvisioning.h rename to Stripe/STPAPIClient+PushProvisioning.h diff --git a/Stripe/STPAPIClient+PushProvisioning.m b/Stripe/STPAPIClient+PushProvisioning.m index 3fba70671e8..0d33a979c6b 100644 --- a/Stripe/STPAPIClient+PushProvisioning.m +++ b/Stripe/STPAPIClient+PushProvisioning.m @@ -15,20 +15,11 @@ - (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsPar completion:(STPPushProvisioningDetailsCompletionBlock)completion { NSString *endpoint = [NSString stringWithFormat:@"issuing/cards/%@/push_provisioning_details", params.cardId]; - NSMutableArray* base64Certificates = [NSMutableArray arrayWithCapacity:params.certificates.count]; - for (NSData *certificate in params.certificates) { - NSString *base64Certificate = [certificate base64EncodedStringWithOptions:kNilOptions]; - [base64Certificates addObject:base64Certificate]; - } - - NSString *nonceHexString = [self.class hexadecimalStringForData:params.nonce]; - NSString *nonceSignatureHexString = [self.class hexadecimalStringForData:params.nonceSignature]; - NSDictionary *parameters = @{ @"ios": @{ - @"certificates": base64Certificates, - @"nonce": nonceHexString, - @"nonce_signature": nonceSignatureHexString, + @"certificates": params.certificatesBase64, + @"nonce": params.nonceHex, + @"nonce_signature": params.nonceSignatureHex, }, }; @@ -40,22 +31,5 @@ - (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsPar completion(details, error); }]; } - -+ (NSString *)hexadecimalStringForData:(NSData *)data { - /* Returns hexadecimal string of NSData. Empty string if data is empty. */ - - const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; - - if (!dataBuffer) - return [NSString string]; - - NSUInteger dataLength = [data length]; - NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)]; - - for (NSUInteger i = 0; i < dataLength; ++i) - [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]]; - - return [NSString stringWithString:hexString]; -} @end diff --git a/Stripe/STPEphemeralKeyManager.m b/Stripe/STPEphemeralKeyManager.m index c0a393dd7f1..4ce35678562 100644 --- a/Stripe/STPEphemeralKeyManager.m +++ b/Stripe/STPEphemeralKeyManager.m @@ -89,7 +89,7 @@ - (void)_createKey { if ([self.keyProvider conformsToProtocol:@protocol(STPCustomerEphemeralKeyProvider)]) { NSAssert(NO, @"Could not parse the ephemeral key response following protocol STPCustomerEphemeralKeyProvider. Make sure your backend is sending the unmodified JSON of the ephemeral key to your app. For more info, see https://stripe.com/docs/mobile/ios/standard#prepare-your-api"); } else if ([self.keyProvider conformsToProtocol:@protocol(STPIssuingCardEphemeralKeyProvider)]) { - NSAssert(NO, @"Could not parse the ephemeral key response following protocol STPCustomerEphemeralKeyProvider. Make sure your backend is sending the unmodified JSON of the ephemeral key to your app. For more info, see https://stripe.com/docs/mobile/ios/standard#prepare-your-api"); + NSAssert(NO, @"Could not parse the ephemeral key response following protocol STPIssuingCardEphemeralKeyProvider. Make sure your backend is sending the unmodified JSON of the ephemeral key to your app. For more info, see https://stripe.com/docs/mobile/ios/standard#prepare-your-api"); } NSAssert(NO, @"Could not parse the ephemeral key response. Make sure your backend is sending the unmodified JSON of the ephemeral key to your app. For more info, see https://stripe.com/docs/mobile/ios/standard#prepare-your-api"); } diff --git a/Stripe/STPFakeAddPaymentPassViewController.m b/Stripe/STPFakeAddPaymentPassViewController.m index 0ff32c1e508..538b84c0c47 100644 --- a/Stripe/STPFakeAddPaymentPassViewController.m +++ b/Stripe/STPFakeAddPaymentPassViewController.m @@ -80,8 +80,8 @@ - (void)viewDidLoad { contentLabel.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:contentLabel]; [contentLabel.topAnchor constraintEqualToAnchor:navBar.bottomAnchor].active = YES; - [contentLabel.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES; - [contentLabel.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES; + [contentLabel.leftAnchor constraintEqualToAnchor:self.view.leftAnchor constant:10.0f].active = YES; + [contentLabel.rightAnchor constraintEqualToAnchor:self.view.rightAnchor constant:-10.0f].active = YES; [contentLabel.heightAnchor constraintEqualToConstant:150].active = YES; NSMutableArray *pairs = [NSMutableArray array]; diff --git a/Stripe/STPPushProvisioningContext.m b/Stripe/STPPushProvisioningContext.m index 0c25df944d3..6dcd0993c82 100644 --- a/Stripe/STPPushProvisioningContext.m +++ b/Stripe/STPPushProvisioningContext.m @@ -42,6 +42,9 @@ + (PKAddPaymentPassRequestConfiguration *)requestConfigurationWithName:(NSString if (brand == STPCardBrandVisa) { config.paymentNetwork = PKPaymentNetworkVisa; } + if (brand == STPCardBrandMasterCard) { + config.paymentNetwork = PKPaymentNetworkMasterCard; + } return config; } diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetails.h b/Stripe/STPPushProvisioningDetails.h similarity index 100% rename from Stripe/PublicHeaders/STPPushProvisioningDetails.h rename to Stripe/STPPushProvisioningDetails.h diff --git a/Stripe/STPPushProvisioningDetailsParams.m b/Stripe/STPPushProvisioningDetailsParams.m index e5fd9e3b721..8194fc4eae7 100644 --- a/Stripe/STPPushProvisioningDetailsParams.m +++ b/Stripe/STPPushProvisioningDetailsParams.m @@ -30,5 +30,39 @@ +(instancetype)paramsWithCardId:(NSString *)cardId params.nonceSignature = nonceSignature; return params; } + +- (NSArray *)certificatesBase64 { + NSMutableArray *base64Certificates = [NSMutableArray array]; + for (NSData *certificate in self.certificates) { + [base64Certificates addObject:[certificate base64EncodedStringWithOptions:kNilOptions]]; + } + return base64Certificates; +} + +- (NSString *)nonceHex { + return [self.class hexadecimalStringForData:self.nonce]; +} + +- (NSString *)nonceSignatureHex { + return [self.class hexadecimalStringForData:self.nonceSignature]; +} + +// Adapted from https://stackoverflow.com/questions/1305225/best-way-to-serialize-an-nsdata-into-a-hexadeximal-string ++ (NSString *)hexadecimalStringForData:(NSData *)data { + const unsigned char *dataBuffer = (const unsigned char *)[data bytes]; + + if (!dataBuffer) { + return [NSString string]; + } + + NSUInteger dataLength = [data length]; + NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)]; + + for (NSUInteger i = 0; i < dataLength; ++i) { + [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]]; + } + + return [NSString stringWithString:hexString]; +} @end diff --git a/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m b/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m index 783b5fcc046..9a1ce54edc7 100644 --- a/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m +++ b/Tests/Tests/STPPushProvisioningDetailsFunctionalTest.m @@ -17,7 +17,7 @@ @interface STPPushProvisioningDetailsFunctionalTest : STPNetworkStubbingTestCase @implementation STPPushProvisioningDetailsFunctionalTest - (void)setUp { - [super setUp]; + [super setUp]; } - (void)testRetrievePushProvisioningDetails { From 11575f5a565e7a68a3354547bed17fe943f9d357 Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Sun, 29 Sep 2019 22:58:13 -0400 Subject: [PATCH 06/10] testmode --- Stripe.xcodeproj/project.pbxproj | 20 ++++++++++---------- Stripe/STPFakeAddPaymentPassViewController.m | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index 1daf0ea7d1d..db18c2dfa7a 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -34,10 +34,10 @@ 0413CB29233FECD5006429EA /* STPPushProvisioningDetailsParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0413CB2A233FECD5006429EA /* STPPushProvisioningContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0413CB2B233FECD5006429EA /* STPPushProvisioningContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0413CB2C233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0413CB2D233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0413CB2E233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0413CB2F233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0413CB2C233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */; }; + 0413CB2D233FECD5006429EA /* STPAPIClient+PushProvisioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */; }; + 0413CB2E233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */; }; + 0413CB2F233FECD5006429EA /* STPPushProvisioningDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */; }; 0413CB30233FECD5006429EA /* STPAPIClient+PushProvisioning.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */; }; 0413CB31233FECD5006429EA /* STPAPIClient+PushProvisioning.m in Sources */ = {isa = PBXBuildFile; fileRef = 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */; }; 0426B96E1CEADC98006AC8DD /* STPColorUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0426B96C1CEADC98006AC8DD /* STPColorUtils.h */; }; @@ -1375,8 +1375,8 @@ 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPushProvisioningDetails.m; sourceTree = ""; }; 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPPushProvisioningDetailsParams.h; path = PublicHeaders/STPPushProvisioningDetailsParams.h; sourceTree = ""; }; 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPPushProvisioningContext.h; path = PublicHeaders/STPPushProvisioningContext.h; sourceTree = ""; }; - 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "STPAPIClient+PushProvisioning.h"; path = "PublicHeaders/STPAPIClient+PushProvisioning.h"; sourceTree = ""; }; - 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPPushProvisioningDetails.h; path = PublicHeaders/STPPushProvisioningDetails.h; sourceTree = ""; }; + 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "STPAPIClient+PushProvisioning.h"; sourceTree = ""; }; + 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPPushProvisioningDetails.h; sourceTree = ""; }; 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STPAPIClient+PushProvisioning.m"; sourceTree = ""; }; 0426B96C1CEADC98006AC8DD /* STPColorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPColorUtils.h; sourceTree = ""; }; 0426B96D1CEADC98006AC8DD /* STPColorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPColorUtils.m; sourceTree = ""; }; @@ -2925,12 +2925,8 @@ 04633B061CD44F47009D4FB5 /* STPAPIClient+ApplePay.h */, 04633B041CD44F1C009D4FB5 /* STPAPIClient+ApplePay.m */, C184107A1EC2539F00178149 /* STPEphemeralKeyProvider.h */, - 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */, - 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */, 0413CB1E233FECD4006429EA /* STPPushProvisioningContext.h */, 0413CB1A233FECD4006429EA /* STPPushProvisioningContext.m */, - 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */, - 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */, 0413CB1D233FECD4006429EA /* STPPushProvisioningDetailsParams.h */, 0413CB1B233FECD4006429EA /* STPPushProvisioningDetailsParams.m */, F152321F1EA92FCF00D65C67 /* STPRedirectContext.h */, @@ -3010,6 +3006,8 @@ 36239BAC2295EA23004FB1A5 /* STP3DS2AuthenticateResponse.h */, 36239BAD2295EA23004FB1A5 /* STP3DS2AuthenticateResponse.m */, 049952D11BCF13DD0088C703 /* STPAPIClient+Private.h */, + 0413CB1F233FECD4006429EA /* STPAPIClient+PushProvisioning.h */, + 0413CB21233FECD5006429EA /* STPAPIClient+PushProvisioning.m */, 049952CD1BCF13510088C703 /* STPAPIRequest.h */, 049952CE1BCF13510088C703 /* STPAPIRequest.m */, 8B429AD71EF9D4A300F95F34 /* STPBankAccountParams+Private.h */, @@ -3040,6 +3038,8 @@ B6B41F74223481BA0020BA7F /* STPPaymentMethodCardWallet+Private.h */, B665CE45228DE4C4008B546F /* STPPaymentMethodListDeserializer.h */, B665CE46228DE4C4008B546F /* STPPaymentMethodListDeserializer.m */, + 0413CB20233FECD5006429EA /* STPPushProvisioningDetails.h */, + 0413CB1C233FECD4006429EA /* STPPushProvisioningDetails.m */, B32B176420F80442000D6EF8 /* STPRedirectContext+Private.h */, B640DB1622C69A8E003C8810 /* STPSetupIntent+Private.h */, C1C1012C1E57A26F00C7BFAE /* STPSource+Private.h */, diff --git a/Stripe/STPFakeAddPaymentPassViewController.m b/Stripe/STPFakeAddPaymentPassViewController.m index 538b84c0c47..4fddb3740d6 100644 --- a/Stripe/STPFakeAddPaymentPassViewController.m +++ b/Stripe/STPFakeAddPaymentPassViewController.m @@ -195,7 +195,8 @@ - (void)next:(__unused id)sender { self.errorText = error; [self setState:STPFakeAddPaymentPassViewControllerStateError]; } - else if ([contents isEqualToString:@"TESTMODE_CONTENTS_VALUE"]){ + // This specific string is returned by the Stripe API in testmode. + else if ([contents isEqualToString:@"TESTMODE_CONTENTS"]){ [self setState:STPFakeAddPaymentPassViewControllerStateSuccess]; } else { self.errorText = @"Your server response contained the wrong encrypted card details. Please ensure that you are not modifying the response from the Stripe API in any way, and that your request is in testmode."; From 4ec195beaa63f7983e08589cbee5681be3ad18fc Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Mon, 30 Sep 2019 11:11:07 -0400 Subject: [PATCH 07/10] fix category linker --- Stripe/PKAddPaymentPassRequest+Stripe_Error.m | 1 + Stripe/STPAPIClient+PushProvisioning.h | 9 +++++++++ Stripe/STPAPIClient+PushProvisioning.m | 2 ++ Stripe/STPCategoryLoader.m | 3 +++ 4 files changed, 15 insertions(+) diff --git a/Stripe/PKAddPaymentPassRequest+Stripe_Error.m b/Stripe/PKAddPaymentPassRequest+Stripe_Error.m index 3406e6da968..2e160c44629 100644 --- a/Stripe/PKAddPaymentPassRequest+Stripe_Error.m +++ b/Stripe/PKAddPaymentPassRequest+Stripe_Error.m @@ -19,3 +19,4 @@ - (void)setStp_error:(NSError *)stp_error { } @end +void linkPKAddPaymentPassRequestCategory(void){} diff --git a/Stripe/STPAPIClient+PushProvisioning.h b/Stripe/STPAPIClient+PushProvisioning.h index a0bc7ac1fe8..58d05096ab2 100644 --- a/Stripe/STPAPIClient+PushProvisioning.h +++ b/Stripe/STPAPIClient+PushProvisioning.h @@ -22,3 +22,12 @@ typedef void (^STPPushProvisioningDetailsCompletionBlock)(STPPushProvisioningDet @end NS_ASSUME_NONNULL_END + +/** + This function should not be called directly. + + It is used by the SDK when it is built as a static library to force the + compiler to link in category methods regardless of the integrating + app's compiler flags. + */ +void linkSTPAPIClientPushProvisioningCategory(void); diff --git a/Stripe/STPAPIClient+PushProvisioning.m b/Stripe/STPAPIClient+PushProvisioning.m index 0d33a979c6b..571b996677d 100644 --- a/Stripe/STPAPIClient+PushProvisioning.m +++ b/Stripe/STPAPIClient+PushProvisioning.m @@ -33,3 +33,5 @@ - (void)retrievePushProvisioningDetailsWithParams:(STPPushProvisioningDetailsPar } @end + +void linkSTPAPIClientPushProvisioningCategory(void){} diff --git a/Stripe/STPCategoryLoader.m b/Stripe/STPCategoryLoader.m index 06fc95fb448..5e952b7e2aa 100644 --- a/Stripe/STPCategoryLoader.m +++ b/Stripe/STPCategoryLoader.m @@ -21,7 +21,9 @@ #import "NSURLComponents+Stripe.h" #import "PKPayment+Stripe.h" #import "PKPaymentAuthorizationViewController+Stripe_Blocks.h" +#import "PKAddPaymentPassRequest+Stripe_Error.h" #import "STPAPIClient+ApplePay.h" +#import "STPAPIClient+PushProvisioning.h" #import "STPAspects.h" #import "STPCardValidator+Private.h" #import "StripeError.h" @@ -55,6 +57,7 @@ + (void)loadCategories { linkPKPaymentCategory(); linkPKAddPaymentPassRequestCategory(); linkSTPAPIClientApplePayCategory(); + linkSTPAPIClientPushProvisioningCategory(); linkSTPCardValidatorPrivateCategory(); linkUIBarButtonItemCategory(); linkUIImageCategory(); From f58400c5d7be849563041efee58fa6081fe5fd86 Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Mon, 30 Sep 2019 23:17:27 -0400 Subject: [PATCH 08/10] build warnings --- .../STPFakeAddPaymentPassViewController.h | 2 +- .../STPPushProvisioningContext.h | 4 ++-- .../STPPushProvisioningDetailsParams.h | 2 +- Stripe/STPFakeAddPaymentPassViewController.m | 22 ++++++++++--------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h b/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h index 16285db4491..bbc7925d551 100644 --- a/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h +++ b/Stripe/PublicHeaders/STPFakeAddPaymentPassViewController.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN -/*! +/** This class is a piece of fake UI that is intended to mimic `PKAddPaymentPassViewController`. That class is restricted to apps with a special entitlement from Apple, and as such can be difficult to build and test against. This class implements the same public API as `PKAddPaymentPassViewController`, and can be used to develop against the Stripe API in *testmode only*. (Obviously it will not actually place cards into the user's Apple Pay wallet either.) When it's time to go to production, you may simply replace all references to `STPFakeAddPaymentPassViewController` in your app with `PKAddPaymentPassViewController` and it will continue to function. For more information on developing against this API, please see https://stripe.com/docs/issuing/cards/digital-wallets . */ @interface STPFakeAddPaymentPassViewController : UIViewController diff --git a/Stripe/PublicHeaders/STPPushProvisioningContext.h b/Stripe/PublicHeaders/STPPushProvisioningContext.h index 71192f2b392..f84b7d10124 100644 --- a/Stripe/PublicHeaders/STPPushProvisioningContext.h +++ b/Stripe/PublicHeaders/STPPushProvisioningContext.h @@ -32,12 +32,12 @@ NS_ASSUME_NONNULL_BEGIN last4:(nullable NSString *)last4 brand:(STPCardBrand)brand; -/*! +/** In order to retreive the encrypted payload that PKAddPaymentPassViewController expects, the Stripe SDK must talk to the Stripe API. As this requires privileged access, you must write a "key provider" that generates an Ephemeral Key on your backend and provides it to the SDK when requested. For more information, see https://stripe.com/docs/mobile/ios/standard#prepare-your-api */ - (instancetype)initWithKeyProvider:(id)keyProvider; -/*! +/** This method lines up with the method of the same name on `PKAddPaymentPassViewControllerDelegate`. You should implement that protocol in your own app, and when that method is called, call this method on your `STPPushProvisioningContext`. This in turn will first initiate a call to your `keyProvider` (see above) to obtain an Ephemeral Key, then make a call to the Stripe Issuing API to fetch an encrypted payload for the card in question, then return that payload to iOS. */ - (void)addPaymentPassViewController:(PKAddPaymentPassViewController *)controller diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h index 06cc6d1e1c1..bfa19f953ea 100644 --- a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h +++ b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN -/*! +/** A helper class for turning the raw certificate array, nonce, and nonce signature emitted by PKAddPaymentPassViewController into a format that is understandable by the Stripe API. If you are using STPPushProvisioningContext to implement your integration, you do not need to use this class. */ diff --git a/Stripe/STPFakeAddPaymentPassViewController.m b/Stripe/STPFakeAddPaymentPassViewController.m index 4fddb3740d6..1e31aaaa30a 100644 --- a/Stripe/STPFakeAddPaymentPassViewController.m +++ b/Stripe/STPFakeAddPaymentPassViewController.m @@ -130,30 +130,30 @@ - (void)setState:(STPFakeAddPaymentPassViewControllerState)state { UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; [indicatorView startAnimating]; UIBarButtonItem *loadingItem = [[UIBarButtonItem alloc] initWithCustomView:indicatorView]; - [nextButton setTitle:@"Next" forState:UIControlStateNormal]; + [nextButton setTitle:STPNonLocalizedString(@"Next") forState:UIControlStateNormal]; UIBarButtonItem *nextItem = [[UIBarButtonItem alloc] initWithCustomView:nextButton]; UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)]; switch (state) { case STPFakeAddPaymentPassViewControllerStateInitial: - self.contentLabel.text = @"This class simulates the delegate methods that PKAddPaymentPassViewController will call in your app. Press next to continue."; + self.contentLabel.text = STPNonLocalizedString(@"This class simulates the delegate methods that PKAddPaymentPassViewController will call in your app. Press next to continue."); self.navigationItem.leftBarButtonItem = cancelItem; self.navigationItem.rightBarButtonItem = nextItem; break; case STPFakeAddPaymentPassViewControllerStateLoading: - self.contentLabel.text = @"Fetching encrypted card details..."; + self.contentLabel.text = STPNonLocalizedString(@"Fetching encrypted card details..."); cancelItem.enabled = NO; self.navigationItem.leftBarButtonItem = cancelItem; self.navigationItem.rightBarButtonItem = loadingItem; break; case STPFakeAddPaymentPassViewControllerStateError: - self.contentLabel.text = [@"Error: " stringByAppendingString:self.errorText]; + self.contentLabel.text = STPNonLocalizedString([@"Error: " stringByAppendingString:self.errorText]); doneItem.enabled = NO; self.navigationItem.leftBarButtonItem = cancelItem; self.navigationItem.rightBarButtonItem = doneItem; break; case STPFakeAddPaymentPassViewControllerStateSuccess: - self.contentLabel.text = @"Success! In production, your card would now have been added to your Apple Pay wallet. Your app's success callback will be triggered when the user presses 'Done'."; + self.contentLabel.text = STPNonLocalizedString(@"Success! In production, your card would now have been added to your Apple Pay wallet. Your app's success callback will be triggered when the user presses 'Done'."); cancelItem.enabled = NO; self.navigationItem.leftBarButtonItem = cancelItem; self.navigationItem.rightBarButtonItem = doneItem; @@ -172,17 +172,19 @@ - (void)next:(__unused id)sender { ]; NSData *nonce = [@"nonce" dataUsingEncoding:NSUTF8StringEncoding]; NSData *nonceSignature = [@"nonceSignature" dataUsingEncoding:NSUTF8StringEncoding]; - NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 repeats:NO block:^(__unused NSTimer * _Nonnull _timer2) { - self.errorText = @"You exceeded the timeout of 10 seconds to call the request completion handler. Please check your PKAddPaymentPassViewControllerDelegate implementation, and make sure you are calling the `completionHandler` in `addPaymentPassViewController:generateRequestWithCertificateChain:nonce:nonceSignature:completionHandler`."; - [self setState:STPFakeAddPaymentPassViewControllerStateError]; - }]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + if (self.state == STPFakeAddPaymentPassViewControllerStateLoading) { + self.errorText = @"You exceeded the timeout of 10 seconds to call the request completion handler. Please check your PKAddPaymentPassViewControllerDelegate implementation, and make sure you are calling the `completionHandler` in `addPaymentPassViewController:generateRequestWithCertificateChain:nonce:nonceSignature:completionHandler`."; + [self setState:STPFakeAddPaymentPassViewControllerStateError]; + } + }); [self.delegate addPaymentPassViewController:(PKAddPaymentPassViewController *)self generateRequestWithCertificateChain:certificates nonce:nonce nonceSignature:nonceSignature completionHandler:^(PKAddPaymentPassRequest * _Nonnull request) { if (self.state == STPFakeAddPaymentPassViewControllerStateLoading) { - [timer invalidate]; NSString *contents; if (request.encryptedPassData) { contents = [[NSString alloc] initWithData:request.encryptedPassData encoding:NSUTF8StringEncoding]; From c308eeed8b9b40b46a07d95ae7e2d55a9bfd8d49 Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Thu, 3 Oct 2019 10:19:40 -0400 Subject: [PATCH 09/10] compile error --- Stripe/STPFakeAddPaymentPassViewController.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Stripe/STPFakeAddPaymentPassViewController.m b/Stripe/STPFakeAddPaymentPassViewController.m index 1e31aaaa30a..7de0d2030be 100644 --- a/Stripe/STPFakeAddPaymentPassViewController.m +++ b/Stripe/STPFakeAddPaymentPassViewController.m @@ -9,6 +9,7 @@ #import "STPFakeAddPaymentPassViewController.h" #import "PKAddPaymentPassRequest+Stripe_Error.h" #import "StripeError.h" +#import "STPLocalizationUtils.h" typedef NS_ENUM(NSUInteger, STPFakeAddPaymentPassViewControllerState) { STPFakeAddPaymentPassViewControllerStateInitial, From 827a4b9eeb1f129e1b3b4fcfd46f486dd55cdc35 Mon Sep 17 00:00:00 2001 From: Jack Flintermann Date: Mon, 14 Oct 2019 12:27:12 -0400 Subject: [PATCH 10/10] docs --- Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h index bfa19f953ea..fc2b13efae0 100644 --- a/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h +++ b/Stripe/PublicHeaders/STPPushProvisioningDetailsParams.h @@ -16,9 +16,13 @@ NS_ASSUME_NONNULL_BEGIN */ @interface STPPushProvisioningDetailsParams : NSObject +/// The Stripe ID of the Issuing card object to retrieve details for. @property (nonatomic, readonly) NSString *cardId; +/// An array of certificates that should be used to encrypt the card details. @property (nonatomic, readonly) NSArray *certificates; +/// A nonce that should be used during the encryption of the card details. @property (nonatomic, readonly) NSData *nonce; +/// A nonce signature that should be used during the encryption of the card details. @property (nonatomic, readonly) NSData *nonceSignature; /// Implemented for convenience - the Stripe API expects the certificate chain as an array of base64-encoded strings. @@ -28,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN /// Implemented for convenience - the Stripe API expects the nonce signature as a hex-encoded string. @property (nonatomic, readonly) NSString *nonceSignatureHex; +/// Instantiates a new params object with the provided attributes. +(instancetype)paramsWithCardId:(NSString *)cardId certificates:(NSArray*)certificates nonce:(NSData *)nonce