Ali 5bb8089449 Update card validation
(cherry picked from commit 5c71c08b6e9442b009ca3b71e784a1f8e2ebe4a1)
2023-02-07 23:25:39 +04:00

200 lines
8.3 KiB
Objective-C
Executable File

//
// STPCardParams.m
// Stripe
//
// Created by Jack Flintermann on 10/4/15.
// Copyright © 2015 Stripe, Inc. All rights reserved.
//
#import "STPCardParams.h"
#import "STPCardValidator.h"
#import "StripeError.h"
@implementation STPCardParams
@synthesize additionalAPIParameters = _additionalAPIParameters;
- (instancetype)init {
self = [super init];
if (self) {
_additionalAPIParameters = @{};
}
return self;
}
- (NSString *)last4 {
if (self.number && self.number.length >= 4) {
return [self.number substringFromIndex:(self.number.length - 4)];
} else {
return nil;
}
}
#if TARGET_OS_IPHONE
- (STPAddress *)address {
STPAddress *address = [STPAddress new];
address.name = self.name;
address.line1 = self.addressLine1;
address.line2 = self.addressLine2;
address.city = self.addressCity;
address.state = self.addressState;
address.postalCode = self.addressZip;
address.country = self.addressCountry;
return address;
}
- (void)setAddress:(STPAddress *)address {
self.name = address.name;
self.addressLine1 = address.line1;
self.addressLine2 = address.line2;
self.addressCity = address.city;
self.addressState = address.state;
self.addressZip = address.postalCode;
self.addressCountry = address.country;
}
#endif
- (BOOL)validateNumber:(id *)ioValue error:(NSError **)outError {
if (*ioValue == nil) {
return [self.class handleValidationErrorForParameter:@"number" error:outError];
}
NSString *ioValueString = (NSString *)*ioValue;
if ([STPCardValidator validationStateForNumber:ioValueString validatingCardBrand:NO] != STPCardValidationStateValid) {
return [self.class handleValidationErrorForParameter:@"number" error:outError];
}
return YES;
}
- (BOOL)validateCvc:(id *)ioValue error:(NSError **)outError {
if (*ioValue == nil) {
return [self.class handleValidationErrorForParameter:@"number" error:outError];
}
NSString *ioValueString = (NSString *)*ioValue;
STPCardBrand brand = [STPCardValidator brandForNumber:self.number];
if ([STPCardValidator validationStateForCVC:ioValueString cardBrand:brand] != STPCardValidationStateValid) {
return [self.class handleValidationErrorForParameter:@"cvc" error:outError];
}
return YES;
}
- (BOOL)validateExpMonth:(id *)ioValue error:(NSError **)outError {
if (*ioValue == nil) {
return [self.class handleValidationErrorForParameter:@"expMonth" error:outError];
}
NSString *ioValueString = [(NSString *)*ioValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([STPCardValidator validationStateForExpirationMonth:ioValueString] != STPCardValidationStateValid) {
return [self.class handleValidationErrorForParameter:@"expMonth" error:outError];
}
return YES;
}
- (BOOL)validateExpYear:(id *)ioValue error:(NSError **)outError {
if (*ioValue == nil) {
return [self.class handleValidationErrorForParameter:@"expYear" error:outError];
}
NSString *ioValueString = [(NSString *)*ioValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *monthString = [@(self.expMonth) stringValue];
if ([STPCardValidator validationStateForExpirationYear:ioValueString inMonth:monthString cardBrand:[STPCardValidator brandForNumber:self.number]] != STPCardValidationStateValid) {
return [self.class handleValidationErrorForParameter:@"expYear" error:outError];
}
return YES;
}
- (BOOL)validateCardReturningError:(NSError **)outError {
// Order matters here
NSString *numberRef = [self number];
NSString *expMonthRef = [NSString stringWithFormat:@"%02lu", (unsigned long)[self expMonth]];
NSString *expYearRef = [NSString stringWithFormat:@"%02lu", (unsigned long)[self expYear]];
NSString *cvcRef = [self cvc];
// Make sure expMonth, expYear, and number are set. Validate CVC if it is provided
return [self validateNumber:&numberRef error:outError] && [self validateExpYear:&expYearRef error:outError] &&
[self validateExpMonth:&expMonthRef error:outError] && (cvcRef == nil || [self validateCvc:&cvcRef error:outError]);
}
#pragma mark Private Helpers
+ (BOOL)handleValidationErrorForParameter:(NSString *)parameter error:(NSError **)outError {
if (outError != nil) {
if ([parameter isEqualToString:@"number"]) {
*outError = [self createErrorWithMessage:[NSError stp_cardErrorInvalidNumberUserMessage]
parameter:parameter
cardErrorCode:STPInvalidNumber
devErrorMessage:@"Card number must be between 10 and 19 digits long and Luhn valid."];
} else if ([parameter isEqualToString:@"cvc"]) {
*outError = [self createErrorWithMessage:[NSError stp_cardInvalidCVCUserMessage]
parameter:parameter
cardErrorCode:STPInvalidCVC
devErrorMessage:@"Card CVC must be numeric, 3 digits for Visa, Discover, MasterCard, JCB, and Discover cards, and 3 or 4 "
@"digits for American Express cards."];
} else if ([parameter isEqualToString:@"expMonth"]) {
*outError = [self createErrorWithMessage:[NSError stp_cardErrorInvalidExpMonthUserMessage]
parameter:parameter
cardErrorCode:STPInvalidExpMonth
devErrorMessage:@"expMonth must be less than 13"];
} else if ([parameter isEqualToString:@"expYear"]) {
*outError = [self createErrorWithMessage:[NSError stp_cardErrorInvalidExpYearUserMessage]
parameter:parameter
cardErrorCode:STPInvalidExpYear
devErrorMessage:@"expYear must be this year or a year in the future"];
} else {
// This should not be possible since this is a private method so we
// know exactly how it is called. We use STPAPIError for all errors
// that are unexpected within the bindings as well.
*outError = [[NSError alloc] initWithDomain:StripeDomain
code:STPAPIError
userInfo:@{
NSLocalizedDescriptionKey: [NSError stp_unexpectedErrorMessage],
STPErrorMessageKey: @"There was an error within the Stripe client library when trying to generate the "
@"proper validation error. Contact support@stripe.com if you see this."
}];
}
}
return NO;
}
+ (NSError *)createErrorWithMessage:(NSString *)userMessage
parameter:(NSString *)parameter
cardErrorCode:(NSString *)cardErrorCode
devErrorMessage:(NSString *)devMessage {
return [[NSError alloc] initWithDomain:StripeDomain
code:STPCardError
userInfo:@{
NSLocalizedDescriptionKey: userMessage,
STPErrorParameterKey: parameter,
STPCardErrorCodeKey: cardErrorCode,
STPErrorMessageKey: devMessage
}];
}
#pragma mark - STPFormEncodable
+ (NSString *)rootObjectName {
return @"card";
}
+ (NSDictionary *)propertyNamesToFormFieldNamesMapping {
return @{
@"number": @"number",
@"cvc": @"cvc",
@"name": @"name",
@"addressLine1": @"address_line1",
@"addressLine2": @"address_line2",
@"addressCity": @"address_city",
@"addressState": @"address_state",
@"addressZip": @"address_zip",
@"addressCountry": @"address_country",
@"expMonth": @"exp_month",
@"expYear": @"exp_year",
@"currency": @"currency",
};
}
@end