Use Google's libphonenumber to perform more robust phone number validation and to convert all phone numbers to E164 before storing them. Closes #45
This commit is contained in:
parent
628c8d656b
commit
5f322824ac
5
pom.xml
5
pom.xml
|
@ -101,6 +101,11 @@
|
|||
<artifactId>gson</artifactId>
|
||||
<version>2.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.libphonenumber</groupId>
|
||||
<artifactId>libphonenumber</artifactId>
|
||||
<version>7.4.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Mongo -->
|
||||
<dependency>
|
||||
|
|
|
@ -7,6 +7,7 @@ import fr.javatic.mongo.jacksonCodec.objectId.Id;
|
|||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.frozenorb.apiv3.APIv3;
|
||||
import net.frozenorb.apiv3.util.PhoneUtils;
|
||||
import net.frozenorb.apiv3.util.SyncUtils;
|
||||
import net.frozenorb.apiv3.util.ZangUtils;
|
||||
import net.frozenorb.apiv3.zang.ZangResult;
|
||||
|
@ -31,32 +32,50 @@ public final class PhoneIntel {
|
|||
}
|
||||
|
||||
public static void findById(String id, SingleResultCallback<PhoneIntel> callback) {
|
||||
phoneIntelCollection.find(new Document("_id", id)).first(SyncUtils.vertxWrap(callback));
|
||||
String e164Phone = PhoneUtils.toE164(id);
|
||||
|
||||
if (e164Phone == null) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
phoneIntelCollection.find(new Document("_id", id)).first(SyncUtils.vertxWrap(callback));
|
||||
}
|
||||
}
|
||||
|
||||
public static void findOrCreateById(String id, SingleResultCallback<PhoneIntel> callback) {
|
||||
findById(id, (existingPhoneIntel, error) -> {
|
||||
String e164Phone = PhoneUtils.toE164(id);
|
||||
|
||||
if (e164Phone == null) {
|
||||
callback.onResult(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
findById(e164Phone, (existingPhoneIntel, error) -> {
|
||||
if (error != null) {
|
||||
callback.onResult(null, error);
|
||||
} else if (existingPhoneIntel != null) {
|
||||
callback.onResult(existingPhoneIntel, null);
|
||||
} else {
|
||||
ZangUtils.getCarrierInfo(id, (zangResult, error2) -> {
|
||||
if (error2 != null) {
|
||||
callback.onResult(null, error2);
|
||||
} else {
|
||||
PhoneIntel newPhoneIntel = new PhoneIntel(id, zangResult);
|
||||
|
||||
phoneIntelCollection.insertOne(newPhoneIntel, SyncUtils.vertxWrap((ignored, error3) -> {
|
||||
if (error3 != null) {
|
||||
callback.onResult(null, error3);
|
||||
} else {
|
||||
callback.onResult(newPhoneIntel, null);
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingPhoneIntel != null) {
|
||||
callback.onResult(existingPhoneIntel, null);
|
||||
return;
|
||||
}
|
||||
|
||||
ZangUtils.getCarrierInfo(e164Phone, (zangResult, error2) -> {
|
||||
if (error2 != null) {
|
||||
callback.onResult(null, error2);
|
||||
return;
|
||||
}
|
||||
|
||||
PhoneIntel newPhoneIntel = new PhoneIntel(e164Phone, zangResult);
|
||||
|
||||
phoneIntelCollection.insertOne(newPhoneIntel, SyncUtils.vertxWrap((ignored, error3) -> {
|
||||
if (error3 != null) {
|
||||
callback.onResult(null, error3);
|
||||
} else {
|
||||
callback.onResult(newPhoneIntel, null);
|
||||
}
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -117,10 +117,16 @@ public final class User {
|
|||
}
|
||||
|
||||
public static void findByPhone(String phoneNumber, SingleResultCallback<User> callback) {
|
||||
usersCollection.find(new Document("$or", ImmutableList.of(
|
||||
new Document("phone", phoneNumber),
|
||||
new Document("pendingPhone", phoneNumber)
|
||||
))).first(SyncUtils.vertxWrap(callback));
|
||||
String e164Phone = PhoneUtils.toE164(phoneNumber);
|
||||
|
||||
if (e164Phone == null) {
|
||||
callback.onResult(null, null);
|
||||
} else {
|
||||
usersCollection.find(new Document("$or", ImmutableList.of(
|
||||
new Document("phone", phoneNumber),
|
||||
new Document("pendingPhone", phoneNumber)
|
||||
))).first(SyncUtils.vertxWrap(callback));
|
||||
}
|
||||
}
|
||||
|
||||
public static void findByEmail(String email, SingleResultCallback<User> callback) {
|
||||
|
@ -536,7 +542,11 @@ public final class User {
|
|||
}
|
||||
|
||||
public void startPhoneRegistration(String phoneNumber) {
|
||||
this.pendingPhone = phoneNumber;
|
||||
String e164Phone = PhoneUtils.toE164(phoneNumber);
|
||||
|
||||
if (e164Phone == null) return;
|
||||
|
||||
this.pendingPhone = e164Phone;
|
||||
this.pendingPhoneToken = String.valueOf(new Random().nextInt(999999 - 100000) + 100000);
|
||||
this.pendingPhoneTokenSetAt = Instant.now();
|
||||
}
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
package net.frozenorb.apiv3.util;
|
||||
|
||||
import com.google.i18n.phonenumbers.NumberParseException;
|
||||
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||
import com.google.i18n.phonenumbers.Phonenumber;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@UtilityClass
|
||||
public class PhoneUtils {
|
||||
|
||||
private static final Pattern VALID_PHONE_PATTERN = Pattern.compile(
|
||||
"^\\+?[1-9]\\d{1,14}$",
|
||||
Pattern.CASE_INSENSITIVE
|
||||
);
|
||||
public static final String DEFAULT_COUNTRY_CODE = "US";
|
||||
private static final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
|
||||
|
||||
public static boolean isValidPhone(String phoneNumber) {
|
||||
return phoneNumber != null && VALID_PHONE_PATTERN.matcher(phoneNumber).matches();
|
||||
try {
|
||||
return phoneNumber != null && phoneUtil.isValidNumber(phoneUtil.parse(phoneNumber, DEFAULT_COUNTRY_CODE));
|
||||
} catch (NumberParseException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toE164(String phoneNumber) {
|
||||
try {
|
||||
Phonenumber.PhoneNumber number = phoneUtil.parse(phoneNumber, DEFAULT_COUNTRY_CODE);
|
||||
return phoneUtil.format(number, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||
} catch (NumberParseException ex) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue