all repos — weimar @ b26a020c4b21a1c0d9a62bc6afdf405ea2097d82

Unnamed repository; edit this file 'description' to name the repository.

internal/auth/register.go (view raw)

 1package auth
 2
 3import (
 4	"context"
 5	"errors"
 6	"fmt"
 7	"strings"
 8
 9	"github.com/mjensen/weimar/internal/db"
10	"golang.org/x/crypto/bcrypt"
11)
12
13var (
14	ErrUsernameTaken     = errors.New("username already taken")
15	ErrPasswordTooShort  = errors.New("password must be at least 8 characters")
16	ErrUsernameTooShort  = errors.New("username must be at least 3 characters")
17	ErrRegistrationClosed = errors.New("registration is closed")
18)
19
20const (
21	MinPasswordLength = 8
22	MinUsernameLength = 3
23	bcryptCost        = 12
24)
25
26// Register creates a new user account. If allowRegistration is false it
27// returns ErrRegistrationClosed.
28func Register(ctx context.Context, database *db.DB, username, password string, isAdmin bool) (*db.User, error) {
29	if len(username) < MinUsernameLength {
30		return nil, ErrUsernameTooShort
31	}
32	if len(password) < MinPasswordLength {
33		return nil, ErrPasswordTooShort
34	}
35
36	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
37	if err != nil {
38		return nil, fmt.Errorf("hash password: %w", err)
39	}
40
41	user, err := database.CreateUser(ctx, username, string(hash), isAdmin)
42	if err != nil {
43		if isUniqueViolation(err) {
44			return nil, ErrUsernameTaken
45		}
46		return nil, fmt.Errorf("create user: %w", err)
47	}
48	return user, nil
49}
50
51func isUniqueViolation(err error) bool {
52	return err != nil && strings.Contains(err.Error(), "UNIQUE constraint failed")
53}