Skip to content

fix(authenticator): make phone number mandatory when "required" option is specified #5794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3a98a38
added checks for country code against the maximum length of number in…
Sep 27, 2024
3d8f70e
added a map of dial codes to number lengths, and check the input phon…
Sep 30, 2024
4173bba
removed files from building example app
Oct 1, 2024
259f4eb
removed files from \sandbox
Oct 1, 2024
8ef9d66
removed files from sandbox
Oct 1, 2024
d765390
updating formatting
Oct 1, 2024
184b10c
added checks for country code against the maximum length of number in…
Sep 27, 2024
0332e29
added a map of dial codes to number lengths, and check the input phon…
Sep 30, 2024
9f0439a
removed files from building example app
Oct 1, 2024
7da3d51
removed files from \sandbox
Oct 1, 2024
3d28992
removed files from sandbox
Oct 1, 2024
9d9498a
updating formatting
Oct 1, 2024
c616675
rewrote functions for better code standards, and rewrote duplicated test
ekjotmultani Jan 4, 2025
6d36e60
Merge branch 'fix/authenticator/phone-validator' of https://github.co…
ekjotmultani Jan 5, 2025
31a91cf
added checks for country code against the maximum length of number in…
Sep 27, 2024
ba417be
added a map of dial codes to number lengths, and check the input phon…
Sep 30, 2024
c157f28
removed files from building example app
Oct 1, 2024
08b3b54
removed files from \sandbox
Oct 1, 2024
faef952
removed files from sandbox
Oct 1, 2024
94c2bb4
updating formatting
Oct 1, 2024
23e0c1c
added checks for country code against the maximum length of number in…
Sep 27, 2024
babdfb5
added a map of dial codes to number lengths, and check the input phon…
Sep 30, 2024
0d6733e
removed files from building example app
Oct 1, 2024
a6987d9
removed files from \sandbox
Oct 1, 2024
6460570
removed files from sandbox
Oct 1, 2024
5542a44
updating formatting
Oct 1, 2024
d954252
Merge branch 'fix/authenticator/phone-validator' of https://github.co…
ekjotmultani Jan 6, 2025
74dff61
Merge branch 'main' into fix/authenticator/phone-validator
ekjotmultani Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:amplify_authenticator/src/keys.dart';
import 'package:amplify_authenticator/src/l10n/dial_code_resolver.dart';
import 'package:amplify_authenticator/src/utils/breakpoint.dart';
import 'package:amplify_authenticator/src/utils/dial_code.dart';
import 'package:amplify_authenticator/src/utils/dial_code_to_length.dart';
import 'package:amplify_authenticator/src/widgets/authenticator_input_config.dart';
import 'package:amplify_authenticator/src/widgets/form_field.dart';
import 'package:collection/collection.dart';
Expand Down Expand Up @@ -47,12 +48,22 @@ mixin AuthenticatorPhoneFieldMixin<FieldType extends Enum,
return phoneNumber?.ensureStartsWith('+${state.dialCode.value}');
}

String displayPhoneNumber(String phoneNumber) {
String displayPhoneNumber(String? phoneNumber) {
phoneNumber = phoneNumber ?? '';
final prefix = '+${state.dialCode.value}';
if (phoneNumber.startsWith(prefix)) {
phoneNumber = phoneNumber.substring(prefix.length);
}
return phoneNumber;
// this is to handle the case where the user may errantly input their dial code again in their phone number
// we make sure the user's phone number doesn't naturally just start with their dial code by checking if the number exceeds the maximum phone length of the country's phone number scheme before truncating it
if (!phoneNumber.startsWith(prefix.substring(1))) {
return phoneNumber;
}
final prefixLength = countryPhoneNumberLengths[prefix];
if (prefixLength == null || phoneNumber.length <= prefixLength) {
return phoneNumber;
}
return phoneNumber.substring(prefix.length - 1);
}

String get dialCode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_authenticator/src/keys.dart';
import 'package:amplify_authenticator/src/models/username_input.dart';
import 'package:amplify_authenticator/src/utils/dial_code_to_length.dart';
import 'package:amplify_authenticator/src/utils/validators.dart';
import 'package:amplify_authenticator/src/widgets/component.dart';
import 'package:amplify_authenticator/src/widgets/form_field.dart';
Expand Down Expand Up @@ -164,6 +165,58 @@ mixin AuthenticatorUsernameField<FieldType extends Enum,
}
}

String displayPhoneNumber(String? phoneNumber) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this method defined 3 times in this file? I see there are small differences in the implementation, don't know if it is a Dart thing that I am not familiar with

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to note that the comments seem copy pasted too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is because i accidentally copy pasted it too many times, it should be two different functions

phoneNumber = phoneNumber ?? '';
final prefix = '+${state.dialCode.value}';
if (phoneNumber.startsWith(prefix)) {
phoneNumber = phoneNumber.substring(prefix.length);
}
// this is to handle the case where the user may errantly input their dial code again in their phone number
// we make sure the user's phone number doesn't naturally just start with their dial code by checking if the number exceeds the maximum phone length of the country's phone number scheme before truncating it
if (phoneNumber.startsWith(prefix.substring(1))) {
if (countryPhoneNumberLengths.containsKey(prefix) &&
phoneNumber.length > countryPhoneNumberLengths[prefix]!) {
phoneNumber = phoneNumber.substring(prefix.length - 1);
}
}
return phoneNumber;
}

String displayPhoneNumber(String? phoneNumber) {
phoneNumber = phoneNumber ?? '';
final prefix = '+${state.dialCode.value}';
if (phoneNumber.startsWith(prefix)) {
phoneNumber = phoneNumber.substring(prefix.length);
}
// this is to handle the case where the user may errantly input their dial code again in their phone number
// we make sure the user's phone number doesn't naturally just start with their dial code by checking if the number exceeds the maximum phone length of the country's phone number scheme before truncating it
if (phoneNumber.startsWith(prefix.substring(1))) {
if (countryPhoneNumberLengths.containsKey(prefix) &&
phoneNumber.length > countryPhoneNumberLengths[prefix]!) {
phoneNumber = phoneNumber.substring(prefix.length - 1);
}
}
return phoneNumber;
}

String displayPhoneNumber(String? phoneNumber) {
phoneNumber = phoneNumber ?? '';
final prefix = '+${state.dialCode.value}';
if (phoneNumber.startsWith(prefix)) {
phoneNumber = phoneNumber.substring(prefix.length);
}
// this is to handle the case where the user may errantly input their dial code again in their phone number
// we make sure the user's phone number doesn't naturally just start with their dial code by checking if the number exceeds the maximum phone length of the country's phone number scheme before truncating it
if (!phoneNumber.startsWith(prefix.substring(1))) {
return phoneNumber;
}
final prefixLength = countryPhoneNumberLengths[prefix];
if (prefixLength == null || phoneNumber.length <= prefixLength) {
return phoneNumber;
}
return phoneNumber.substring(prefix.length - 1);
}

@override
FormFieldValidator<UsernameInput> get validator {
switch (selectedUsernameType) {
Expand All @@ -183,7 +236,7 @@ mixin AuthenticatorUsernameField<FieldType extends Enum,
isOptional: isOptional,
context: context,
inputResolver: stringResolver.inputs,
)(input?.username);
)(displayPhoneNumber(input?.username));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are passing the username as a param into the phone number method? that doesn't seem right

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The username can be a phone number, and at that point in the code its been validated as such. We use AWS Cognito as our base provider for auth, which accepts phone and email as usernames if it has been configured that way.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL! thank you for explaining :)

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
/// A list of [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) dial codes mapped to the maximum [possible length](https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers) of the phone number from that country as an integer
///
///
Map<String, int> countryPhoneNumberLengths = {
'+1': 10, // United States, Canada, and other NANP countries
'+7': 10, // Russia, Kazakhstan
'+20': 10, // Egypt
'+27': 9, // South Africa
'+30': 10, // Greece
'+31': 9, // Netherlands
'+32': 9, // Belgium
'+33': 9, // France
'+34': 9, // Spain
'+36': 9, // Hungary
'+39': 10, // Italy
'+40': 9, // Romania
'+44': 10, // United Kingdom
'+45': 8, // Denmark
'+46': 9, // Sweden
'+47': 8, // Norway
'+48': 9, // Poland
'+49': 11, // Germany
'+51': 9, // Peru
'+52': 10, // Mexico
'+53': 8, // Cuba
'+54': 10, // Argentina
'+55': 11, // Brazil
'+56': 9, // Chile
'+57': 10, // Colombia
'+58': 10, // Venezuela
'+60': 10, // Malaysia
'+61': 9, // Australia
'+62': 11, // Indonesia
'+63': 10, // Philippines
'+64': 9, // New Zealand
'+65': 8, // Singapore
'+66': 9, // Thailand
'+81': 10, // Japan
'+82': 10, // South Korea
'+84': 10, // Vietnam
'+86': 11, // China
'+90': 11, // Turkey
'+91': 10, // India
'+92': 10, // Pakistan
'+93': 9, // Afghanistan
'+94': 10, // Sri Lanka
'+95': 9, // Myanmar
'+98': 10, // Iran
'+211': 9, // South Sudan
'+212': 9, // Morocco
'+213': 9, // Algeria
'+216': 8, // Tunisia
'+218': 10, // Libya
'+220': 7, // Gambia
'+221': 9, // Senegal
'+222': 9, // Mauritania
'+223': 8, // Mali
'+224': 9, // Guinea
'+225': 10, // Ivory Coast
'+226': 8, // Burkina Faso
'+227': 8, // Niger
'+228': 8, // Togo
'+229': 8, // Benin
'+230': 7, // Mauritius
'+231': 9, // Liberia
'+232': 8, // Sierra Leone
'+233': 9, // Ghana
'+234': 10, // Nigeria
'+235': 8, // Chad
'+236': 8, // Central African Republic
'+237': 9, // Cameroon
'+238': 7, // Cape Verde
'+239': 7, // São Tomé and Príncipe
'+240': 9, // Equatorial Guinea
'+241': 9, // Gabon
'+242': 9, // Republic of the Congo
'+243': 9, // DR Congo
'+244': 9, // Angola
'+245': 7, // Guinea-Bissau
'+248': 7, // Seychelles
'+249': 9, // Sudan
'+250': 9, // Rwanda
'+251': 9, // Ethiopia
'+252': 8, // Somalia
'+253': 8, // Djibouti
'+254': 10, // Kenya
'+255': 9, // Tanzania
'+256': 9, // Uganda
'+257': 8, // Burundi
'+258': 9, // Mozambique
'+260': 9, // Zambia
'+261': 9, // Madagascar
'+262': 9, // Réunion
'+263': 9, // Zimbabwe
'+264': 9, // Namibia
'+265': 9, // Malawi
'+266': 8, // Lesotho
'+267': 8, // Botswana
'+268': 8, // Eswatini (Swaziland)
'+269': 7, // Comoros
'+290': 4, // Saint Helena
'+291': 7, // Eritrea
'+297': 7, // Aruba
'+298': 6, // Faroe Islands
'+299': 6, // Greenland
'+350': 8, // Gibraltar
'+351': 9, // Portugal
'+352': 9, // Luxembourg
'+353': 9, // Ireland
'+354': 7, // Iceland
'+355': 9, // Albania
'+356': 8, // Malta
'+357': 8, // Cyprus
'+358': 10, // Finland
'+359': 9, // Bulgaria
'+370': 8, // Lithuania
'+371': 8, // Latvia
'+372': 8, // Estonia
'+373': 8, // Moldova
'+374': 8, // Armenia
'+375': 9, // Belarus
'+376': 6, // Andorra
'+377': 8, // Monaco
'+378': 10, // San Marino
'+380': 9, // Ukraine
'+381': 9, // Serbia
'+382': 9, // Montenegro
'+385': 9, // Croatia
'+386': 9, // Slovenia
'+387': 8, // Bosnia and Herzegovina
'+389': 8, // North Macedonia
'+420': 9, // Czech Republic
'+421': 9, // Slovakia
'+423': 7, // Liechtenstein
'+500': 5, // Falkland Islands
'+501': 7, // Belize
'+502': 8, // Guatemala
'+503': 8, // El Salvador
'+504': 8, // Honduras
'+505': 8, // Nicaragua
'+506': 8, // Costa Rica
'+507': 7, // Panama
'+509': 8, // Haiti
'+590': 9, // Guadeloupe
'+591': 8, // Bolivia
'+592': 7, // Guyana
'+593': 9, // Ecuador
'+594': 9, // French Guiana
'+595': 9, // Paraguay
'+596': 9, // Martinique
'+597': 7, // Suriname
'+598': 9, // Uruguay
'+670': 7, // East Timor
'+672': 6, // Australian External Territories
'+673': 7, // Brunei
'+674': 7, // Nauru
'+675': 8, // Papua New Guinea
'+676': 5, // Tonga
'+677': 7, // Solomon Islands
'+678': 7, // Vanuatu
'+679': 7, // Fiji
'+680': 7, // Palau
'+681': 6, // Wallis and Futuna
'+682': 5, // Cook Islands
'+683': 4, // Niue
'+685': 7, // Samoa
'+686': 8, // Kiribati
'+687': 6, // New Caledonia
'+688': 5, // Tuvalu
'+689': 6, // French Polynesia
'+690': 4, // Tokelau
'+691': 7, // Micronesia
'+692': 7, // Marshall Islands
'+850': 10, // North Korea
'+852': 8, // Hong Kong
'+853': 8, // Macau
'+855': 9, // Cambodia
'+856': 9, // Laos
'+880': 10, // Bangladesh
'+886': 9, // Taiwan
'+960': 7, // Maldives
'+961': 8, // Lebanon
'+962': 9, // Jordan
'+963': 9, // Syria
'+964': 10, // Iraq
'+965': 8, // Kuwait
'+966': 9, // Saudi Arabia
'+967': 9, // Yemen
'+968': 8, // Oman
'+970': 9, // Palestine
'+971': 9, // United Arab Emirates
'+972': 9, // Israel
'+973': 8, // Bahrain
'+974': 8, // Qatar
'+975': 8, // Bhutan
'+976': 8, // Mongolia
'+977': 10, // Nepal
'+992': 9, // Tajikistan
'+993': 8, // Turkmenistan
'+994': 9, // Azerbaijan
'+995': 9, // Georgia
'+996': 9, // Kyrgyzstan
'+998': 9, // Uzbekistan
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'package:flutter/material.dart';
*/
final usernameRegex = RegExp(r'^\S+$');
final emailRegex = RegExp(r'^\S+@\S+$');
final phoneNumberRegex = RegExp(r'^\+\d+$');
final phoneNumberRegex = RegExp(r'^\d+$');
final _codeRegex = RegExp(r'^\d{6}$');
final _uppercase = RegExp(r'[A-Z]');
final _lowercase = RegExp(r'[a-z]');
Expand Down Expand Up @@ -154,8 +154,8 @@ FormFieldValidator<String> validatePhoneNumber({
InputResolverKey.phoneNumberEmpty,
);
}
phoneNumber = phoneNumber.trim();
if (!phoneNumberRegex.hasMatch(phoneNumber)) {
final formattedNumber = phoneNumber.trim();
if (!phoneNumberRegex.hasMatch(formattedNumber)) {
return inputResolver.resolve(context, InputResolverKey.phoneNumberFormat);
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ class _ConfirmSignInPhoneFieldState extends _ConfirmSignInTextFieldState
@override
FormFieldValidator<String> get validator {
return (phoneNumber) {
phoneNumber = formatPhoneNumber(phoneNumber);
phoneNumber = displayPhoneNumber(phoneNumber);
return validatePhoneNumber(
inputResolver: stringResolver.inputs,
context: context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ class _AuthenticatorPhoneFieldState<FieldType extends Enum>
@override
FormFieldValidator<String> get validator {
return (String? phoneNumber) {
phoneNumber = formatPhoneNumber(phoneNumber);
final validator = widget.validator;
if (validator != null) {
phoneNumber = formatPhoneNumber(phoneNumber);
return validator(phoneNumber);
}
phoneNumber = displayPhoneNumber(phoneNumber);
return validatePhoneNumber(
inputResolver: stringResolver.inputs,
context: context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ class _SignUpPhoneFieldState extends _SignUpTextFieldState
@override
FormFieldValidator<String> get validator {
return (phoneNumber) {
phoneNumber = formatPhoneNumber(phoneNumber);
phoneNumber = displayPhoneNumber(phoneNumber);
return validatePhoneNumber(
inputResolver: stringResolver.inputs,
context: context,
Expand Down
Loading
Loading