mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-31 11:52:10 +00:00
fix: use ValidateEmail as binding across web forms
This commit is contained in:
parent
df907ec7f9
commit
471567b3ba
24 changed files with 281 additions and 221 deletions
|
@ -7,8 +7,6 @@ package user
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -18,53 +16,10 @@ import (
|
|||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// ErrEmailNotActivated e-mail address has not been activated error
|
||||
var ErrEmailNotActivated = util.NewInvalidArgumentErrorf("e-mail address has not been activated")
|
||||
|
||||
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
|
||||
type ErrEmailCharIsNotSupported struct {
|
||||
Email string
|
||||
}
|
||||
|
||||
// IsErrEmailCharIsNotSupported checks if an error is an ErrEmailCharIsNotSupported
|
||||
func IsErrEmailCharIsNotSupported(err error) bool {
|
||||
_, ok := err.(ErrEmailCharIsNotSupported)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrEmailCharIsNotSupported) Error() string {
|
||||
return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email)
|
||||
}
|
||||
|
||||
func (err ErrEmailCharIsNotSupported) Unwrap() error {
|
||||
return util.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
|
||||
// or has a leading '-' character
|
||||
type ErrEmailInvalid struct {
|
||||
Email string
|
||||
}
|
||||
|
||||
// IsErrEmailInvalid checks if an error is an ErrEmailInvalid
|
||||
func IsErrEmailInvalid(err error) bool {
|
||||
_, ok := err.(ErrEmailInvalid)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrEmailInvalid) Error() string {
|
||||
return fmt.Sprintf("e-mail invalid [email: %s]", err.Email)
|
||||
}
|
||||
|
||||
func (err ErrEmailInvalid) Unwrap() error {
|
||||
return util.ErrInvalidArgument
|
||||
}
|
||||
|
||||
// ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error.
|
||||
type ErrEmailAlreadyUsed struct {
|
||||
Email string
|
||||
|
@ -156,22 +111,6 @@ func UpdateEmailAddress(ctx context.Context, email *EmailAddress) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
||||
|
||||
// ValidateEmail check if email is a valid & allowed address
|
||||
func ValidateEmail(email string) error {
|
||||
if err := validateEmailBasic(email); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateEmailDomain(email)
|
||||
}
|
||||
|
||||
// ValidateEmailForAdmin check if email is a valid address when admins manually add or edit users
|
||||
func ValidateEmailForAdmin(email string) error {
|
||||
return validateEmailBasic(email)
|
||||
// In this case we do not need to check the email domain
|
||||
}
|
||||
|
||||
func GetEmailAddressByEmail(ctx context.Context, email string) (*EmailAddress, error) {
|
||||
ea := &EmailAddress{}
|
||||
if has, err := db.GetEngine(ctx).Where("lower_email=?", strings.ToLower(email)).Get(ea); err != nil {
|
||||
|
@ -462,41 +401,3 @@ func ActivateUserEmail(ctx context.Context, userID int64, email string, activate
|
|||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
// validateEmailBasic checks whether the email complies with the rules
|
||||
func validateEmailBasic(email string) error {
|
||||
if len(email) == 0 {
|
||||
return ErrEmailInvalid{email}
|
||||
}
|
||||
|
||||
if !emailRegexp.MatchString(email) {
|
||||
return ErrEmailCharIsNotSupported{email}
|
||||
}
|
||||
|
||||
if email[0] == '-' {
|
||||
return ErrEmailInvalid{email}
|
||||
}
|
||||
|
||||
if _, err := mail.ParseAddress(email); err != nil {
|
||||
return ErrEmailInvalid{email}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateEmailDomain checks whether the email domain is allowed or blocked
|
||||
func validateEmailDomain(email string) error {
|
||||
if !IsEmailDomainAllowed(email) {
|
||||
return ErrEmailInvalid{email}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsEmailDomainAllowed(email string) bool {
|
||||
if len(setting.Service.EmailDomainAllowList) == 0 {
|
||||
return !validation.IsEmailDomainListed(setting.Service.EmailDomainBlockList, email)
|
||||
}
|
||||
|
||||
return validation.IsEmailDomainListed(setting.Service.EmailDomainAllowList, email)
|
||||
}
|
||||
|
|
|
@ -130,63 +130,6 @@ func TestListEmails(t *testing.T) {
|
|||
assert.Greater(t, count, int64(len(emails)))
|
||||
}
|
||||
|
||||
func TestEmailAddressValidate(t *testing.T) {
|
||||
kases := map[string]error{
|
||||
"abc@gmail.com": nil,
|
||||
"132@hotmail.com": nil,
|
||||
"1-3-2@test.org": nil,
|
||||
"1.3.2@test.org": nil,
|
||||
"a_123@test.org.cn": nil,
|
||||
`first.last@iana.org`: nil,
|
||||
`first!last@iana.org`: nil,
|
||||
`first#last@iana.org`: nil,
|
||||
`first$last@iana.org`: nil,
|
||||
`first%last@iana.org`: nil,
|
||||
`first&last@iana.org`: nil,
|
||||
`first'last@iana.org`: nil,
|
||||
`first*last@iana.org`: nil,
|
||||
`first+last@iana.org`: nil,
|
||||
`first/last@iana.org`: nil,
|
||||
`first=last@iana.org`: nil,
|
||||
`first?last@iana.org`: nil,
|
||||
`first^last@iana.org`: nil,
|
||||
"first`last@iana.org": nil,
|
||||
`first{last@iana.org`: nil,
|
||||
`first|last@iana.org`: nil,
|
||||
`first}last@iana.org`: nil,
|
||||
`first~last@iana.org`: nil,
|
||||
`first;last@iana.org`: user_model.ErrEmailCharIsNotSupported{`first;last@iana.org`},
|
||||
".233@qq.com": user_model.ErrEmailInvalid{".233@qq.com"},
|
||||
"!233@qq.com": nil,
|
||||
"#233@qq.com": nil,
|
||||
"$233@qq.com": nil,
|
||||
"%233@qq.com": nil,
|
||||
"&233@qq.com": nil,
|
||||
"'233@qq.com": nil,
|
||||
"*233@qq.com": nil,
|
||||
"+233@qq.com": nil,
|
||||
"-233@qq.com": user_model.ErrEmailInvalid{"-233@qq.com"},
|
||||
"/233@qq.com": nil,
|
||||
"=233@qq.com": nil,
|
||||
"?233@qq.com": nil,
|
||||
"^233@qq.com": nil,
|
||||
"_233@qq.com": nil,
|
||||
"`233@qq.com": nil,
|
||||
"{233@qq.com": nil,
|
||||
"|233@qq.com": nil,
|
||||
"}233@qq.com": nil,
|
||||
"~233@qq.com": nil,
|
||||
";233@qq.com": user_model.ErrEmailCharIsNotSupported{";233@qq.com"},
|
||||
"Foo <foo@bar.com>": user_model.ErrEmailCharIsNotSupported{"Foo <foo@bar.com>"},
|
||||
string([]byte{0xE2, 0x84, 0xAA}): user_model.ErrEmailCharIsNotSupported{string([]byte{0xE2, 0x84, 0xAA})},
|
||||
}
|
||||
for kase, err := range kases {
|
||||
t.Run(kase, func(t *testing.T) {
|
||||
assert.EqualValues(t, err, user_model.ValidateEmail(kase))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActivatedEmailAddresses(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
|
|
|
@ -711,11 +711,11 @@ func createUser(ctx context.Context, u *User, createdByAdmin bool, overwriteDefa
|
|||
}
|
||||
|
||||
if createdByAdmin {
|
||||
if err := ValidateEmailForAdmin(u.Email); err != nil {
|
||||
if err := validation.ValidateEmailForAdmin(u.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := ValidateEmail(u.Email); err != nil {
|
||||
if err := validation.ValidateEmail(u.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -879,7 +879,7 @@ func (u User) Validate() []string {
|
|||
if err := ValidateUser(&u); err != nil {
|
||||
result = append(result, err.Error())
|
||||
}
|
||||
if err := ValidateEmail(u.Email); err != nil {
|
||||
if err := validation.ValidateEmail(u.Email); err != nil {
|
||||
result = append(result, err.Error())
|
||||
}
|
||||
return result
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -320,7 +321,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
|
|||
|
||||
err := user_model.CreateUser(db.DefaultContext, user)
|
||||
require.Error(t, err)
|
||||
assert.True(t, user_model.IsErrEmailCharIsNotSupported(err))
|
||||
assert.True(t, validation.IsErrEmailCharIsNotSupported(err))
|
||||
}
|
||||
|
||||
func TestCreateUserEmailAlreadyUsed(t *testing.T) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue