feat: normalize and validate phone numbers before saving
This commit is contained in:
@@ -511,8 +511,17 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
return
|
||||
}
|
||||
|
||||
countryCode := user.GetCountryCode("")
|
||||
if destType == object.VerifyTypePhone {
|
||||
if object.HasUserByPhoneAndCountryCode(user.Owner, dest, user.GetCountryCode("")) {
|
||||
normalizedPhone, normalizedCountryCode, isValid := util.GetNormalizedPhone(dest, countryCode)
|
||||
if !isValid {
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), countryCode))
|
||||
return
|
||||
}
|
||||
|
||||
dest, countryCode = normalizedPhone, normalizedCountryCode
|
||||
|
||||
if object.HasUserByPhoneAndCountryCode(user.Owner, dest, countryCode) {
|
||||
c.ResponseError(c.T("check:Phone already exists"))
|
||||
return
|
||||
}
|
||||
@@ -527,8 +536,8 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
c.ResponseError(errMsg)
|
||||
return
|
||||
}
|
||||
if checkDest, ok = util.GetE164Number(dest, user.GetCountryCode("")); !ok {
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), user.CountryCode))
|
||||
if checkDest, ok = util.GetE164Number(dest, countryCode); !ok {
|
||||
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), countryCode))
|
||||
return
|
||||
}
|
||||
} else if destType == object.VerifyTypeEmail {
|
||||
@@ -568,7 +577,8 @@ func (c *ApiController) ResetEmailOrPhone() {
|
||||
_, err = object.UpdateUser(id, user, columns, false)
|
||||
case object.VerifyTypePhone:
|
||||
user.Phone = dest
|
||||
_, err = object.SetUserField(user, "phone", user.Phone)
|
||||
user.CountryCode = countryCode
|
||||
_, err = object.UpdateUser(user.GetId(), user, []string{"phone", "country_code"}, false)
|
||||
default:
|
||||
c.ResponseError(c.T("verification:Unknown type"))
|
||||
return
|
||||
|
||||
+26
-2
@@ -39,6 +39,17 @@ func CheckUserSignup(application *Application, organization *Organization, authF
|
||||
return i18n.Translate(lang, "check:Organization does not exist")
|
||||
}
|
||||
|
||||
// Normalize the phone number before the duplication checks below
|
||||
if authForm.Phone != "" {
|
||||
normalizedPhone, normalizedCountryCode, ok := util.GetNormalizedPhone(authForm.Phone, authForm.CountryCode)
|
||||
if !ok {
|
||||
return i18n.Translate(lang, "check:Phone number is invalid")
|
||||
}
|
||||
|
||||
authForm.Phone = normalizedPhone
|
||||
authForm.CountryCode = normalizedCountryCode
|
||||
}
|
||||
|
||||
if application.IsSignupItemVisible("Username") {
|
||||
if len(authForm.Username) <= 1 {
|
||||
return i18n.Translate(lang, "check:Username must have at least 2 characters")
|
||||
@@ -802,8 +813,21 @@ func CheckUpdateUser(oldUser, user *User, lang string) string {
|
||||
}
|
||||
}
|
||||
if oldUser.Phone != user.Phone || oldUser.CountryCode != user.CountryCode {
|
||||
if HasUserByPhoneAndCountryCode(user.Owner, user.Phone, user.CountryCode) {
|
||||
return i18n.Translate(lang, "check:Phone already exists")
|
||||
if user.Phone != "" {
|
||||
normalizedPhone, normalizedCountryCode, ok := util.GetNormalizedPhone(user.Phone, user.GetCountryCode(""))
|
||||
if !ok {
|
||||
return i18n.Translate(lang, "check:Phone number is invalid")
|
||||
}
|
||||
|
||||
user.Phone = normalizedPhone
|
||||
user.CountryCode = normalizedCountryCode
|
||||
}
|
||||
|
||||
// The normalization may have turned the new phone number into the old one
|
||||
if oldUser.Phone != user.Phone || oldUser.CountryCode != user.CountryCode {
|
||||
if HasUserByPhoneAndCountryCode(user.Owner, user.Phone, user.CountryCode) {
|
||||
return i18n.Translate(lang, "check:Phone already exists")
|
||||
}
|
||||
}
|
||||
}
|
||||
if oldUser.IpWhitelist != user.IpWhitelist {
|
||||
|
||||
@@ -84,6 +84,27 @@ func GetE164Number(phone string, countryCode string) (string, bool) {
|
||||
return phonenumbers.Format(phoneNumber, phonenumbers.E164), phonenumbers.IsValidNumber(phoneNumber)
|
||||
}
|
||||
|
||||
// GetNormalizedPhone converts a phone number like "+48 666 666 666" into the national number
|
||||
// in digits only (e.g. "666666666") and the region code (e.g. "PL"), it returns the input
|
||||
// unchanged when the phone number is invalid.
|
||||
func GetNormalizedPhone(phone string, countryCode string) (string, string, bool) {
|
||||
phoneNumber, err := phonenumbers.Parse(phone, countryCode)
|
||||
if err != nil || !phonenumbers.IsValidNumber(phoneNumber) {
|
||||
return phone, countryCode, false
|
||||
}
|
||||
|
||||
// Only take the region from the number itself when it is in the international format,
|
||||
// so that a shared calling code like "+1" doesn't overwrite the chosen country code
|
||||
normalizedCountryCode := countryCode
|
||||
if normalizedCountryCode == "" || strings.HasPrefix(strings.TrimSpace(phone), "+") {
|
||||
if regionCode := phonenumbers.GetRegionCodeForNumber(phoneNumber); regionCode != "" {
|
||||
normalizedCountryCode = regionCode
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d", phoneNumber.GetNationalNumber()), normalizedCountryCode, true
|
||||
}
|
||||
|
||||
func GetCountryCode(prefix string, phone string) (string, error) {
|
||||
if prefix == "" || phone == "" {
|
||||
return "", nil
|
||||
|
||||
Reference in New Issue
Block a user