Skip to content

Commit

Permalink
fix: reworked GeneratePassword to use secure crypt random generator
Browse files Browse the repository at this point in the history
  • Loading branch information
klajdi369 committed Sep 10, 2024
1 parent 07a44bc commit fb1a58c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 11 deletions.
6 changes: 5 additions & 1 deletion internal/api/magic_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ func (a *API) MagicLink(w http.ResponseWriter, r *http.Request) error {
if isNewUser {
// User either doesn't exist or hasn't completed the signup process.
// Sign them up with temporary password.
password := utilities.GeneratePassword(config.Password.RequiredCharacters, 33)
password, err := utilities.GeneratePassword(config.Password.RequiredCharacters, 33)
if err != nil {
// password generation must succeed
panic(err)
}

signUpParams := &SignupParams{
Email: params.Email,
Expand Down
45 changes: 35 additions & 10 deletions internal/utilities/password.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package utilities

import (
"math/rand"
"crypto/rand"
"math/big"
"strings"
)

Expand All @@ -12,29 +13,53 @@ func parseGroups(requiredChars []string) []string {
return groups
}

func GeneratePassword(requiredChars []string, length int) string {

func GeneratePassword(requiredChars []string, length int) (string, error) {
groups := parseGroups(requiredChars)
passwordBuilder := strings.Builder{}
passwordBuilder.Grow(length)

// Add required characters
for _, group := range groups {
if len(group) > 0 {
passwordBuilder.WriteString(string(group[rand.Intn(len(group))]))
randomIndex, err := secureRandomInt(len(group))
if err != nil {
return "", err
}
passwordBuilder.WriteByte(group[randomIndex])
}
}

// Define a default character set for random generation (if needed)
allChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

// Fill the rest of the password
for passwordBuilder.Len() < length {
passwordBuilder.WriteString(string(allChars[rand.Intn(len(allChars))]))
randomIndex, err := secureRandomInt(len(allChars))
if err != nil {
return "", err
}
passwordBuilder.WriteByte(allChars[randomIndex])
}

password := passwordBuilder.String()
passwordBytes := []byte(password)
rand.Shuffle(len(passwordBytes), func(i, j int) {
// Convert to byte slice for shuffling
passwordBytes := []byte(passwordBuilder.String())

// Secure shuffling
for i := len(passwordBytes) - 1; i > 0; i-- {
j, err := secureRandomInt(i + 1)
if err != nil {
return "", err
}
passwordBytes[i], passwordBytes[j] = passwordBytes[j], passwordBytes[i]
})
}

return string(passwordBytes), nil
}

return string(passwordBytes)
func secureRandomInt(max int) (int, error) {
randomInt, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
if err != nil {
return 0, err
}
return int(randomInt.Int64()), nil
}

0 comments on commit fb1a58c

Please sign in to comment.