CW-254-proper-bitcoin-address-validation-in-exchange-screen (#900)

* feat: Proper Bitcoin address validation in exchange screen

* fix: use custom validation in addition to RegEx to make sure all address cases are validated

- for cases like P2SH addresses starting with a 3, which are not validated by bitcoin_flutter functions

* feat: add bitcoin_flutter to root project

* refactor: improve conditional isValid return chain
This commit is contained in:
Rafael Saes 2023-05-15 09:39:00 -03:00 committed by GitHub
parent 7fa7c45c0c
commit 0231298381
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 23 deletions

View file

@ -1,4 +1,4 @@
import 'package:flutter/foundation.dart'; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/validator.dart'; import 'package:cake_wallet/core/validator.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
@ -7,6 +7,9 @@ class AddressValidator extends TextValidator {
AddressValidator({required CryptoCurrency type}) AddressValidator({required CryptoCurrency type})
: super( : super(
errorMessage: S.current.error_text_address, errorMessage: S.current.error_text_address,
useAdditionalValidation: type == CryptoCurrency.btc
? bitcoin.Address.validateAddress
: null,
pattern: getPattern(type), pattern: getPattern(type),
length: getLength(type)); length: getLength(type));
@ -18,8 +21,7 @@ class AddressValidator extends TextValidator {
return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$' return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
'|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$'; '|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
case CryptoCurrency.btc: case CryptoCurrency.btc:
return '^1[0-9a-zA-Z]{32}\$|^1[0-9a-zA-Z]{33}\$|^3[0-9a-zA-Z]{32}\$' return '^3[0-9a-zA-Z]{32}\$|^3[0-9a-zA-Z]{33}\$|^bc1[0-9a-zA-Z]{59}\$';
'|^3[0-9a-zA-Z]{33}\$|^bc1[0-9a-zA-Z]{39}\$|^bc1[0-9a-zA-Z]{59}\$';
case CryptoCurrency.nano: case CryptoCurrency.nano:
return '[0-9a-zA-Z_]'; return '[0-9a-zA-Z_]';
case CryptoCurrency.usdc: case CryptoCurrency.usdc:
@ -63,7 +65,7 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.bch: case CryptoCurrency.bch:
case CryptoCurrency.bnb: case CryptoCurrency.bnb:
return '[0-9a-zA-Z]'; return '[0-9a-zA-Z]';
case CryptoCurrency.hbar: case CryptoCurrency.hbar:
return '[0-9a-zA-Z.]'; return '[0-9a-zA-Z.]';
case CryptoCurrency.zaddr: case CryptoCurrency.zaddr:
return '^zs[0-9a-zA-Z]{75}'; return '^zs[0-9a-zA-Z]{75}';
@ -165,9 +167,9 @@ class AddressValidator extends TextValidator {
return [34]; return [34];
case CryptoCurrency.hbar: case CryptoCurrency.hbar:
return [4, 5, 6, 7, 8, 9, 10, 11]; return [4, 5, 6, 7, 8, 9, 10, 11];
case CryptoCurrency.xvg: case CryptoCurrency.xvg:
return [34]; return [34];
case CryptoCurrency.zen: case CryptoCurrency.zen:
return [35]; return [35];
case CryptoCurrency.zaddr: case CryptoCurrency.zaddr:
return null; return null;

View file

@ -1,24 +1,26 @@
import 'package:flutter/foundation.dart';
abstract class Validator<T> { abstract class Validator<T> {
Validator({required this.errorMessage}); Validator({required this.errorMessage, this.useAdditionalValidation});
final String errorMessage; final String errorMessage;
final bool Function(T)? useAdditionalValidation;
bool isValid(T? value); bool isValid(T? value);
String? call(T? value) => !isValid(value) ? errorMessage : null; String? call(T? value) => !isValid(value) ? errorMessage : null;
} }
class TextValidator extends Validator<String> { class TextValidator extends Validator<String> {
TextValidator( TextValidator({
{this.minLength, bool Function(String)? useAdditionalValidation,
this.maxLength, this.minLength,
this.pattern, this.maxLength,
String errorMessage = '', this.pattern,
this.length, String errorMessage = '',
this.isAutovalidate = false}) this.length,
: super(errorMessage: errorMessage); this.isAutovalidate = false,
}) : super(
errorMessage: errorMessage,
useAdditionalValidation: useAdditionalValidation);
final int? minLength; final int? minLength;
final int? maxLength; final int? maxLength;
@ -32,11 +34,26 @@ class TextValidator extends Validator<String> {
return isAutovalidate ? true : false; return isAutovalidate ? true : false;
} }
return value.length > (minLength ?? 0) && final greaterThanMinLength = value.length > (minLength ?? 0);
(length?.contains(value.length) ?? true) && if (!greaterThanMinLength) return false;
((maxLength ?? 0) > 0 ? (value.length <= maxLength!) : true) &&
(pattern != null ? match(value) : true); final lengthMatched = length?.contains(value.length) ?? true;
if (!lengthMatched) return false;
final lowerThanMaxLength =
(maxLength ?? 0) > 0 ? (value.length <= maxLength!) : true;
if (!lowerThanMaxLength) return false;
if (pattern == null) return true;
final valueMatched = match(value);
final valueValidated = useAdditionalValidation != null
? useAdditionalValidation!(value) || valueMatched
: valueMatched;
return valueValidated;
} }
bool match(String value) => pattern != null ? RegExp(pattern!).hasMatch(value) : false; bool match(String value) =>
pattern != null ? RegExp(pattern!).hasMatch(value) : false;
} }

View file

@ -81,6 +81,10 @@ dependencies:
path_provider_android: 2.0.24 path_provider_android: 2.0.24
shared_preferences_android: 2.0.17 shared_preferences_android: 2.0.17
url_launcher_android: 6.0.24 url_launcher_android: 6.0.24
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: