From 71bba5ebf4bd891604404904432cd196635bc3e6 Mon Sep 17 00:00:00 2001 From: Iner Garcia Rodriguez Date: Fri, 14 Jan 2022 22:16:59 -0500 Subject: [PATCH 1/2] Null safety migration of the stripe_api package --- lib/card_utils.dart | 54 ++++---- lib/credit_card_mask_controller.dart | 36 +++--- lib/ephemeral_key_manager.dart | 54 ++++---- lib/model/address.dart | 14 +- lib/model/card.dart | 165 +++++++++++------------- lib/model/customer.dart | 34 ++--- lib/model/customer_source.dart | 39 +++--- lib/model/shipping_information.dart | 13 +- lib/model/source.dart | 78 ++++++----- lib/model/source_card_data.dart | 26 ++-- lib/model/source_code_verification.dart | 8 +- lib/model/source_owner.dart | 22 ++-- lib/model/source_receiver.dart | 10 +- lib/model/source_redirect.dart | 8 +- lib/model/stripe_json_model.dart | 10 +- lib/model/stripe_json_utils.dart | 92 ++++++------- lib/model/stripe_source_type_model.dart | 6 +- lib/model/token.dart | 50 +++---- lib/stripe_api.dart | 46 +++---- lib/stripe_api_handler.dart | 58 ++++----- lib/stripe_error.dart | 24 ++-- lib/stripe_network_utils.dart | 12 +- lib/stripe_text_utils.dart | 50 ++++--- lib/text_utils.dart | 6 +- pubspec.yaml | 2 +- 25 files changed, 437 insertions(+), 480 deletions(-) diff --git a/lib/card_utils.dart b/lib/card_utils.dart index 4121e6e..97b84c5 100644 --- a/lib/card_utils.dart +++ b/lib/card_utils.dart @@ -12,27 +12,23 @@ const int MAX_LENGTH_COMMON = 19; // because Diners Club has one more space, but one less digit. const int MAX_LENGTH_AMEX_DINERS = 17; -/** - * Checks the input string to see whether or not it is a valid card number, possibly - * with groupings separated by spaces or hyphens. - * - * @param cardNumber a String that may or may not represent a valid card number - * @return {@code true} if and only if the input value is a valid card number - */ +/// Checks the input string to see whether or not it is a valid card number, possibly +/// with groupings separated by spaces or hyphens. +/// +/// @param cardNumber a String that may or may not represent a valid card number +/// @return {@code true} if and only if the input value is a valid card number bool isValidCardNumber(String cardNumber) { - String normalizedNumber = removeSpacesAndHyphens(cardNumber); - return isValidLuhnNumber(normalizedNumber) && - isValidCardLength(normalizedNumber); + String? normalizedNumber = removeSpacesAndHyphens(cardNumber); + return isValidLuhnNumber(normalizedNumber ?? '') && + isValidCardLength(normalizedNumber ?? '', cardBrand: ''); } -/** - * Checks the input string to see whether or not it is a valid Luhn number. - * - * @param cardNumber a String that may or may not represent a valid Luhn number - * @return {@code true} if and only if the input value is a valid Luhn number - */ +/// Checks the input string to see whether or not it is a valid Luhn number. +/// +/// @param cardNumber a String that may or may not represent a valid Luhn number +/// @return {@code true} if and only if the input value is a valid Luhn number bool isValidLuhnNumber(String cardNumber) { - if (cardNumber == null) { + if (cardNumber.isEmpty) { return false; } @@ -45,7 +41,7 @@ bool isValidLuhnNumber(String cardNumber) { return false; } - int digitInteger = getNumericValue(c); + int digitInteger = getNumericValue(c) ?? 0; isOdd = !isOdd; if (isOdd) { @@ -62,19 +58,17 @@ bool isValidLuhnNumber(String cardNumber) { return sum % 10 == 0; } -/** - * Checks to see whether the input number is of the correct length, given the assumed brand of - * the card. This function does not perform a Luhn check. - * - * @param cardNumber the card number with no spaces or dashes - * @param cardBrand a {@link CardBrand} used to get the correct size - * @return {@code true} if the card number is the correct length for the assumed brand - */ -bool isValidCardLength(String cardNumber, {String cardBrand}) { - if (cardBrand == null) { +/// Checks to see whether the input number is of the correct length, given the assumed brand of +/// the card. This function does not perform a Luhn check. +/// +/// @param cardNumber the card number with no spaces or dashes +/// @param cardBrand a {@link CardBrand} used to get the correct size +/// @return {@code true} if the card number is the correct length for the assumed brand +bool isValidCardLength(String cardNumber, {required String cardBrand}) { + if (cardBrand.isEmpty) { cardBrand = getPossibleCardType(cardNumber, shouldNormalize: false); } - if (cardNumber == null || StripeCard.UNKNOWN == cardBrand) { + if (cardNumber.isEmpty || StripeCard.UNKNOWN == cardBrand) { return false; } @@ -96,7 +90,7 @@ String getPossibleCardType(String cardNumber, {bool shouldNormalize = true}) { String spacelessCardNumber = cardNumber; if (shouldNormalize) { - spacelessCardNumber = removeSpacesAndHyphens(cardNumber); + spacelessCardNumber = removeSpacesAndHyphens(cardNumber) ?? ''; } if (hasAnyPrefix(spacelessCardNumber, StripeCard.PREFIXES_AMERICAN_EXPRESS)) { diff --git a/lib/credit_card_mask_controller.dart b/lib/credit_card_mask_controller.dart index 178c887..b5f44ee 100644 --- a/lib/credit_card_mask_controller.dart +++ b/lib/credit_card_mask_controller.dart @@ -2,17 +2,17 @@ import 'package:flutter/material.dart'; import 'package:stripe_api/stripe_api.dart'; class CreditCardMaskedTextController extends TextEditingController { - CreditCardMaskedTextController({String text}) : super(text: text) { - this._translator = CreditCardMaskedTextController._getDefaultTranslator(); + CreditCardMaskedTextController({String text = ''}) : super(text: text) { + _translator = CreditCardMaskedTextController._getDefaultTranslator(); - this.addListener(() { - this._updateText(this.text); + addListener(() { + _updateText(this.text); }); - this._updateText(this.text); + _updateText(this.text); } - static const CARD_MASKS = const { + static const Map CARD_MASKS = { StripeCard.UNKNOWN: '0000 0000 0000 0000', StripeCard.AMERICAN_EXPRESS: '0000 000000 00000', StripeCard.DISCOVER: '0000 0000 0000 0000', @@ -23,24 +23,24 @@ class CreditCardMaskedTextController extends TextEditingController { StripeCard.UNIONPAY: '0000 0000 0000 0000', }; - Map _translator; + late Map _translator; String _lastUpdatedText = ''; void _updateText(String text) { - if (text != null) { - final cardType = getPossibleCardType(text, shouldNormalize: true); - final mask = CARD_MASKS[cardType]; - this.text = this._applyMask(mask, text); + if (text.isNotEmpty) { + final String cardType = getPossibleCardType(text, shouldNormalize: true); + final String mask = CARD_MASKS[cardType]!; + this.text = _applyMask(mask, text); } else { this.text = ''; } - this._lastUpdatedText = this.text; + _lastUpdatedText = this.text; } void _moveCursorToEnd() { - var text = this._lastUpdatedText; - this.selection = TextSelection.fromPosition( - TextPosition(offset: (text ?? '').length), + var text = _lastUpdatedText; + selection = TextSelection.fromPosition( + TextPosition(offset: text.length), ); } @@ -48,7 +48,7 @@ class CreditCardMaskedTextController extends TextEditingController { set text(String newText) { if (super.text != newText) { super.text = newText; - this._moveCursorToEnd(); + _moveCursorToEnd(); } } @@ -90,8 +90,8 @@ class CreditCardMaskedTextController extends TextEditingController { } // apply translator if match - if (this._translator.containsKey(maskChar)) { - if (this._translator[maskChar].hasMatch(valueChar)) { + if (_translator.containsKey(maskChar)) { + if (_translator[maskChar]!.hasMatch(valueChar)) { result += valueChar; maskCharIndex += 1; } diff --git a/lib/ephemeral_key_manager.dart b/lib/ephemeral_key_manager.dart index b8d637e..818970d 100644 --- a/lib/ephemeral_key_manager.dart +++ b/lib/ephemeral_key_manager.dart @@ -9,7 +9,7 @@ import 'stripe_error.dart'; /// /// /// -typedef Future EphemeralKeyProvider(String apiVersion); +typedef EphemeralKeyProvider = Future Function(String apiVersion); /// /// @@ -26,28 +26,28 @@ class EphemeralKey extends StripeJsonModel { static const String NULL = "null"; - String _id; - int _created; - int _expires; - bool _liveMode; - String _customerId; - String _object; - String _secret; - String _type; - DateTime _createdAt; - DateTime _expiresAt; + late String _id; + late int _created; + late int _expires; + late bool _liveMode; + late String _customerId; + late String _object; + late String _secret; + late String _type; + late DateTime _createdAt; + late DateTime _expiresAt; EphemeralKey.fromJson(Map json) { - _id = optString(json, FIELD_ID); - _created = optInteger(json, FIELD_CREATED); - _expires = optInteger(json, FIELD_EXPIRES); - _liveMode = optBoolean(json, FIELD_LIVEMODE); + _id = optString(json, FIELD_ID) ?? ''; + _created = optInteger(json, FIELD_CREATED) ?? -1; + _expires = optInteger(json, FIELD_EXPIRES) ?? -1; + _liveMode = optBoolean(json, FIELD_LIVEMODE) ?? false; _customerId = json[FIELD_ASSOCIATED_OBJECTS][0][FIELD_ID]; _type = json[FIELD_ASSOCIATED_OBJECTS][0][FIELD_TYPE]; - _object = optString(json, FIELD_OBJECT); - _secret = optString(json, FIELD_SECRET); - _createdAt = new DateTime.fromMillisecondsSinceEpoch(_created); - _expiresAt = new DateTime.fromMillisecondsSinceEpoch(_expires); + _object = optString(json, FIELD_OBJECT) ?? ''; + _secret = optString(json, FIELD_SECRET) ?? ''; + _createdAt = DateTime.fromMillisecondsSinceEpoch(_created); + _expiresAt = DateTime.fromMillisecondsSinceEpoch(_expires); } String get id => _id; @@ -90,7 +90,7 @@ class EphemeralKey extends StripeJsonModel { /// /// class EphemeralKeyManager { - EphemeralKey _ephemeralKey; + EphemeralKey? _ephemeralKey; final EphemeralKeyProvider ephemeralKeyProvider; final int timeBufferInSeconds; @@ -99,28 +99,28 @@ class EphemeralKeyManager { /// /// /// - Future retrieveEphemeralKey() async { + Future retrieveEphemeralKey() async { if (_shouldRefreshKey()) { String key; try { key = await ephemeralKeyProvider(API_VERSION); } catch (error) { - final e = new StripeAPIError(null, { + final e = StripeAPIError('', { StripeAPIError.FIELD_MESSAGE: "Failed to retrive ephemeralKey from server", }); - throw new StripeAPIException(e); + throw StripeAPIException(e); } try { Map decodedKey = json.decode(key); - _ephemeralKey = new EphemeralKey.fromJson(decodedKey); + _ephemeralKey = EphemeralKey.fromJson(decodedKey); } catch (error) { - final e = new StripeAPIError(null, { + final e = StripeAPIError('', { StripeAPIError.FIELD_MESSAGE: "Failed to parse Ephemeral Key, Please return the response as it is as you recieved from stripe server", }); - throw new StripeAPIException(e); + throw StripeAPIException(e); } return _ephemeralKey; @@ -138,7 +138,7 @@ class EphemeralKeyManager { } DateTime now = DateTime.now(); - final diff = _ephemeralKey.expiresAt.difference(now).abs(); + final diff = _ephemeralKey!.expiresAt.difference(now).abs(); return diff.inSeconds < timeBufferInSeconds; } } diff --git a/lib/model/address.dart b/lib/model/address.dart index 22d1f0c..8576058 100644 --- a/lib/model/address.dart +++ b/lib/model/address.dart @@ -10,12 +10,12 @@ class Address extends StripeJsonModel { static const String FIELD_POSTAL_CODE = "postal_code"; static const String FIELD_STATE = "state"; - String city; - String country; - String line1; - String line2; - String postalCode; - String state; + String? city; + String? country; + String? line1; + String? line2; + String? postalCode; + String? state; Address({ this.city, @@ -37,7 +37,7 @@ class Address extends StripeJsonModel { @override Map toMap() { - Map hashMap = new Map(); + Map hashMap = {}; hashMap[FIELD_CITY] = city; hashMap[FIELD_COUNTRY] = country; hashMap[FIELD_LINE_1] = line1; diff --git a/lib/model/card.dart b/lib/model/card.dart index 2943371..89a175d 100644 --- a/lib/model/card.dart +++ b/lib/model/card.dart @@ -1,5 +1,3 @@ -import 'package:flutter/foundation.dart'; - import '../card_utils.dart'; import '../stripe_network_utils.dart'; import '../stripe_text_utils.dart'; @@ -111,36 +109,36 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { static const String FIELD_ID = "id"; static const String FIELD_TOKENIZATION_METHOD = "tokenization_method"; - String number; - String cvc; - int expMonth; - int expYear; - String name; - String addressLine1; - String addressLine1Check; - String addressLine2; - String addressCity; - String addressState; - String addressZip; - String addressZipCheck; - String addressCountry; - String last4; - String _brand; - String funding; - String fingerprint; - String country; - String currency; - String customerId; - String cvcCheck; - String id; - List loggingTokens = []; - String tokenizationMethod; + late String number; + late String cvc; + late int expMonth; + late int expYear; + String? name; + String? addressLine1; + String? addressLine1Check; + String? addressLine2; + String? addressCity; + String? addressState; + String? addressZip; + String? addressZipCheck; + String? addressCountry; + String? last4; + late String _brand; + String? funding; + String? fingerprint; + String? country; + String? currency; + String? customerId; + String? cvcCheck; + late String id; + late List loggingTokens; + String? tokenizationMethod; StripeCard({ - @required this.number, - @required this.cvc, - @required this.expMonth, - @required this.expYear, + required this.number, + required this.cvc, + required this.expMonth, + required this.expYear, this.name, this.addressLine1, this.addressLine1Check, @@ -151,24 +149,25 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { this.addressZipCheck, this.addressCountry, this.last4, - String brand, + String? brand, this.funding, this.fingerprint, this.country, this.currency, this.customerId, this.cvcCheck, - this.id, - this.loggingTokens, + this.id = '', + List? loggingTokens, this.tokenizationMethod, - }) : _brand = brand; + }) : _brand = brand ??= '', + loggingTokens = loggingTokens ?? []; StripeCard.fromJson(Map json) { // Note that we'll never get the CVC or card number in JSON, so those values are null - number = optString(json, FIELD_NUMBER); - cvc = optString(json, FIELD_CVC); - expMonth = optInteger(json, FIELD_EXP_MONTH); - expYear = optInteger(json, FIELD_EXP_YEAR); + number = optString(json, FIELD_NUMBER) ?? ''; + cvc = optString(json, FIELD_CVC) ?? ''; + expMonth = optInteger(json, FIELD_EXP_MONTH) ?? -1; + expYear = optInteger(json, FIELD_EXP_YEAR) ?? -1; addressCity = optString(json, FIELD_ADDRESS_CITY); addressLine1 = optString(json, FIELD_ADDRESS_LINE1); addressLine1Check = optString(json, FIELD_ADDRESS_LINE1_CHECK); @@ -178,14 +177,14 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { addressState = optString(json, FIELD_ADDRESS_STATE); addressZip = optString(json, FIELD_ADDRESS_ZIP); addressZipCheck = optString(json, FIELD_ADDRESS_ZIP_CHECK); - _brand = asCardBrand(optString(json, FIELD_BRAND)); + _brand = asCardBrand(optString(json, FIELD_BRAND) ?? ''); country = optCountryCode(json, FIELD_COUNTRY); customerId = optString(json, FIELD_CUSTOMER); currency = optCurrency(json, FIELD_CURRENCY); cvcCheck = optString(json, FIELD_CVC_CHECK); - funding = asFundingType(optString(json, FIELD_FUNDING)); + funding = asFundingType(optString(json, FIELD_FUNDING) ?? ''); fingerprint = optString(json, FIELD_FINGERPRINT); - id = optString(json, FIELD_ID); + id = optString(json, FIELD_ID) ?? ''; last4 = optString(json, FIELD_LAST4); name = optString(json, FIELD_NAME); tokenizationMethod = optString(json, FIELD_TOKENIZATION_METHOD); @@ -199,39 +198,31 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { return _brand; } - /** - * Checks whether {@code this} represents a valid card. - * - * @return {@code true} if valid, {@code false} otherwise. - */ + /// Checks whether {@code this} represents a valid card. + /// + /// @return {@code true} if valid, {@code false} otherwise. bool validateCard() { return _validateCard(DateTime.now()); } - /** - * Checks whether or not the {@link #number} field is valid. - * - * @return {@code true} if valid, {@code false} otherwise. - */ + /// Checks whether or not the {@link #number} field is valid. + /// + /// @return {@code true} if valid, {@code false} otherwise. bool validateNumber() { return isValidCardNumber(number); } - /** - * Checks whether or not the {@link #expMonth} and {@link #expYear} fields represent a valid - * expiry date. - * - * @return {@code true} if valid, {@code false} otherwise - */ + /// Checks whether or not the {@link #expMonth} and {@link #expYear} fields represent a valid + /// expiry date. + /// + /// @return {@code true} if valid, {@code false} otherwise bool validateExpiryDate() { return _validateExpiryDate(DateTime.now()); } - /** - * Checks whether or not the {@link #cvc} field is valid. - * - * @return {@code true} if valid, {@code false} otherwise - */ + /// Checks whether or not the {@link #cvc} field is valid. + /// + /// @return {@code true} if valid, {@code false} otherwise bool validateCVC() { if (isBlank(cvc)) { return false; @@ -246,26 +237,22 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { return ModelUtils.isWholePositiveNumber(cvcValue) && validLength; } - /** - * Checks whether or not the {@link #expMonth} field is valid. - * - * @return {@code true} if valid, {@code false} otherwise. - */ + /// Checks whether or not the {@link #expMonth} field is valid. + /// + /// @return {@code true} if valid, {@code false} otherwise. bool validateExpMonth() { - return expMonth != null && expMonth >= 1 && expMonth <= 12; + return expMonth >= 1 && expMonth <= 12; } - /** - * Checks whether or not the {@link #expYear} field is valid. - * - * @return {@code true} if valid, {@code false} otherwise. - */ + /// Checks whether or not the {@link #expYear} field is valid. + /// + /// @return {@code true} if valid, {@code false} otherwise. bool validateExpYear(DateTime now) { - return expYear != null && !ModelUtils.hasYearPassed(expYear, now); + return !ModelUtils.hasYearPassed(expYear, now); } bool _validateCard(DateTime now) { - if (cvc == null) { + if (cvc.isEmpty) { return validateNumber() && _validateExpiryDate(now); } else { return validateNumber() && _validateExpiryDate(now) && validateCVC(); @@ -313,15 +300,13 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { return map; } - /** - * Converts an unchecked String value to a {@link CardBrand} or {@code null}. - * - * @param possibleCardType a String that might match a {@link CardBrand} or be empty. - * @return {@code null} if the input is blank, else the appropriate {@link CardBrand}. - */ + /// Converts an unchecked String value to a {@link CardBrand} or {@code null}. + /// + /// @param possibleCardType a String that might match a {@link CardBrand} or be empty. + /// @return {@code null} if the input is blank, else the appropriate {@link CardBrand}. static String asCardBrand(String possibleCardType) { - if (possibleCardType == null || possibleCardType.trim().isEmpty) { - return null; + if (possibleCardType.isEmpty || possibleCardType.trim().isEmpty) { + return StripeCard.UNKNOWN; } if (StripeCard.AMERICAN_EXPRESS == possibleCardType) { @@ -343,15 +328,13 @@ class StripeCard extends StripeJsonModel implements StripePaymentSource { } } - /** - * Converts an unchecked String value to a {@link FundingType} or {@code null}. - * - * @param possibleFundingType a String that might match a {@link FundingType} or be empty - * @return {@code null} if the input is blank, else the appropriate {@link FundingType} - */ + /// Converts an unchecked String value to a {@link FundingType} or {@code null}. + /// + /// @param possibleFundingType a String that might match a {@link FundingType} or be empty + /// @return {@code null} if the input is blank, else the appropriate {@link FundingType} static String asFundingType(String possibleFundingType) { - if (possibleFundingType == null || possibleFundingType.trim().isEmpty) { - return null; + if (possibleFundingType.isEmpty || possibleFundingType.trim().isEmpty) { + return StripeCard.FUNDING_UNKNOWN; } if (StripeCard.FUNDING_CREDIT == possibleFundingType) { diff --git a/lib/model/customer.dart b/lib/model/customer.dart index 419b27e..8901c8b 100644 --- a/lib/model/customer.dart +++ b/lib/model/customer.dart @@ -21,38 +21,38 @@ class Customer extends StripeJsonModel { static const String VALUE_APPLE_PAY = "apple_pay"; - String id; + late String id; - String defaultSource; - ShippingInformation shippingInformation; + String? defaultSource; + late ShippingInformation shippingInformation; List sources = []; - bool hasMore; - int totalCount; - String url; + late bool hasMore; + late int totalCount; + String? url; Customer.fromJson(Map json) { - id = optString(json, FIELD_ID); + id = optString(json, FIELD_ID) ?? ''; defaultSource = optString(json, FIELD_DEFAULT_SOURCE); final shipInfoObject = json[FIELD_SHIPPING]; //.cast() if (shipInfoObject != null) { - shippingInformation = new ShippingInformation.fromJson( - shipInfoObject.cast()); + shippingInformation = + ShippingInformation.fromJson(shipInfoObject.cast()); } - final Map sources = + final Map? sources = json[FIELD_SOURCES].cast(); if (sources != null && (VALUE_LIST == optString(sources, FIELD_OBJECT))) { - hasMore = optBoolean(sources, FIELD_HAS_MORE); - totalCount = optInteger(sources, FIELD_TOTAL_COUNT); + hasMore = optBoolean(sources, FIELD_HAS_MORE) ?? false; + totalCount = optInteger(sources, FIELD_TOTAL_COUNT) ?? -1; url = optString(sources, FIELD_URL); - List sourceDataList = new List(); - List dataArray = sources[FIELD_DATA] ?? new List(); + List sourceDataList = []; + List dataArray = sources[FIELD_DATA] ?? []; for (int i = 0; i < dataArray.length; i++) { try { var customerSourceObject = dataArray[i]; - CustomerSource sourceData = new CustomerSource.fromJson( + CustomerSource? sourceData = CustomerSource.fromJson( customerSourceObject.cast()); if (sourceData == null || VALUE_APPLE_PAY == sourceData.getTokenizationMethod()) { @@ -69,7 +69,7 @@ class Customer extends StripeJsonModel { @override Map toMap() { - Map mapObject = new Map(); + Map mapObject = {}; mapObject[FIELD_ID] = id; mapObject[FIELD_OBJECT] = VALUE_CUSTOMER; mapObject[FIELD_DEFAULT_SOURCE] = defaultSource; @@ -77,7 +77,7 @@ class Customer extends StripeJsonModel { StripeJsonModel.putStripeJsonModelMapIfNotNull( mapObject, FIELD_SHIPPING, shippingInformation); - Map sourcesObject = new Map(); + Map sourcesObject = {}; sourcesObject[FIELD_HAS_MORE] = hasMore; sourcesObject[FIELD_TOTAL_COUNT] = totalCount; sourcesObject[FIELD_OBJECT] = VALUE_LIST; diff --git a/lib/model/customer_source.dart b/lib/model/customer_source.dart index 9cbdf1d..dc78218 100644 --- a/lib/model/customer_source.dart +++ b/lib/model/customer_source.dart @@ -7,59 +7,58 @@ import 'stripe_json_model.dart'; import 'stripe_payment_source.dart'; class CustomerSource extends StripeJsonModel implements StripePaymentSource { - StripePaymentSource stripePaymentSource; + StripePaymentSource? stripePaymentSource; - factory CustomerSource.fromJson(Map json) { - String objectString = optString(json, "object"); - StripePaymentSource sourceObject; + static fromJson(Map json) { + String objectString = optString(json, "object") ?? ''; + StripePaymentSource? sourceObject; if (StripeCard.VALUE_CARD == objectString) { - sourceObject = new StripeCard.fromJson(json.cast()); + sourceObject = StripeCard.fromJson(json.cast()); } else if (Source.VALUE_SOURCE == objectString) { - sourceObject = new Source.fromJson(json.cast()); + sourceObject = Source.fromJson(json.cast()); } if (sourceObject == null) { return null; } else { - return new CustomerSource._internal(sourceObject); + return CustomerSource._internal(sourceObject); } } CustomerSource._internal(this.stripePaymentSource); @override - String get id => stripePaymentSource == null ? null : stripePaymentSource.id; + String get id => stripePaymentSource == null ? '' : stripePaymentSource!.id; - Source asSource() { + Source? asSource() { if (stripePaymentSource is Source) { - return stripePaymentSource; + return stripePaymentSource as Source; } return null; } - String getTokenizationMethod() { - Source paymentAsSource = asSource(); - StripeCard paymentAsCard = asCard(); + String? getTokenizationMethod() { + Source? paymentAsSource = asSource(); + StripeCard? paymentAsCard = asCard(); if (paymentAsSource != null && paymentAsSource.type == Source.CARD) { SourceCardData cardData = paymentAsSource.sourceTypeModel as SourceCardData; - if (cardData != null) { - return cardData.tokenizationMethod; - } + + return cardData.tokenizationMethod; } else if (paymentAsCard != null) { return paymentAsCard.tokenizationMethod; } return null; } - StripeCard asCard() { + StripeCard? asCard() { if (stripePaymentSource is StripeCard) { - return stripePaymentSource; + return stripePaymentSource as StripeCard; } return null; } - String getSourceType() { + String? getSourceType() { if (stripePaymentSource is StripeCard) { return Source.CARD; } else if (stripePaymentSource is Source) { @@ -76,6 +75,6 @@ class CustomerSource extends StripeJsonModel implements StripePaymentSource { } else if (stripePaymentSource is StripeCard) { return (stripePaymentSource as StripeCard).toMap(); } - return new Map(); + return {}; } } diff --git a/lib/model/shipping_information.dart b/lib/model/shipping_information.dart index fce648c..555ef52 100644 --- a/lib/model/shipping_information.dart +++ b/lib/model/shipping_information.dart @@ -8,9 +8,9 @@ class ShippingInformation extends StripeJsonModel { static const String FIELD_NAME = "name"; static const String FIELD_PHONE = "phone"; - Address address; - String name; - String phone; + Address? address; + String? name; + String? phone; ShippingInformation({ this.address, @@ -22,14 +22,13 @@ class ShippingInformation extends StripeJsonModel { name = optString(json, FIELD_NAME); phone = optString(json, FIELD_PHONE); var addr = json[FIELD_ADDRESS]; - address = addr == null - ? null - : new Address.fromJson(addr.cast()); + address = + addr == null ? null : Address.fromJson(addr.cast()); } @override Map toMap() { - Map map = new Map(); + Map map = {}; map[FIELD_NAME] = name; map[FIELD_PHONE] = phone; StripeJsonModel.putStripeJsonModelMapIfNotNull(map, FIELD_ADDRESS, address); diff --git a/lib/model/source.dart b/lib/model/source.dart index aceaa39..e3efefb 100644 --- a/lib/model/source.dart +++ b/lib/model/source.dart @@ -24,7 +24,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { static const String MULTIBANCO = "multibanco"; static const String UNKNOWN = "unknown"; - static final Set MODELED_TYPES = new Set() + static final Set MODELED_TYPES = Set() ..add(CARD) ..add(SEPA_DEBIT); @@ -63,27 +63,27 @@ class Source extends StripeJsonModel implements StripePaymentSource { static const String FIELD_USAGE = "usage"; @override - String id; - int amount; - String clientSecret; - SourceCodeVerification codeVerification; - int created; - String currency; - String typeRaw; - String flow; - bool liveMode; - Map metaData; - SourceOwner owner; - SourceReceiver receiver; - SourceRedirect redirect; - String status; - Map sourceTypeData; - StripeSourceTypeModel sourceTypeModel; - String type; - String usage; + late String id; + int? amount; + String? clientSecret; + SourceCodeVerification? codeVerification; + int? created; + String? currency; + String? typeRaw; + String? flow; + bool? liveMode; + Map? metaData; + SourceOwner? owner; + SourceReceiver? receiver; + SourceRedirect? redirect; + String? status; + Map? sourceTypeData; + StripeSourceTypeModel? sourceTypeModel; + String? type; + String? usage; Source({ - this.id, + this.id = '', this.amount, this.clientSecret, this.codeVerification, @@ -104,13 +104,13 @@ class Source extends StripeJsonModel implements StripePaymentSource { }); Source.fromJson(Map json) { - id = optString(json, FIELD_ID); + id = optString(json, FIELD_ID) ?? ''; amount = optInteger(json, FIELD_AMOUNT); clientSecret = optString(json, FIELD_CLIENT_SECRET); final codeVerf = json[FIELD_CODE_VERIFICATION]; if (codeVerf != null) { codeVerification = - new SourceCodeVerification.fromJson(codeVerf.cast()); + SourceCodeVerification.fromJson(codeVerf.cast()); } created = optInteger( @@ -123,39 +123,35 @@ class Source extends StripeJsonModel implements StripePaymentSource { if (metaDataObj != null) { metaData = metaDataObj.cast(); } else { - metaData = new Map(); + metaData = {}; } final ownerObject = json[FIELD_OWNER]; if (ownerObject != null) { - owner = new SourceOwner.fromJson(ownerObject.cast()); + owner = SourceOwner.fromJson(ownerObject.cast()); } var receiverObject = json[FIELD_RECEIVER]; if (receiverObject != null) { receiver = - new SourceReceiver.fromJson(receiverObject.cast()); + SourceReceiver.fromJson(receiverObject.cast()); } var redirectObject = json[FIELD_REDIRECT]; if (redirectObject != null) { redirect = - new SourceRedirect.fromJson(redirectObject.cast()); + SourceRedirect.fromJson(redirectObject.cast()); } status = asSourceStatus(optString(json, FIELD_STATUS)); - String typeRaw = optString(json, FIELD_TYPE); - if (typeRaw == null) { - // We can't allow this type to be null, as we are using it for a key - // on the JSON object later. - typeRaw = UNKNOWN; - } + String? typeRaw = optString(json, FIELD_TYPE); + // We can't allow this type to be null, as we are using it for a key + // on the JSON object later. + typeRaw ??= UNKNOWN; type = asSourceType(typeRaw); - if (type == null) { - type = UNKNOWN; - } + type ??= UNKNOWN; // Until we have models for all types, keep the original hash and the // model object. The customType variable can be any field, and is not altered by @@ -172,7 +168,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { @override Map toMap() { - Map hashMap = new Map(); + Map hashMap = {}; hashMap[FIELD_ID] = id; hashMap[FIELD_AMOUNT] = amount; hashMap[FIELD_CLIENT_SECRET] = clientSecret; @@ -192,7 +188,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { StripeJsonModel.putStripeJsonModelMapIfNotNull( hashMap, FIELD_REDIRECT, redirect); - hashMap[typeRaw] = sourceTypeData; + hashMap[typeRaw!] = sourceTypeData; hashMap[FIELD_STATUS] = status; hashMap[FIELD_TYPE] = typeRaw; @@ -201,7 +197,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { return hashMap; } - static String asSourceStatus(String sourceStatus) { + static String? asSourceStatus(String? sourceStatus) { if (PENDING == sourceStatus) { return PENDING; } else if (CHARGEABLE == sourceStatus) { @@ -216,7 +212,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { return null; } - static String asSourceType(String sourceType) { + static String? asSourceType(String sourceType) { if (CARD == sourceType) { return CARD; } else if (THREE_D_SECURE == sourceType) { @@ -242,7 +238,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { return null; } - static String asUsage(String usage) { + static String? asUsage(String? usage) { if (REUSABLE == usage) { return REUSABLE; } else if (SINGLE_USE == usage) { @@ -251,7 +247,7 @@ class Source extends StripeJsonModel implements StripePaymentSource { return null; } - static String asSourceFlow(String sourceFlow) { + static String? asSourceFlow(String? sourceFlow) { if (REDIRECT == sourceFlow) { return REDIRECT; } else if (RECEIVER == sourceFlow) { diff --git a/lib/model/source_card_data.dart b/lib/model/source_card_data.dart index b4deb01..a7cd7eb 100644 --- a/lib/model/source_card_data.dart +++ b/lib/model/source_card_data.dart @@ -20,22 +20,22 @@ class SourceCardData extends StripeSourceTypeModel { static const String FIELD_THREE_D_SECURE = "three_d_secure"; static const String FIELD_TOKENIZATION_METHOD = "tokenization_method"; - String addressLine1Check; - String addressZipCheck; - String brand; - String country; - String cvcCheck; - String dynamicLast4; - int expiryMonth; - int expiryYear; - String funding; - String last4; - String threeDSecureStatus; - String tokenizationMethod; + late String addressLine1Check; + late String addressZipCheck; + late String brand; + late String country; + late String cvcCheck; + late String dynamicLast4; + late int expiryMonth; + late int expiryYear; + late String funding; + late String last4; + late String threeDSecureStatus; + late String tokenizationMethod; @override Map toMap() { - Map objectMap = new Map(); + Map objectMap = {}; objectMap[FIELD_ADDRESS_LINE1_CHECK] = addressLine1Check; objectMap[FIELD_ADDRESS_ZIP_CHECK] = addressZipCheck; objectMap[FIELD_BRAND] = brand; diff --git a/lib/model/source_code_verification.dart b/lib/model/source_code_verification.dart index ddfc4d5..c4a2965 100644 --- a/lib/model/source_code_verification.dart +++ b/lib/model/source_code_verification.dart @@ -9,8 +9,8 @@ class SourceCodeVerification extends StripeJsonModel { static const String FIELD_STATUS = "status"; static const int INVALID_ATTEMPTS_REMAINING = -1; - int attemptsRemaining; - String status; + late int attemptsRemaining; + String? status; SourceCodeVerification(this.attemptsRemaining, this.status); @@ -22,7 +22,7 @@ class SourceCodeVerification extends StripeJsonModel { @override Map toMap() { - Map hashMap = new Map(); + Map hashMap = {}; hashMap[FIELD_ATTEMPTS_REMAINING] = attemptsRemaining; if (status != null) { hashMap[FIELD_STATUS] = status; @@ -30,7 +30,7 @@ class SourceCodeVerification extends StripeJsonModel { return hashMap; } - static String _asStatus(String stringStatus) { + static String? _asStatus(String? stringStatus) { if (stringStatus == null) { return null; } else if (PENDING == stringStatus) { diff --git a/lib/model/source_owner.dart b/lib/model/source_owner.dart index 8fc7e5a..64e5444 100644 --- a/lib/model/source_owner.dart +++ b/lib/model/source_owner.dart @@ -14,14 +14,14 @@ class SourceOwner extends StripeJsonModel { static const String FIELD_VERIFIED_NAME = VERIFIED + FIELD_NAME; static const String FIELD_VERIFIED_PHONE = VERIFIED + FIELD_PHONE; - Address address; - String email; - String name; - String phone; - Address verifiedAddress; - String verifiedEmail; - String verifiedName; - String verifiedPhone; + Address? address; + String? email; + String? name; + String? phone; + Address? verifiedAddress; + String? verifiedEmail; + String? verifiedName; + String? verifiedPhone; SourceOwner({ this.address, @@ -55,15 +55,15 @@ class SourceOwner extends StripeJsonModel { @override Map toMap() { - Map hashMap = new Map(); + Map hashMap = {}; if (address != null) { - hashMap[FIELD_ADDRESS] = address.toMap(); + hashMap[FIELD_ADDRESS] = address?.toMap() ?? {}; } hashMap[FIELD_EMAIL] = email; hashMap[FIELD_NAME] = name; hashMap[FIELD_PHONE] = phone; if (verifiedAddress != null) { - hashMap[FIELD_VERIFIED_ADDRESS] = verifiedAddress.toMap(); + hashMap[FIELD_VERIFIED_ADDRESS] = verifiedAddress?.toMap() ?? {}; } hashMap[FIELD_VERIFIED_EMAIL] = verifiedEmail; hashMap[FIELD_VERIFIED_NAME] = verifiedName; diff --git a/lib/model/source_receiver.dart b/lib/model/source_receiver.dart index bd6201f..d1d3e94 100644 --- a/lib/model/source_receiver.dart +++ b/lib/model/source_receiver.dart @@ -7,10 +7,10 @@ class SourceReceiver extends StripeJsonModel { static const String FIELD_AMOUNT_RETURNED = "amount_returned"; // This is not to be confused with the Address object - String address; - int amountCharged; - int amountReceived; - int amountReturned; + String? address; + int? amountCharged; + int? amountReceived; + int? amountReturned; // SourceReceiver({ @@ -29,7 +29,7 @@ class SourceReceiver extends StripeJsonModel { @override Map toMap() { - Map hashMap = new Map(); + Map hashMap = {}; hashMap[FIELD_ADDRESS] = address; hashMap[FIELD_AMOUNT_CHARGED] = amountCharged; diff --git a/lib/model/source_redirect.dart b/lib/model/source_redirect.dart index 9601e91..4a423c5 100644 --- a/lib/model/source_redirect.dart +++ b/lib/model/source_redirect.dart @@ -10,9 +10,9 @@ class SourceRedirect extends StripeJsonModel { static const String FIELD_STATUS = "status"; static const String FIELD_URL = "url"; - String returnUrl; - String status; - String url; + String? returnUrl; + String? status; + String? url; SourceRedirect({ this.returnUrl, @@ -28,7 +28,7 @@ class SourceRedirect extends StripeJsonModel { @override Map toMap() { - Map hashMap = new Map(); + Map hashMap = {}; hashMap[FIELD_RETURN_URL] = returnUrl; hashMap[FIELD_STATUS] = status; hashMap[FIELD_URL] = url; diff --git a/lib/model/stripe_json_model.dart b/lib/model/stripe_json_model.dart index 3e4b18b..eb0a9da 100644 --- a/lib/model/stripe_json_model.dart +++ b/lib/model/stripe_json_model.dart @@ -13,20 +13,22 @@ abstract class StripeJsonModel { } static void putStripeJsonModelMapIfNotNull(Map upperLevelMap, - String key, StripeJsonModel jsonModel) { + String key, StripeJsonModel? jsonModel) { if (jsonModel == null) { return; } upperLevelMap[key] = jsonModel.toMap(); } - static void putStripeJsonModelListIfNotNull(Map upperLevelMap, - String key, List jsonModelList) { + static void putStripeJsonModelListIfNotNull( + Map upperLevelMap, + String key, + List? jsonModelList) { if (jsonModelList == null) { return; } - List> mapList = new List(); + List> mapList = []; for (int i = 0; i < jsonModelList.length; i++) { mapList.add(jsonModelList[i].toMap()); } diff --git a/lib/model/stripe_json_utils.dart b/lib/model/stripe_json_utils.dart index fd09b73..7f03c4d 100644 --- a/lib/model/stripe_json_utils.dart +++ b/lib/model/stripe_json_utils.dart @@ -1,70 +1,60 @@ const String EMPTY = ""; const String NULL = "null"; -/** - * Calls through to {@link JSONObject#optString(String)} while safely - * converting the raw string "null" and the empty string to {@code null}. Will not throw - * an exception if the field isn't found. - * - * @param jsonObject the input object - * @param fieldName the optional field name - * @return the value stored in the field, or {@code null} if the field isn't present - */ -String optString(Map json, String fieldName) { +/// Calls through to {@link JSONObject#optString(String)} while safely +/// converting the raw string "null" and the empty string to {@code null}. Will not throw +/// an exception if the field isn't found. +/// +/// @param jsonObject the input object +/// @param fieldName the optional field name +/// @return the value stored in the field, or {@code null} if the field isn't present +String? optString(Map json, String fieldName) { return nullIfNullOrEmpty(json[fieldName] ?? ""); } -/** - * Calls through to {@link JSONObject#optInt(String)} only in the case that the - * key exists. This returns {@code null} if the key is not in the object. - * - * @param jsonObject the input object - * @param fieldName the required field name - * @return the value stored in the requested field, or {@code null} if the key is not present - */ -bool optBoolean(Map json, String fieldName) { - return json[fieldName] ?? false; +/// Calls through to {@link JSONObject#optInt(String)} only in the case that the +/// key exists. This returns {@code null} if the key is not in the object. +/// +/// @param jsonObject the input object +/// @param fieldName the required field name +/// @return the value stored in the requested field, or {@code null} if the key is not present +bool? optBoolean(Map json, String fieldName) { + return json[fieldName]; } -/** - * Calls through to {@link JSONObject#optInt(String)} only in the case that the - * key exists. This returns {@code null} if the key is not in the object. - * - * @param jsonObject the input object - * @param fieldName the required field name - * @return the value stored in the requested field, or {@code null} if the key is not present - */ -int optInteger(Map json, String fieldName) { - return json[fieldName] ?? 0; +/// Calls through to {@link JSONObject#optInt(String)} only in the case that the +/// key exists. This returns {@code null} if the key is not in the object. +/// +/// @param jsonObject the input object +/// @param fieldName the required field name +/// @return the value stored in the requested field, or {@code null} if the key is not present +int? optInteger(Map json, String fieldName) { + return json[fieldName]; } -/** - * Calls through to {@link JSONObject#optString(String)} while safely converting - * the raw string "null" and the empty string to {@code null}, along with any value that isn't - * a two-character string. - * @param jsonObject the object from which to retrieve the country code - * @param fieldName the name of the field in which the country code is stored - * @return a two-letter country code if one is found, or {@code null} - */ -String optCountryCode(Map json, String fieldName) { - String value = optString(json, fieldName); +/// Calls through to {@link JSONObject#optString(String)} while safely converting +/// the raw string "null" and the empty string to {@code null}, along with any value that isn't +/// a two-character string. +/// @param jsonObject the object from which to retrieve the country code +/// @param fieldName the name of the field in which the country code is stored +/// @return a two-letter country code if one is found, or {@code null} +String? optCountryCode(Map json, String fieldName) { + String? value = optString(json, fieldName); if (value != null && value.length == 2) { return value; } return null; } -/** - * Calls through to {@link JSONObject#optString(String)} while safely converting - * the raw string "null" and the empty string to {@code null}, along with any value that isn't - * a three-character string. - * @param jsonObject the object from which to retrieve the currency code - * @param fieldName the name of the field in which the currency code is stored - * @return a three-letter currency code if one is found, or {@code null} - */ +/// Calls through to {@link JSONObject#optString(String)} while safely converting +/// the raw string "null" and the empty string to {@code null}, along with any value that isn't +/// a three-character string. +/// @param jsonObject the object from which to retrieve the currency code +/// @param fieldName the name of the field in which the currency code is stored +/// @return a three-letter currency code if one is found, or {@code null} -String optCurrency(Map json, String fieldName) { - String value = optString(json, fieldName); +String? optCurrency(Map json, String fieldName) { + String? value = optString(json, fieldName); if (value != null && value.length == 3) { return value; } @@ -72,7 +62,7 @@ String optCurrency(Map json, String fieldName) { } /// -String nullIfNullOrEmpty(String possibleNull) { +String? nullIfNullOrEmpty(String possibleNull) { return ((NULL == possibleNull) || (EMPTY == possibleNull)) ? null : possibleNull; diff --git a/lib/model/stripe_source_type_model.dart b/lib/model/stripe_source_type_model.dart index 7dcdcc1..81bbc5b 100644 --- a/lib/model/stripe_source_type_model.dart +++ b/lib/model/stripe_source_type_model.dart @@ -1,8 +1,8 @@ import 'stripe_json_model.dart'; abstract class StripeSourceTypeModel extends StripeJsonModel { - Map additionalFields = new Map(); - Set standardFields = new Set(); + Map additionalFields = {}; + Set standardFields = Set(); static const String NULL = "null"; void addStandardFields(List fields) { @@ -10,7 +10,7 @@ abstract class StripeSourceTypeModel extends StripeJsonModel { } static void putAdditionalFieldsIntoMap( - Map map, Map additionalFields) { + Map? map, Map? additionalFields) { if (map == null || additionalFields == null || additionalFields.isEmpty) { return; } diff --git a/lib/model/token.dart b/lib/model/token.dart index 747a208..4b2d2dd 100644 --- a/lib/model/token.dart +++ b/lib/model/token.dart @@ -22,13 +22,13 @@ class Token implements StripePaymentSource { @override final String id; - final String type; + final String? type; final DateTime created; final bool liveMode; - final bool used; + final bool? used; //final BankAccount bankAccount; - final StripeCard card; + final StripeCard? card; Token._internal( this.id, @@ -40,22 +40,25 @@ class Token implements StripePaymentSource { }); factory Token(Map json) { - String tokenId = optString(json, FIELD_ID); - int createdTimeStamp = optInteger(json, FIELD_CREATED); - bool liveMode = optBoolean(json, FIELD_LIVEMODE); - String tokenType = asTokenType(optString(json, FIELD_TYPE)); - bool used = optBoolean(json, FIELD_USED); + String? tokenId = optString(json, FIELD_ID); + int? createdTimeStamp = optInteger(json, FIELD_CREATED); + bool? liveMode = optBoolean(json, FIELD_LIVEMODE); + String? tokenType = asTokenType(optString(json, FIELD_TYPE)); + bool? used = optBoolean(json, FIELD_USED); + + late Token token; if (tokenId == null || createdTimeStamp == null || liveMode == null) { - return null; + token = Token._internal("-1", false, DateTime.now(), "", false); + return token; } - DateTime date = new DateTime.fromMillisecondsSinceEpoch(2000); + DateTime date = DateTime.fromMillisecondsSinceEpoch(2000); - Token token; if (Token.TYPE_BANK_ACCOUNT == tokenType) { final bankAccountObject = json[FIELD_BANK_ACCOUNT]; if (bankAccountObject == null) { - return null; + token = Token._internal("-1", false, DateTime.now(), "", false); + return token; } //BankAccount bankAccount = BankAccount.fromJson(bankAccountObject); //token = new Token(tokenId, liveMode, date, used, bankAccount); @@ -63,25 +66,24 @@ class Token implements StripePaymentSource { } else if (Token.TYPE_CARD == tokenType) { final cardObject = json[FIELD_CARD]; if (cardObject == null) { - return null; + token = Token._internal("-1", false, DateTime.now(), "", false); + return token; } StripeCard card = StripeCard.fromJson(cardObject.cast()); - token = new Token._internal(tokenId, liveMode, date, tokenType, used, - card: card); + token = + Token._internal(tokenId, liveMode, date, tokenType, used, card: card); } else if (Token.TYPE_PII == tokenType || Token.TYPE_ACCOUNT == tokenType) { - token = new Token._internal(tokenId, liveMode, date, tokenType, used); + token = Token._internal(tokenId, liveMode, date, tokenType, used); } return token; } - /** - * Converts an unchecked String value to a {@link TokenType} or {@code null}. - * - * @param possibleTokenType a String that might match a {@link TokenType} or be empty - * @return {@code null} if the input is blank or otherwise does not match a {@link TokenType}, - * else the appropriate {@link TokenType}. - */ - static String asTokenType(String possibleTokenType) { + /// Converts an unchecked String value to a {@link TokenType} or {@code null}. + /// + /// @param possibleTokenType a String that might match a {@link TokenType} or be empty + /// @return {@code null} if the input is blank or otherwise does not match a {@link TokenType}, + /// else the appropriate {@link TokenType}. + static String? asTokenType(String? possibleTokenType) { if (possibleTokenType == null || possibleTokenType.trim().isEmpty) { return null; } diff --git a/lib/stripe_api.dart b/lib/stripe_api.dart index 5ea352f..1496504 100644 --- a/lib/stripe_api.dart +++ b/lib/stripe_api.dart @@ -19,25 +19,25 @@ export 'model/source.dart'; export 'model/token.dart'; class Stripe { - static Stripe _instance; + static Stripe? _instance; - final StripeApiHandler _apiHandler = new StripeApiHandler(); + final StripeApiHandler _apiHandler = StripeApiHandler(); final String publishableKey; - String stripeAccount; + //String stripeAccount; Stripe._internal(this.publishableKey); static void init(String publishableKey) { if (_instance == null) { _validateKey(publishableKey); - _instance = new Stripe._internal(publishableKey); + _instance = Stripe._internal(publishableKey); } } - static Stripe get instance { + static Stripe? get instance { if (_instance == null) { - throw new Exception( + throw Exception( "Attempted to get instance of Stripe without initialization"); } return _instance; @@ -50,19 +50,19 @@ class Stripe { return token; } - Future createBankAccountToken(StripeCard card) async { + Future createBankAccountToken(StripeCard card) async { return null; } - static void _validateKey(String publishableKey) { + static void _validateKey(String? publishableKey) { if (publishableKey == null || publishableKey.isEmpty) { - throw new Exception("Invalid Publishable Key: " + + throw Exception("Invalid Publishable Key: " + "You must use a valid publishable key to create a token. " + "For more info, see https://stripe.com/docs/stripe.js."); } if (publishableKey.startsWith("sk_")) { - throw new Exception("Invalid Publishable Key: " + + throw Exception("Invalid Publishable Key: " + "You are using a secret key to create a token, " + "instead of the publishable one. For more info, " + "see https://stripe.com/docs/stripe.js"); @@ -71,11 +71,11 @@ class Stripe { } class CustomerSession { - static final int KEY_REFRESH_BUFFER_IN_SECONDS = 30; + static const int KEY_REFRESH_BUFFER_IN_SECONDS = 30; - static CustomerSession _instance; + static CustomerSession? _instance; - final StripeApiHandler _apiHandler = new StripeApiHandler(); + final StripeApiHandler _apiHandler = StripeApiHandler(); final EphemeralKeyManager _keyManager; @@ -88,8 +88,8 @@ class CustomerSession { static void initCustomerSession(EphemeralKeyProvider provider) { if (_instance == null) { final manager = - new EphemeralKeyManager(provider, KEY_REFRESH_BUFFER_IN_SECONDS); - _instance = new CustomerSession._internal(manager); + EphemeralKeyManager(provider, KEY_REFRESH_BUFFER_IN_SECONDS); + _instance = CustomerSession._internal(manager); } } @@ -103,9 +103,9 @@ class CustomerSession { /// /// /// - static CustomerSession get instance { + static CustomerSession? get instance { if (_instance == null) { - throw new Exception( + throw Exception( "Attempted to get instance of CustomerSession without initialization."); } return _instance; @@ -116,8 +116,8 @@ class CustomerSession { /// Future retrieveCurrentCustomer() async { final key = await _keyManager.retrieveEphemeralKey(); - final customer = - await _apiHandler.retrieveCustomer(key.customerId, key.secret); + final customer = await _apiHandler.retrieveCustomer( + key?.customerId ?? '', key?.secret ?? ''); return customer; } @@ -127,7 +127,7 @@ class CustomerSession { Future addCustomerSource(String sourceId) async { final key = await _keyManager.retrieveEphemeralKey(); final source = await _apiHandler.addCustomerSource( - key.customerId, sourceId, key.secret); + key?.customerId ?? '', sourceId, key?.secret ?? ''); return source; } @@ -137,7 +137,7 @@ class CustomerSession { Future deleteCustomerSource(String sourceId) async { final key = await _keyManager.retrieveEphemeralKey(); final deleted = await _apiHandler.deleteCustomerSource( - key.customerId, sourceId, key.secret); + key?.customerId ?? '', sourceId, key?.secret ?? ''); return deleted; } @@ -147,7 +147,7 @@ class CustomerSession { Future updateCustomerDefaultSource(String sourceId) async { final key = await _keyManager.retrieveEphemeralKey(); final customer = await _apiHandler.updateCustomerDefaultSource( - key.customerId, sourceId, key.secret); + key?.customerId ?? '', sourceId, key?.secret ?? ''); return customer; } @@ -158,7 +158,7 @@ class CustomerSession { ShippingInformation shippingInfo) async { final key = await _keyManager.retrieveEphemeralKey(); final customer = await _apiHandler.updateCustomerShippingInformation( - key.customerId, shippingInfo, key.secret); + key?.customerId ?? '', shippingInfo, key?.secret ?? ''); return customer; } } diff --git a/lib/stripe_api_handler.dart b/lib/stripe_api_handler.dart index e449a83..4cb1c62 100644 --- a/lib/stripe_api_handler.dart +++ b/lib/stripe_api_handler.dart @@ -36,7 +36,7 @@ class StripeApiHandler { static final StripeApiHandler _singleton = StripeApiHandler._internal(); - final http.Client _client = new http.Client(); + final http.Client _client = http.Client(); factory StripeApiHandler() { return _singleton; @@ -49,11 +49,11 @@ class StripeApiHandler { /// Future createToken( Map params, String publishableKey) async { - final url = "$LIVE_API_PATH/tokens"; - final options = new RequestOptions(publishableApiKey: publishableKey); + const url = "$LIVE_API_PATH/tokens"; + final options = RequestOptions(publishableApiKey: publishableKey); final response = await _getStripeResponse(RequestMethod.post, url, options, params: params); - final token = new Token(response); + final token = Token(response); return token; } @@ -62,7 +62,7 @@ class StripeApiHandler { /// Future retrieveCustomer(String customerId, String secret) async { final String url = "$LIVE_API_PATH/customers/$customerId"; - final options = new RequestOptions(publishableApiKey: secret); + final options = RequestOptions(publishableApiKey: secret); final response = await _getStripeResponse(RequestMethod.get, url, options); final customer = Customer.fromJson(response); return customer; @@ -74,7 +74,7 @@ class StripeApiHandler { Future addCustomerSource( String customerId, String sourceId, String secret) async { final String url = "$LIVE_API_PATH/customers/$customerId/sources"; - final options = new RequestOptions(publishableApiKey: secret); + final options = RequestOptions(publishableApiKey: secret); final response = await _getStripeResponse( RequestMethod.post, url, @@ -91,7 +91,7 @@ class StripeApiHandler { Future deleteCustomerSource( String customerId, String sourceId, String secret) async { final String url = "$LIVE_API_PATH/customers/$customerId/sources/$sourceId"; - final options = new RequestOptions(publishableApiKey: secret); + final options = RequestOptions(publishableApiKey: secret); final response = await _getStripeResponse( RequestMethod.delete, url, @@ -107,7 +107,7 @@ class StripeApiHandler { Future updateCustomerDefaultSource( String customerId, String sourceId, String secret) async { final String url = "$LIVE_API_PATH/customers/$customerId"; - final options = new RequestOptions(publishableApiKey: secret); + final options = RequestOptions(publishableApiKey: secret); final response = await _getStripeResponse( RequestMethod.post, url, @@ -124,7 +124,7 @@ class StripeApiHandler { Future updateCustomerShippingInformation(String customerId, ShippingInformation shippingInfo, String secret) async { final String url = "$LIVE_API_PATH/customers/$customerId"; - final options = new RequestOptions(publishableApiKey: secret); + final options = RequestOptions(publishableApiKey: secret); final response = await _getStripeResponse( RequestMethod.post, url, @@ -140,7 +140,7 @@ class StripeApiHandler { /// Future> _getStripeResponse( RequestMethod method, final String url, final RequestOptions options, - {final Map params}) async { + {final Map? params}) async { final headers = _headers(options: options); http.Response response; @@ -148,7 +148,7 @@ class StripeApiHandler { switch (method) { case RequestMethod.get: String fUrl = url; - if (params != null && params.length > 0) { + if (params != null && params.isNotEmpty) { fUrl = "$url?${_encodeMap(params)}"; } response = await _client.get(Uri.parse(fUrl), headers: headers); @@ -166,7 +166,7 @@ class StripeApiHandler { response = await _client.delete(Uri.parse(url), headers: headers); break; default: - throw new Exception("Request Method: $method not implemented"); + throw Exception("Request Method: $method not implemented"); } final requestId = response.headers[HEADER_KEY_REQUEST_ID]; @@ -176,15 +176,15 @@ class StripeApiHandler { try { resp = json.decode(response.body); } catch (error) { - final stripeError = StripeAPIError(requestId, + final stripeError = StripeAPIError(requestId ?? '', {StripeAPIError.FIELD_MESSAGE: MALFORMED_RESPONSE_MESSAGE}); - throw new StripeAPIException(stripeError); + throw StripeAPIException(stripeError); } if (statusCode < 200 || statusCode >= 300) { final Map errBody = resp[FIELD_ERROR]; - final stripeError = StripeAPIError(requestId, errBody); - throw new StripeAPIException(stripeError); + final stripeError = StripeAPIError(requestId ?? '', errBody); + throw StripeAPIException(stripeError); } else { return resp; } @@ -193,8 +193,8 @@ class StripeApiHandler { /// /// /// - static Map _headers({RequestOptions options}) { - final Map headers = new Map(); + static Map _headers({RequestOptions? options}) { + final Map headers = {}; headers["Accept-Charset"] = CHARSET; headers["Accept"] = "application/json"; headers["Content-Type"] = "application/x-www-form-urlencoded"; @@ -205,7 +205,7 @@ class StripeApiHandler { } // debug headers - Map propertyMap = new Map(); + Map propertyMap = {}; propertyMap["os.name"] = defaultTargetPlatform.toString(); //propertyMap["os.version"] = String.valueOf(Build.VERSION.SDK_INT)); propertyMap["bindings.version"] = VERSION_NAME; @@ -215,16 +215,16 @@ class StripeApiHandler { headers["X-Stripe-Client-User-Agent"] = json.encode(propertyMap); if (options != null) { - if (options.apiVersion != null) { + if (options.apiVersion.isNotEmpty) { headers["Stripe-Version"] = options.apiVersion; } if (options.stripeAccount != null) { - headers["Stripe-Account"] = options.stripeAccount; + headers["Stripe-Account"] = options.stripeAccount ?? ''; } if (options.idempotencyKey != null) { - headers["Idempotency-Key"] = options.idempotencyKey; + headers["Idempotency-Key"] = options.idempotencyKey ?? ''; } } @@ -239,7 +239,7 @@ class StripeApiHandler { } static String _urlEncodeMap(dynamic data) { - StringBuffer urlData = new StringBuffer(""); + StringBuffer urlData = StringBuffer(); bool first = true; void urlEncode(dynamic sub, String path) { if (sub is List) { @@ -249,7 +249,7 @@ class StripeApiHandler { } else if (sub is Map) { sub.forEach((k, v) { if (path == "") { - urlEncode(v, "${Uri.encodeQueryComponent(k)}"); + urlEncode(v, Uri.encodeQueryComponent(k)); } else { urlEncode(v, "$path%5B${Uri.encodeQueryComponent(k)}%5D"); } @@ -273,11 +273,11 @@ class RequestOptions { static const String TYPE_JSON = "json_data"; final String apiVersion; - final String guid; - final String idempotencyKey; - final String publishableApiKey; - final String requestType; - final String stripeAccount; + final String? guid; + final String? idempotencyKey; + final String? publishableApiKey; + final String? requestType; + final String? stripeAccount; RequestOptions({ this.apiVersion = API_VERSION, diff --git a/lib/stripe_error.dart b/lib/stripe_error.dart index 0270447..3c90da7 100644 --- a/lib/stripe_error.dart +++ b/lib/stripe_error.dart @@ -9,14 +9,14 @@ class StripeAPIError { static const String FIELD_MESSAGE = "message"; static const String FIELD_PARAM = "param"; - final String requestId; - final String type; - final String charge; - final String code; - final String declineCode; - final String docUrl; - final String message; - final String param; + final String? requestId; + final String? type; + final String? charge; + final String? code; + final String? declineCode; + final String? docUrl; + final String? message; + final String? param; StripeAPIError._internal( this.requestId, @@ -38,7 +38,7 @@ class StripeAPIError { final message = optString(json, FIELD_MESSAGE); final param = optString(json, FIELD_PARAM); - return new StripeAPIError._internal( + return StripeAPIError._internal( requestId, type, charge, @@ -53,8 +53,8 @@ class StripeAPIError { class StripeAPIException implements Exception { final StripeAPIError error; - final String requestId; - final String message; + final String? requestId; + final String? message; StripeAPIException(this.error) : requestId = error.requestId, @@ -62,6 +62,6 @@ class StripeAPIException implements Exception { @override String toString() { - return message; + return message ?? 'null'; } } diff --git a/lib/stripe_network_utils.dart b/lib/stripe_network_utils.dart index 5249331..9f3f96c 100644 --- a/lib/stripe_network_utils.dart +++ b/lib/stripe_network_utils.dart @@ -1,9 +1,7 @@ -/** - * Remove null values from a map. This helps with JSON conversion and validation. - * - * @param mapToEdit a {@link Map} from which to remove the keys that have {@code null} values - */ -void removeNullAndEmptyParams(Map mapToEdit) { +/// Remove null values from a map. This helps with JSON conversion and validation. +/// +/// @param mapToEdit a {@link Map} from which to remove the keys that have {@code null} values +void removeNullAndEmptyParams(Map mapToEdit) { // Remove all null values; they cause validation errors final keys = mapToEdit.keys.toList(growable: false); for (String key in keys) { @@ -15,7 +13,7 @@ void removeNullAndEmptyParams(Map mapToEdit) { mapToEdit.remove(key); } } else if (value is Map) { - removeNullAndEmptyParams(value); + removeNullAndEmptyParams(value as Map); } } } diff --git a/lib/stripe_text_utils.dart b/lib/stripe_text_utils.dart index 99d8e85..cb2b2d5 100644 --- a/lib/stripe_text_utils.dart +++ b/lib/stripe_text_utils.dart @@ -7,48 +7,42 @@ const String HEX_ARRAY = "0123456789ABCDEF"; /// @param value an input string that may or may not be entirely whitespace /// @return {@code null} if the string is entirely whitespace, otherwise the input value /// -String nullIfBlank(String value) { +String? nullIfBlank(String value) { if (isBlank(value)) { return null; } return value; } -/** - * A checker for whether or not the input value is entirely whitespace. This is slightly more - * aggressive than the android TextUtils#isEmpty method, which only returns true for - * {@code null} or {@code ""}. - * - * @param value a possibly blank input string value - * @return {@code true} if and only if the value is all whitespace, {@code null}, or empty - */ -bool isBlank(String value) { +/// A checker for whether or not the input value is entirely whitespace. This is slightly more +/// aggressive than the android TextUtils#isEmpty method, which only returns true for +/// {@code null} or {@code ""}. +/// +/// @param value a possibly blank input string value +/// @return {@code true} if and only if the value is all whitespace, {@code null}, or empty +bool isBlank(String? value) { return value == null || value.trim().length == 0; } -/** - * Converts a card number that may have spaces between the numbers into one without any spaces. - * Note: method does not check that all characters are digits or spaces. - * - * @param cardNumberWithSpaces a card number, for instance "4242 4242 4242 4242" - * @return the input number minus any spaces, for instance "4242424242424242". - * Returns {@code null} if the input was {@code null} or all spaces. - */ -String removeSpacesAndHyphens(String cardNumberWithSpaces) { +/// Converts a card number that may have spaces between the numbers into one without any spaces. +/// Note: method does not check that all characters are digits or spaces. +/// +/// @param cardNumberWithSpaces a card number, for instance "4242 4242 4242 4242" +/// @return the input number minus any spaces, for instance "4242424242424242". +/// Returns {@code null} if the input was {@code null} or all spaces. +String? removeSpacesAndHyphens(String cardNumberWithSpaces) { if (isBlank(cardNumberWithSpaces)) { return null; } - return cardNumberWithSpaces.replaceAll(new RegExp(r"\s+|\-+"), ""); + return cardNumberWithSpaces.replaceAll(RegExp(r"\s+|\-+"), ""); } -/** - * Check to see if the input number has any of the given prefixes. - * - * @param number the number to test - * @param prefixes the prefixes to test against - * @return {@code true} if number begins with any of the input prefixes - */ -bool hasAnyPrefix(String number, List prefixes) { +/// Check to see if the input number has any of the given prefixes. +/// +/// @param number the number to test +/// @param prefixes the prefixes to test against +/// @return {@code true} if number begins with any of the input prefixes +bool hasAnyPrefix(String? number, List prefixes) { if (number == null) { return false; } diff --git a/lib/text_utils.dart b/lib/text_utils.dart index 63028fe..3823afc 100644 --- a/lib/text_utils.dart +++ b/lib/text_utils.dart @@ -1,17 +1,17 @@ -bool isDigit(String s) { +bool isDigit(String? s) { if (s == null) { return false; } return int.tryParse(s) != null; } -bool isDigitsOnly(String s) { +bool isDigitsOnly(String? s) { if (s == null) { return false; } return int.tryParse(s) != null; } -int getNumericValue(String s) { +int? getNumericValue(String s) { return int.tryParse(s); } diff --git a/pubspec.yaml b/pubspec.yaml index 79cdd6c..9cdfaab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ author: Muhammad Ahmed homepage: https://github.com/Techie-Qabila/stripe_api environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: From b02a50f78a91999f813a0e28e7dbb6bef5f62bb7 Mon Sep 17 00:00:00 2001 From: Iner Garcia Rodriguez Date: Fri, 14 Jan 2022 22:20:43 -0500 Subject: [PATCH 2/2] Null security migration of the example --- example/lib/main.dart | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index fe32b78..3aa4d4d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,7 +18,6 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { - final TextEditingController controller = new CreditCardMaskedTextController(); @override @@ -76,7 +75,8 @@ class _MyAppState extends State { void _getCustomer() async { try { - final customer = await CustomerSession.instance.retrieveCurrentCustomer(); + final customer = + await CustomerSession.instance!.retrieveCurrentCustomer(); print(customer); } catch (error) { print(error); @@ -91,9 +91,9 @@ class _MyAppState extends State { StripeCard card = new StripeCard( number: '4242 4242 4242 4242', cvc: '713', expMonth: 5, expYear: 2019); card.name = 'Jhonny Bravo'; - Stripe.instance.createCardToken(card).then((c) { + Stripe.instance!.createCardToken(card).then((c) { print(c); - return CustomerSession.instance.addCustomerSource(c.id); + return CustomerSession.instance!.addCustomerSource(c.id); }).then((source) { print(source); }).catchError((error) { @@ -103,10 +103,11 @@ class _MyAppState extends State { void _changeDefaultCard() async { try { - final customer = await CustomerSession.instance.retrieveCurrentCustomer(); + final customer = + await CustomerSession.instance!.retrieveCurrentCustomer(); final card = customer.sources[1].asCard(); final v = - await CustomerSession.instance.updateCustomerDefaultSource(card.id); + await CustomerSession.instance!.updateCustomerDefaultSource(card!.id); print(v); } catch (error) { print(error); @@ -115,17 +116,18 @@ class _MyAppState extends State { void _deleteCard() async { try { - final customer = await CustomerSession.instance.retrieveCurrentCustomer(); - String id; + final customer = + await CustomerSession.instance!.retrieveCurrentCustomer(); + late String id; for (var c in customer.sources) { - StripeCard card = c.asCard(); + StripeCard? card = c.asCard(); if (card != null) { id = card.id; break; } } - final v = await CustomerSession.instance.deleteCustomerSource(id); + final v = await CustomerSession.instance!.deleteCustomerSource(id); print(v); } catch (error) { print(error); @@ -153,7 +155,7 @@ class _MyAppState extends State { } Map _getHeaders( - {String accessToken, + {required String accessToken, String acceptType = ContentTypeJson, String contentType = ContentTypeJson}) { final Map headers = new Map(); @@ -173,7 +175,7 @@ class _MyAppState extends State { class CardItem extends StatelessWidget { final StripeCard card; - const CardItem({Key key, this.card}) : super(key: key); + const CardItem({Key? key, required this.card}) : super(key: key); @override Widget build(BuildContext context) {