package auth import ( "context" "errors" "fmt" "strings" "codeberg.org/maxwelljensen/weimar/internal/db" "golang.org/x/crypto/bcrypt" ) var ( ErrUsernameTaken = errors.New("username already taken") ErrPasswordTooShort = errors.New("password must be at least 8 characters") ErrUsernameTooShort = errors.New("username must be at least 3 characters") ErrRegistrationClosed = errors.New("registration is closed") ) const ( MinPasswordLength = 8 MinUsernameLength = 3 bcryptCost = 12 ) // Register creates a new user account. If allowRegistration is false it // returns ErrRegistrationClosed. func Register(ctx context.Context, database *db.DB, username, password string, isAdmin bool) (*db.User, error) { if len(username) < MinUsernameLength { return nil, ErrUsernameTooShort } if len(password) < MinPasswordLength { return nil, ErrPasswordTooShort } hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost) if err != nil { return nil, fmt.Errorf("hash password: %w", err) } user, err := database.CreateUser(ctx, username, string(hash), isAdmin) if err != nil { if isUniqueViolation(err) { return nil, ErrUsernameTaken } return nil, fmt.Errorf("create user: %w", err) } return user, nil } func isUniqueViolation(err error) bool { return err != nil && strings.Contains(err.Error(), "UNIQUE constraint failed") }