Pārlūkot izejas kodu

feat: validate usernames upon creation

The validation doesn't apply to already created usernames.

This should close #925
Julien Voisin 1 gadu atpakaļ
vecāks
revīzija
e22520fc55
2 mainītis faili ar 49 papildinājumiem un 1 dzēšanām
  1. 22 0
      internal/validator/user.go
  2. 27 1
      internal/validator/validator_test.go

+ 22 - 0
internal/validator/user.go

@@ -6,6 +6,7 @@ package validator // import "miniflux.app/v2/internal/validator"
 import (
 	"slices"
 	"strings"
+	"unicode"
 
 	"miniflux.app/v2/internal/locale"
 	"miniflux.app/v2/internal/model"
@@ -22,6 +23,10 @@ func ValidateUserCreationWithPassword(store *storage.Storage, request *model.Use
 		return locale.NewLocalizedError("error.user_already_exists")
 	}
 
+	if err := validateUsername(request.Username); err != nil {
+		return err
+	}
+
 	if err := validatePassword(request.Password); err != nil {
 		return err
 	}
@@ -146,6 +151,23 @@ func validatePassword(password string) *locale.LocalizedError {
 	return nil
 }
 
+// validateUsername return an error if the `username` argument contains
+// a character that isn't alphanumerical nor `_` and `-`.
+func validateUsername(username string) *locale.LocalizedError {
+	if strings.ContainsFunc(username, func(r rune) bool {
+		if unicode.IsLetter(r) || unicode.IsNumber(r) {
+			return false
+		}
+		if r == '_' || r == '-' || r == '@' || r == '.' {
+			return false
+		}
+		return true
+	}) {
+		return locale.NewLocalizedError("error.invalid_username")
+	}
+	return nil
+}
+
 func validateTheme(theme string) *locale.LocalizedError {
 	themes := model.Themes()
 	if _, found := themes[theme]; !found {

+ 27 - 1
internal/validator/validator_test.go

@@ -3,7 +3,11 @@
 
 package validator // import "miniflux.app/v2/internal/validator"
 
-import "testing"
+import (
+	"testing"
+
+	"miniflux.app/v2/internal/locale"
+)
 
 func TestIsValidURL(t *testing.T) {
 	scenarios := map[string]bool{
@@ -77,3 +81,25 @@ func TestIsValidDomain(t *testing.T) {
 		}
 	}
 }
+
+func TestValidateUsername(t *testing.T) {
+	scenarios := map[string]*locale.LocalizedError{
+		"jvoisin":          nil,
+		"j.voisin":         nil,
+		"j@vois.in":        nil,
+		"invalid username": locale.NewLocalizedError("error.invalid_username"),
+	}
+
+	for username, expected := range scenarios {
+		result := validateUsername(username)
+		if expected == nil {
+			if result != nil {
+				t.Errorf(`got an unexpected error for %q instead of nil: %v`, username, result)
+			}
+		} else {
+			if result == nil {
+				t.Errorf(`expected an error, got nil.`)
+			}
+		}
+	}
+}