Skip to content

Commit

Permalink
fix(crashes): fix several crashes and brand handling (#120)
Browse files Browse the repository at this point in the history
* Fix android crash if no `shippingAddressFields`

* Fix ios crash in createPmtMthd if card has address

* Fix ios crash if no shipping methods provided.

* Fix image/brand handling on Android.

* Oops

* bump version
  • Loading branch information
RobertGardner authored May 10, 2020
1 parent 4cd5a32 commit b967da0
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 72 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
Changelog

## 6.6.1 (2020, May 9)
### Fixes
- Crash on iOS in `createPaymentMethod` if the card has address fields. (#119)
- Crash on iOS in `paymentContextDidUpdateShippingAddressCompletion` if no shipping methods provided.
- Crash on Android in `StripeConfig` if `requiredShippingAddressFields` is null.
- Improve handling of brands and images on Android. Latest SDK "brand" values changed.


## 6.6.0 (2020, May 5)
### Updates
- [(# 115)](https://github.com/triniwiz/nativescript-stripe/issues/115) Make Stripe's credit card images visible to clients
Expand Down
5 changes: 3 additions & 2 deletions demo-angular/app/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"android": {
"v8Flags": "--expose_gc"
"v8Flags": "--expose_gc",
"markingMode": "full"
},
"main": "main.js",
"name": "tns-template-hello-world-ng",
"version": "4.0.1"
}
}
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nativescript-stripe",
"version": "6.6.0",
"version": "6.6.1",
"description": "NativeScript Stripe sdk",
"main": "stripe",
"typings": "index.d.ts",
Expand Down
77 changes: 63 additions & 14 deletions src/standard/standard.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,21 @@ export class StripeConfig extends StripeConfigCommon {

get nativeBuilder(): com.stripe.android.PaymentSessionConfig.Builder {
this.initPaymentConfiguration();
const shippingRequired = this.requiredShippingAddressFields && this.requiredShippingAddressFields.length !== 0;
let optionalFields = [];
if (this.requiredShippingAddressFields.indexOf(StripeShippingAddressField.PostalAddress) < 0) {
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.ADDRESS_LINE_ONE_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.ADDRESS_LINE_TWO_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.CITY_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.STATE_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.POSTAL_CODE_FIELD);
}
if (this.requiredShippingAddressFields.indexOf(StripeShippingAddressField.Phone) < 0) {
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.PHONE_FIELD);
if (shippingRequired) {
if (this.requiredShippingAddressFields.indexOf(StripeShippingAddressField.PostalAddress) < 0) {
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.ADDRESS_LINE_ONE_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.ADDRESS_LINE_TWO_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.CITY_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.STATE_FIELD);
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.POSTAL_CODE_FIELD);
}
if (this.requiredShippingAddressFields.indexOf(StripeShippingAddressField.Phone) < 0) {
optionalFields.unshift(com.stripe.android.view.ShippingInfoWidget.CustomizableShippingField.PHONE_FIELD);
}
}

const shippingRequired = this.requiredShippingAddressFields.length !== 0;
return new com.stripe.android.PaymentSessionConfig.Builder()
.setShippingInfoRequired(shippingRequired)
.setShippingMethodsRequired(shippingRequired)
Expand Down Expand Up @@ -187,7 +189,7 @@ export class StripePaymentSession {

function createPaymentSessionListener(parent: StripePaymentSession, listener: StripePaymentListener): com.stripe.android.PaymentSession.PaymentSessionListener {
return new com.stripe.android.PaymentSession.PaymentSessionListener({
onPaymentSessionDataChanged: (sessionData: com.stripe.android.PaymentSessionData): void => {
onPaymentSessionDataChanged: (sessionData: com.stripe.android.PaymentSessionData): void => {
if (parent.paymentInProgress) return;

parent.customerSession.native.retrieveCurrentCustomer(new com.stripe.android.CustomerSession.CustomerRetrievalListener({
Expand Down Expand Up @@ -259,12 +261,12 @@ function createPaymentMethodFromCard(card: com.stripe.android.model.PaymentMetho
const brand = card.component1(); // brand
const last4 = card.component7(); // last4
return {
label: `${brand} ...${last4}`,
image: getBitmapFromResource(com.stripe.android.model.Card.getBrandIcon(brand)),
label: `${toCardBrand(brand)} ...${last4}`,
image: getBitmapFromResource(com.stripe.android.model.Card.getBrandIcon(fixupCardBrand(brand))),
templateImage: undefined,
type: "Card",
stripeID,
brand: brand
brand: toCardBrand(brand)
};
}

Expand Down Expand Up @@ -317,3 +319,50 @@ function createAdShippingMethod(method: StripeShippingMethod, currency: string):
method.detail
);
}

function toCardBrand(brand: string): string {
switch (brand.toLowerCase()) {
case com.stripe.android.model.Card.CardBrand.VISA.toLowerCase():
return 'Visa';
case com.stripe.android.model.Card.CardBrand.AMERICAN_EXPRESS.toLowerCase():
case 'amex':
case 'american express':
return 'Amex';
case com.stripe.android.model.Card.CardBrand.MASTERCARD.toLowerCase():
return 'MasterCard';
case com.stripe.android.model.Card.CardBrand.DISCOVER.toLowerCase():
return 'Discover';
case com.stripe.android.model.Card.CardBrand.JCB.toLowerCase():
return 'JCB';
case com.stripe.android.model.Card.CardBrand.DINERS_CLUB.toLowerCase():
case 'diners':
case 'diners club':
return 'DinersClub';
}
return 'Unknown';
}

function fixupCardBrand(brand: string): string {
let result;
switch (brand.toLowerCase()) {
case 'visa':
return com.stripe.android.model.Card.CardBrand.VISA;
case 'amex':
case 'americanexpress':
case 'american_express':
case 'american express':
return com.stripe.android.model.Card.CardBrand.AMERICAN_EXPRESS;
case 'mastercard':
return com.stripe.android.model.Card.CardBrand.MASTERCARD;
case 'discover':
return com.stripe.android.model.Card.CardBrand.DISCOVER;
case 'jcb':
return com.stripe.android.model.Card.CardBrand.JCB;
case 'diners':
case 'dinersclub':
case 'diners_club':
case 'diners club':
return com.stripe.android.model.Card.CardBrand.DINERS_CLUB;
}
return com.stripe.android.model.Card.CardBrand.UNKNOWN;
}
6 changes: 4 additions & 2 deletions src/standard/standard.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,11 @@ class StripePaymentDelegate extends NSObject implements STPPaymentContextDelegat
}
}

paymentContextDidUpdateShippingAddressCompletion(paymentContext: STPPaymentContext, address: STPAddress, completion: (p1: STPShippingStatus, p2: NSError, p3: NSArray<PKShippingMethod>, p4: PKShippingMethod) => void): void {
paymentContextDidUpdateShippingAddressCompletion(_paymentContext: STPPaymentContext, address: STPAddress, completion: (p1: STPShippingStatus, p2: NSError, p3: NSArray<PKShippingMethod>, p4: PKShippingMethod) => void): void {
let methods = this.listener.provideShippingMethods(createAddress(address));
if (!methods.isValid) {
if (!methods) {
completion(STPShippingStatus.Invalid, createError("ShippingError", 120, "No shipping methods"), null, null);
} else if (!methods.isValid) {
completion(STPShippingStatus.Invalid, createError("ShippingError", 123, methods.validationError), null, null);
} else {
let sh = <NSMutableArray<PKShippingMethod>>NSMutableArray.alloc().init();
Expand Down
100 changes: 61 additions & 39 deletions src/stripe.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,18 @@ export class Stripe {
cardSourceParams,
new com.stripe.android.ApiResultCallback<com.stripe.android.model.Source>({
onSuccess: function (source: com.stripe.android.model.Source) {
if (typeof cb === 'function') {
const newSource: Source = {
id: source.getId(),
amount: source.getAmount().longValue(),
card: card,
clientSecret: source.getClientSecret(),
created: new Date(source.getCreated().toString()),
currency: source.getCurrency(),
livemode: source.isLiveMode().booleanValue(),
metadata: source.getMetaData()
};
cb(null, newSource);
if (typeof cb === 'function') {
const newSource: Source = {
id: source.getId(),
amount: source.getAmount().longValue(),
card: card,
clientSecret: source.getClientSecret(),
created: new Date(source.getCreated().toString()),
currency: source.getCurrency(),
livemode: source.isLiveMode().booleanValue(),
metadata: source.getMetaData()
};
cb(null, newSource);
}
},
onError: function (error) {
Expand Down Expand Up @@ -208,7 +208,7 @@ export class Stripe {
};
this.stripe.confirmPayment(activity, piParams.native);
} catch (error) {
cb(new Error(error.localizedDescription), null);
cb(new Error(error.localizedDescription), null);
}
}

Expand Down Expand Up @@ -264,7 +264,7 @@ export class Card implements CardCommon {
const pmCard = pm.component8(); // card
const newCard = new Card(null, null, null, null);
newCard._last4 = pmCard.component7(); // last4
newCard._brand = <CardBrand>pmCard.component1(); // brand
newCard._brand = toCardBrand(pmCard.component1()); // brand
newCard._cardBuilder = new com.stripe.android.model.Card.Builder(
null,
pmCard.component4(), // expiryMonth
Expand Down Expand Up @@ -374,7 +374,7 @@ export class Card implements CardCommon {
}

get brand(): CardBrand {
if (!this._brand) this._brand = <CardBrand>this.native.getBrand();
if (!this._brand) this._brand = toCardBrand(this.native.getBrand());
return this._brand;
}

Expand All @@ -395,32 +395,54 @@ export class Card implements CardCommon {
* The returned value can be used as [src] in an Image tag.
*/
static cardImage(brand: CardBrand): any {
return getBitmapFromResource(com.stripe.android.model.Card.getBrandIcon(Card.fromCardBrand(brand)));
}

private static fromCardBrand(brand: CardBrand): string {
switch (brand.toLowerCase()) {
case 'visa':
return com.stripe.android.model.Card.CardBrand.VISA;
case 'amex':
case 'americanexpress':
case 'american_express':
case 'american express':
return com.stripe.android.model.Card.CardBrand.AMERICAN_EXPRESS;
case 'mastercard':
return com.stripe.android.model.Card.CardBrand.MASTERCARD;
case 'discover':
return com.stripe.android.model.Card.CardBrand.DISCOVER;
case 'jcb':
return com.stripe.android.model.Card.CardBrand.JCB;
case 'dinersclub':
case 'diners_club':
case 'diners club':
return com.stripe.android.model.Card.CardBrand.DINERS_CLUB;
}
return com.stripe.android.model.Card.CardBrand.UNKNOWN;
return getBitmapFromResource(com.stripe.android.model.Card.getBrandIcon(fixupCardBrand(brand)));
}
}

function toCardBrand(brand: string): CardBrand {
switch (brand.toLowerCase()) {
case com.stripe.android.model.Card.CardBrand.VISA.toLowerCase():
return 'Visa';
case com.stripe.android.model.Card.CardBrand.AMERICAN_EXPRESS.toLowerCase():
case 'amex':
case 'american express':
return 'Amex';
case com.stripe.android.model.Card.CardBrand.MASTERCARD.toLowerCase():
return 'MasterCard';
case com.stripe.android.model.Card.CardBrand.DISCOVER.toLowerCase():
return 'Discover';
case com.stripe.android.model.Card.CardBrand.JCB.toLowerCase():
return 'JCB';
case com.stripe.android.model.Card.CardBrand.DINERS_CLUB.toLowerCase():
case 'diners':
case 'diners club':
return 'DinersClub';
}
return 'Unknown';
}

function fixupCardBrand(brand: string): string {
switch (brand.toLowerCase()) {
case 'visa':
return com.stripe.android.model.Card.CardBrand.VISA;
case 'amex':
case 'americanexpress':
case 'american_express':
case 'american express':
return com.stripe.android.model.Card.CardBrand.AMERICAN_EXPRESS;
case 'mastercard':
return com.stripe.android.model.Card.CardBrand.MASTERCARD;
case 'discover':
return com.stripe.android.model.Card.CardBrand.DISCOVER;
case 'jcb':
return com.stripe.android.model.Card.CardBrand.JCB;
case 'diners':
case 'dinersclub':
case 'diners_club':
case 'diners club':
return com.stripe.android.model.Card.CardBrand.DINERS_CLUB;
}
return com.stripe.android.model.Card.CardBrand.UNKNOWN;
}

function getBitmapFromResource(resID: number): android.graphics.Bitmap {
Expand Down
29 changes: 15 additions & 14 deletions src/stripe.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class Stripe {

const apiClient = STPAPIClient.sharedClient();
apiClient.createSourceWithParamsCompletion(
sourceParams, callback(cb, (source: STPSource) => <Source> {
sourceParams, callback(cb, (source: STPSource) => <Source>{
id: source.stripeID,
amount: source.amount,
card: card,
Expand All @@ -75,6 +75,7 @@ export class Stripe {
if (card.expYear) cardParams.expYear = card.expYear;
if (card.number) cardParams.number = card.number;
const billing = STPPaymentMethodBillingDetails.new();
billing.address = STPPaymentMethodAddress.new();
if (card.addressLine1) billing.address.line1 = card.addressLine1;
if (card.addressLine2) billing.address.line2 = card.addressLine2;
if (card.addressCity) billing.address.city = card.addressCity;
Expand Down Expand Up @@ -165,7 +166,7 @@ export class Stripe {

authContext.hostViewController = iosUtils.getVisibleViewController(rootVC);
authContext.authenticationPresentingViewController = () => {
return authContext.hostViewController;
return authContext.hostViewController;
};
return authContext;
}
Expand All @@ -174,19 +175,19 @@ export class Stripe {
function callback(
cb: (error: Error, value: any) => void,
cvt: (value: any) => any):
(value: any, err: NSError) => void {
return (value: any, error: NSError) => {
if (!error) {
if (typeof cb === 'function') {
cb(null, cvt(value));
}
} else {
if (typeof cb === 'function') {
cb(new Error(error.toLocaleString()), null);
}
}
};
(value: any, err: NSError) => void {
return (value: any, error: NSError) => {
if (!error) {
if (typeof cb === 'function') {
cb(null, cvt(value));
}
} else {
if (typeof cb === 'function') {
cb(new Error(error.toLocaleString()), null);
}
}
};
}

export class Card implements CardCommon {
native: STPCardParams;
Expand Down

0 comments on commit b967da0

Please sign in to comment.