فهرست منبع

Move stuff to util.go

binwiederhier 6 ماه پیش
والد
کامیت
b91ff5f0b5
6فایلهای تغییر یافته به همراه82 افزوده شده و 76 حذف شده
  1. 2 2
      cmd/serve.go
  2. 1 1
      cmd/token.go
  3. 2 6
      cmd/user.go
  4. 4 13
      user/manager.go
  5. 0 54
      user/types.go
  6. 73 0
      user/util.go

+ 2 - 2
cmd/serve.go

@@ -550,7 +550,7 @@ func parseUsers(usersRaw []string) ([]*user.User, error) {
 		role := user.Role(strings.TrimSpace(parts[2]))
 		if !user.AllowedUsername(username) {
 			return nil, fmt.Errorf("invalid auth-users: %s, username invalid", userLine)
-		} else if err := user.AllowedPasswordHash(passwordHash); err != nil {
+		} else if err := user.ValidPasswordHash(passwordHash); err != nil {
 			return nil, fmt.Errorf("invalid auth-users: %s, %s", userLine, err.Error())
 		} else if !user.AllowedRole(role) {
 			return nil, fmt.Errorf("invalid auth-users: %s, role %s is not allowed, allowed roles are 'admin' or 'user'", userLine, role)
@@ -625,7 +625,7 @@ func parseTokens(users []*user.User, tokensRaw []string) (map[string][]*user.Tok
 			return nil, fmt.Errorf("invalid auth-tokens: %s, username %s invalid", tokenLine, username)
 		}
 		token := strings.TrimSpace(parts[1])
-		if !user.AllowedToken(token) {
+		if !user.ValidToken(token) {
 			return nil, fmt.Errorf("invalid auth-tokens: %s, token %s invalid, use 'ntfy token generate' to generate a random token", tokenLine, token)
 		}
 		var label string

+ 1 - 1
cmd/token.go

@@ -222,6 +222,6 @@ func execTokenList(c *cli.Context) error {
 }
 
 func execTokenGenerate(c *cli.Context) error {
-	fmt.Println(user.GenerateToken())
+	fmt.Fprintln(c.App.Writer, user.GenerateToken())
 	return nil
 }

+ 2 - 6
cmd/user.go

@@ -306,19 +306,15 @@ func execUserChangeRole(c *cli.Context) error {
 }
 
 func execUserHash(c *cli.Context) error {
-	manager, err := createUserManager(c)
-	if err != nil {
-		return err
-	}
 	password, err := readPasswordAndConfirm(c)
 	if err != nil {
 		return err
 	}
-	hash, err := manager.HashPassword(password)
+	hash, err := user.HashPassword(password)
 	if err != nil {
 		return fmt.Errorf("failed to hash password: %w", err)
 	}
-	fmt.Fprintf(c.App.Writer, "%s\n", string(hash))
+	fmt.Fprintln(c.App.Writer, hash)
 	return nil
 }
 

+ 4 - 13
user/manager.go

@@ -1015,11 +1015,11 @@ func (a *Manager) addUserTx(tx *sql.Tx, username, password string, role Role, ha
 	var err error = nil
 	if hashed {
 		hash = password
-		if err := AllowedPasswordHash(hash); err != nil {
+		if err := ValidPasswordHash(hash); err != nil {
 			return err
 		}
 	} else {
-		hash, err = a.HashPassword(password)
+		hash, err = hashPassword(password, a.config.BcryptCost)
 		if err != nil {
 			return err
 		}
@@ -1365,11 +1365,11 @@ func (a *Manager) changePasswordTx(tx *sql.Tx, username, password string, hashed
 	var err error
 	if hashed {
 		hash = password
-		if err := AllowedPasswordHash(hash); err != nil {
+		if err := ValidPasswordHash(hash); err != nil {
 			return err
 		}
 	} else {
-		hash, err = a.HashPassword(password)
+		hash, err = hashPassword(password, a.config.BcryptCost)
 		if err != nil {
 			return err
 		}
@@ -1697,15 +1697,6 @@ func (a *Manager) readTier(rows *sql.Rows) (*Tier, error) {
 	}, nil
 }
 
-// HashPassword hashes the given password using bcrypt with the configured cost
-func (a *Manager) HashPassword(password string) (string, error) {
-	hash, err := bcrypt.GenerateFromPassword([]byte(password), a.config.BcryptCost)
-	if err != nil {
-		return "", err
-	}
-	return string(hash), nil
-}
-
 // Close closes the underlying database
 func (a *Manager) Close() error {
 	return a.db.Close()

+ 0 - 54
user/types.go

@@ -4,9 +4,7 @@ import (
 	"errors"
 	"github.com/stripe/stripe-go/v74"
 	"heckel.io/ntfy/v2/log"
-	"heckel.io/ntfy/v2/util"
 	"net/netip"
-	"regexp"
 	"strings"
 	"time"
 )
@@ -244,58 +242,6 @@ const (
 	everyoneID = "u_everyone"
 )
 
-var (
-	allowedUsernameRegex     = regexp.MustCompile(`^[-_.+@a-zA-Z0-9]+$`)    // Does not include Everyone (*)
-	allowedTopicRegex        = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`)  // No '*'
-	allowedTopicPatternRegex = regexp.MustCompile(`^[-_*A-Za-z0-9]{1,64}$`) // Adds '*' for wildcards!
-	allowedTierRegex         = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`)
-	allowedTokenRegex        = regexp.MustCompile(`^tk_[-_A-Za-z0-9]{29}$`) // Must be tokenLength-len(tokenPrefix)
-)
-
-// AllowedRole returns true if the given role can be used for new users
-func AllowedRole(role Role) bool {
-	return role == RoleUser || role == RoleAdmin
-}
-
-// AllowedUsername returns true if the given username is valid
-func AllowedUsername(username string) bool {
-	return allowedUsernameRegex.MatchString(username)
-}
-
-// AllowedTopic returns true if the given topic name is valid
-func AllowedTopic(topic string) bool {
-	return allowedTopicRegex.MatchString(topic)
-}
-
-// AllowedTopicPattern returns true if the given topic pattern is valid; this includes the wildcard character (*)
-func AllowedTopicPattern(topic string) bool {
-	return allowedTopicPatternRegex.MatchString(topic)
-}
-
-// AllowedTier returns true if the given tier name is valid
-func AllowedTier(tier string) bool {
-	return allowedTierRegex.MatchString(tier)
-}
-
-// AllowedPasswordHash checks if the given password hash is a valid bcrypt hash
-func AllowedPasswordHash(hash string) error {
-	if !strings.HasPrefix(hash, "$2a$") && !strings.HasPrefix(hash, "$2b$") && !strings.HasPrefix(hash, "$2y$") {
-		return ErrPasswordHashInvalid
-	}
-	return nil
-}
-
-// AllowedToken returns true if the given token matches the naming convention
-func AllowedToken(token string) bool {
-	return allowedTokenRegex.MatchString(token)
-}
-
-// GenerateToken generates a new token with a prefix and a fixed length
-// Lowercase only to support "<topic>+<token>@<domain>" email addresses
-func GenerateToken() string {
-	return util.RandomLowerStringPrefix(tokenPrefix, tokenLength)
-}
-
 // Error constants used by the package
 var (
 	ErrUnauthenticated     = errors.New("unauthenticated")

+ 73 - 0
user/util.go

@@ -0,0 +1,73 @@
+package user
+
+import (
+	"golang.org/x/crypto/bcrypt"
+	"heckel.io/ntfy/v2/util"
+	"regexp"
+	"strings"
+)
+
+var (
+	allowedUsernameRegex     = regexp.MustCompile(`^[-_.+@a-zA-Z0-9]+$`)    // Does not include Everyone (*)
+	allowedTopicRegex        = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`)  // No '*'
+	allowedTopicPatternRegex = regexp.MustCompile(`^[-_*A-Za-z0-9]{1,64}$`) // Adds '*' for wildcards!
+	allowedTierRegex         = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`)
+	allowedTokenRegex        = regexp.MustCompile(`^tk_[-_A-Za-z0-9]{29}$`) // Must be tokenLength-len(tokenPrefix)
+)
+
+// AllowedRole returns true if the given role can be used for new users
+func AllowedRole(role Role) bool {
+	return role == RoleUser || role == RoleAdmin
+}
+
+// AllowedUsername returns true if the given username is valid
+func AllowedUsername(username string) bool {
+	return allowedUsernameRegex.MatchString(username)
+}
+
+// AllowedTopic returns true if the given topic name is valid
+func AllowedTopic(topic string) bool {
+	return allowedTopicRegex.MatchString(topic)
+}
+
+// AllowedTopicPattern returns true if the given topic pattern is valid; this includes the wildcard character (*)
+func AllowedTopicPattern(topic string) bool {
+	return allowedTopicPatternRegex.MatchString(topic)
+}
+
+// AllowedTier returns true if the given tier name is valid
+func AllowedTier(tier string) bool {
+	return allowedTierRegex.MatchString(tier)
+}
+
+// ValidPasswordHash checks if the given password hash is a valid bcrypt hash
+func ValidPasswordHash(hash string) error {
+	if !strings.HasPrefix(hash, "$2a$") && !strings.HasPrefix(hash, "$2b$") && !strings.HasPrefix(hash, "$2y$") {
+		return ErrPasswordHashInvalid
+	}
+	return nil
+}
+
+// ValidToken returns true if the given token matches the naming convention
+func ValidToken(token string) bool {
+	return allowedTokenRegex.MatchString(token)
+}
+
+// GenerateToken generates a new token with a prefix and a fixed length
+// Lowercase only to support "<topic>+<token>@<domain>" email addresses
+func GenerateToken() string {
+	return util.RandomLowerStringPrefix(tokenPrefix, tokenLength)
+}
+
+// HashPassword hashes the given password using bcrypt with the configured cost
+func HashPassword(password string) (string, error) {
+	return hashPassword(password, DefaultUserPasswordBcryptCost)
+}
+
+func hashPassword(password string, cost int) (string, error) {
+	hash, err := bcrypt.GenerateFromPassword([]byte(password), cost)
+	if err != nil {
+		return "", err
+	}
+	return string(hash), nil
+}