From 1fe23ea3ba2232bd9120712dfd6f540ed0ce7afa Mon Sep 17 00:00:00 2001 From: David Estes Date: Thu, 20 Feb 2020 11:01:01 -0800 Subject: [PATCH 1/2] Add support for 16 digit Diners Club cards --- Stripe/STPBINRange.m | 4 ++-- Stripe/STPCardValidator+Private.h | 1 + Stripe/STPCardValidator+Private.m | 13 +++++++++++-- Stripe/STPFormTextField.m | 3 +-- Stripe/STPPaymentCardTextField.m | 2 +- Stripe/STPPaymentCardTextFieldViewModel.m | 2 +- Tests/Tests/STPCardValidatorTest.m | 3 ++- 7 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Stripe/STPBINRange.m b/Stripe/STPBINRange.m index 39c3a06c1fd..5890f1b8f75 100644 --- a/Stripe/STPBINRange.m +++ b/Stripe/STPBINRange.m @@ -38,9 +38,9 @@ @implementation STPBINRange @[@"37", @"37", @15, @(STPCardBrandAmex)], // Diners Club - @[@"30", @"30", @14, @(STPCardBrandDinersClub)], + @[@"30", @"30", @16, @(STPCardBrandDinersClub)], @[@"36", @"36", @14, @(STPCardBrandDinersClub)], - @[@"38", @"39", @14, @(STPCardBrandDinersClub)], + @[@"38", @"39", @16, @(STPCardBrandDinersClub)], // Discover @[@"60", @"60", @16, @(STPCardBrandDiscover)], diff --git a/Stripe/STPCardValidator+Private.h b/Stripe/STPCardValidator+Private.h index e06f919c7b1..04ef1252b60 100644 --- a/Stripe/STPCardValidator+Private.h +++ b/Stripe/STPCardValidator+Private.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @interface STPCardValidator (Private) + (NSArray *)cardNumberFormatForBrand:(STPCardBrand)brand; ++ (NSArray *)cardNumberFormatForCardNumber:(NSString *)cardNumber; @end diff --git a/Stripe/STPCardValidator+Private.m b/Stripe/STPCardValidator+Private.m index 3f82477260c..5552b6a7637 100644 --- a/Stripe/STPCardValidator+Private.m +++ b/Stripe/STPCardValidator+Private.m @@ -7,6 +7,7 @@ // #import "STPCardValidator+Private.h" +#import "STPBINRange.h" NS_ASSUME_NONNULL_BEGIN @@ -17,13 +18,21 @@ @implementation STPCardValidator (Private) switch (brand) { case STPCardBrandAmex: return @[@4, @6, @5]; - case STPCardBrandDinersClub: - return @[@4, @6, @4]; default: return @[@4, @4, @4, @4]; } } ++ (NSArray *)cardNumberFormatForCardNumber:(NSString *)cardNumber +{ + STPBINRange *binRange = [STPBINRange mostSpecificBINRangeForNumber:cardNumber]; + if (binRange.brand == STPCardBrandDinersClub && binRange.length == 14) { + return @[@4, @6, @4]; + } + + return [self cardNumberFormatForBrand:binRange.brand]; +} + @end NS_ASSUME_NONNULL_END diff --git a/Stripe/STPFormTextField.m b/Stripe/STPFormTextField.m index 055d13e30d5..c2a525c8a8a 100644 --- a/Stripe/STPFormTextField.m +++ b/Stripe/STPFormTextField.m @@ -132,8 +132,7 @@ - (void)setAutoFormattingBehavior:(STPFormTextFieldAutoFormattingBehavior)autoFo return [inputString copy]; } NSMutableAttributedString *attributedString = [inputString mutableCopy]; - STPCardBrand currentBrand = [STPCardValidator brandForNumber:attributedString.string]; - NSArray *cardNumberFormat = [STPCardValidator cardNumberFormatForBrand:currentBrand]; + NSArray *cardNumberFormat = [STPCardValidator cardNumberFormatForCardNumber:attributedString.string]; NSUInteger index = 0; for (NSNumber *segmentLength in cardNumberFormat) { diff --git a/Stripe/STPPaymentCardTextField.m b/Stripe/STPPaymentCardTextField.m index ef059077425..8ce2249778a 100644 --- a/Stripe/STPPaymentCardTextField.m +++ b/Stripe/STPPaymentCardTextField.m @@ -746,7 +746,7 @@ - (CGFloat)numberFieldCompressedWidth { } STPCardBrand currentBrand = [STPCardValidator brandForNumber:cardNumber]; - NSArray *sortedCardNumberFormat = [[STPCardValidator cardNumberFormatForBrand:currentBrand] sortedArrayUsingSelector:@selector(unsignedIntegerValue)]; + NSArray *sortedCardNumberFormat = [[STPCardValidator cardNumberFormatForCardNumber:cardNumber] sortedArrayUsingSelector:@selector(unsignedIntegerValue)]; NSUInteger fragmentLength = [STPCardValidator fragmentLengthForCardBrand:currentBrand]; NSUInteger maxLength = MAX([[sortedCardNumberFormat lastObject] unsignedIntegerValue], fragmentLength); diff --git a/Stripe/STPPaymentCardTextFieldViewModel.m b/Stripe/STPPaymentCardTextFieldViewModel.m index 197a0d5c9a5..27184c265dd 100644 --- a/Stripe/STPPaymentCardTextFieldViewModel.m +++ b/Stripe/STPPaymentCardTextFieldViewModel.m @@ -38,7 +38,7 @@ - (NSString *)compressedCardNumber { } } else { // use the card number format - NSArray *cardNumberFormat = [STPCardValidator cardNumberFormatForBrand:currentBrand]; + NSArray *cardNumberFormat = [STPCardValidator cardNumberFormatForCardNumber:cardNumber]; NSUInteger index = 0; for (NSNumber *segment in cardNumberFormat) { diff --git a/Tests/Tests/STPCardValidatorTest.m b/Tests/Tests/STPCardValidatorTest.m index 5216450efc6..bc01c17e02d 100644 --- a/Tests/Tests/STPCardValidatorTest.m +++ b/Tests/Tests/STPCardValidatorTest.m @@ -46,6 +46,7 @@ + (NSArray *)cardData { @[@(STPCardBrandDiscover), @"6011000990139424", @(STPCardValidationStateValid)], @[@(STPCardBrandDinersClub), @"30569309025904", @(STPCardValidationStateValid)], @[@(STPCardBrandDinersClub), @"38520000023237", @(STPCardValidationStateValid)], + @[@(STPCardBrandDinersClub), @"3056930009020004", @(STPCardValidationStateValid)], @[@(STPCardBrandJCB), @"3530111333300000", @(STPCardValidationStateValid)], @[@(STPCardBrandJCB), @"3566002020360505", @(STPCardValidationStateValid)], @[@(STPCardBrandUnknown), @"1234567812345678", @(STPCardValidationStateInvalid)], @@ -132,7 +133,7 @@ - (void)testLengthsForCardBrand { @[@(STPCardBrandMasterCard), @[@16]], @[@(STPCardBrandAmex), @[@15]], @[@(STPCardBrandDiscover), @[@16]], - @[@(STPCardBrandDinersClub), @[@14]], + @[@(STPCardBrandDinersClub), @[@14, @16]], @[@(STPCardBrandJCB), @[@16]], @[@(STPCardBrandUnionPay), @[@16]], @[@(STPCardBrandUnknown), @[@16]], From 837bfcfdec3444fce1cff9ba9ad339a35f7fd87c Mon Sep 17 00:00:00 2001 From: David Estes Date: Thu, 20 Feb 2020 15:59:02 -0800 Subject: [PATCH 2/2] Fix tests --- Tests/Tests/STPCardValidatorTest.m | 3 +-- .../Tests/STPPaymentCardTextFieldViewModelTest.m | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Tests/Tests/STPCardValidatorTest.m b/Tests/Tests/STPCardValidatorTest.m index bc01c17e02d..ff57a325e44 100644 --- a/Tests/Tests/STPCardValidatorTest.m +++ b/Tests/Tests/STPCardValidatorTest.m @@ -44,8 +44,7 @@ + (NSArray *)cardData { @[@(STPCardBrandAmex), @"371449635398431", @(STPCardValidationStateValid)], @[@(STPCardBrandDiscover), @"6011111111111117", @(STPCardValidationStateValid)], @[@(STPCardBrandDiscover), @"6011000990139424", @(STPCardValidationStateValid)], - @[@(STPCardBrandDinersClub), @"30569309025904", @(STPCardValidationStateValid)], - @[@(STPCardBrandDinersClub), @"38520000023237", @(STPCardValidationStateValid)], + @[@(STPCardBrandDinersClub), @"36227206271667", @(STPCardValidationStateValid)], @[@(STPCardBrandDinersClub), @"3056930009020004", @(STPCardValidationStateValid)], @[@(STPCardBrandJCB), @"3530111333300000", @(STPCardValidationStateValid)], @[@(STPCardBrandJCB), @"3566002020360505", @(STPCardValidationStateValid)], diff --git a/Tests/Tests/STPPaymentCardTextFieldViewModelTest.m b/Tests/Tests/STPPaymentCardTextFieldViewModelTest.m index 9da8891acd0..85e54490971 100644 --- a/Tests/Tests/STPPaymentCardTextFieldViewModelTest.m +++ b/Tests/Tests/STPPaymentCardTextFieldViewModelTest.m @@ -102,14 +102,14 @@ - (void)testCompressedCardNumber { self.viewModel.cardNumber = @"12"; XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"12"); - self.viewModel.cardNumber = @"30569309025904"; - XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"5904"); - self.viewModel.cardNumber = @"3056930902590"; - XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"590"); - self.viewModel.cardNumber = @"30569309025"; - XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"5"); - self.viewModel.cardNumber = @"3056930902"; - XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"930902"); + self.viewModel.cardNumber = @"36227206271667"; + XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"1667"); + self.viewModel.cardNumber = @"3622720627166"; + XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"166"); + self.viewModel.cardNumber = @"36227206271"; + XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"1"); + self.viewModel.cardNumber = @"3622720627"; + XCTAssertEqualObjects(self.viewModel.compressedCardNumber, @"720627"); } @end