Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: magiclink failing due to passwordStrength check #1769

Merged
merged 10 commits into from
Sep 24, 2024
7 changes: 4 additions & 3 deletions internal/api/magic_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"net/http"
"strings"

"github.com/sethvargo/go-password/password"
"github.com/supabase/auth/internal/models"
"github.com/supabase/auth/internal/storage"
"github.com/supabase/auth/internal/utilities"
)

// MagicLinkParams holds the parameters for a magic link request
Expand Down Expand Up @@ -83,9 +83,10 @@ 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, err := password.Generate(64, 10, 1, false, true)
password, err := utilities.GeneratePassword(config.Password.RequiredCharacters, 33)
if err != nil {
return internalServerError("error creating user").WithInternalError(err)
// password generation must succeed
panic(err)
}

signUpParams := &SignupParams{
Expand Down
65 changes: 65 additions & 0 deletions internal/utilities/password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package utilities

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

// parseGroups processes the required character groups from a slice of strings.
func parseGroups(requiredChars []string) []string {
var groups []string
groups = append(groups, requiredChars...)
return groups
}

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 {
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 {
randomIndex, err := secureRandomInt(len(allChars))
if err != nil {
return "", err
}
passwordBuilder.WriteByte(allChars[randomIndex])
}

// 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
}

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
}
Loading