Add password generation UI profile workflow
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -16,6 +17,7 @@ const (
|
||||
)
|
||||
|
||||
var ErrImpossibleProfile = errors.New("impossible password profile")
|
||||
var ErrUnknownProfile = errors.New("unknown password profile")
|
||||
|
||||
type Profile struct {
|
||||
Name string
|
||||
@@ -61,6 +63,31 @@ func DefaultProfiles() map[string]Profile {
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultProfileNames() []string {
|
||||
return ProfileNames(DefaultProfiles())
|
||||
}
|
||||
|
||||
func LookupProfile(name string, profiles map[string]Profile) (Profile, error) {
|
||||
profile, ok := profiles[strings.TrimSpace(name)]
|
||||
if !ok {
|
||||
return Profile{}, fmt.Errorf("%w %q", ErrUnknownProfile, strings.TrimSpace(name))
|
||||
}
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func LookupDefaultProfile(name string) (Profile, error) {
|
||||
return LookupProfile(name, DefaultProfiles())
|
||||
}
|
||||
|
||||
func ProfileNames(profiles map[string]Profile) []string {
|
||||
names := make([]string, 0, len(profiles))
|
||||
for name := range profiles {
|
||||
names = append(names, name)
|
||||
}
|
||||
slices.Sort(names)
|
||||
return names
|
||||
}
|
||||
|
||||
func Generate(profile Profile) (string, error) {
|
||||
if err := validateProfile(profile); err != nil {
|
||||
return "", err
|
||||
|
||||
+40
-11
@@ -1,6 +1,8 @@
|
||||
package passwords
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -9,17 +11,17 @@ func TestGenerateRespectsProfileRequirements(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
profile := Profile{
|
||||
Name: "strong",
|
||||
Length: 24,
|
||||
Lowercase: true,
|
||||
Uppercase: true,
|
||||
Digits: true,
|
||||
Symbols: true,
|
||||
MinLowercase: 2,
|
||||
MinUppercase: 2,
|
||||
MinDigits: 2,
|
||||
MinSymbols: 2,
|
||||
ExcludeSimilar: true,
|
||||
Name: "strong",
|
||||
Length: 24,
|
||||
Lowercase: true,
|
||||
Uppercase: true,
|
||||
Digits: true,
|
||||
Symbols: true,
|
||||
MinLowercase: 2,
|
||||
MinUppercase: 2,
|
||||
MinDigits: 2,
|
||||
MinSymbols: 2,
|
||||
ExcludeSimilar: true,
|
||||
}
|
||||
|
||||
password, err := Generate(profile)
|
||||
@@ -86,6 +88,33 @@ func TestProfileSetReturnsNamedProfiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultProfileNamesReturnsSortedNames(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := DefaultProfileNames()
|
||||
want := []string{"memorable", "strong"}
|
||||
if !slices.Equal(got, want) {
|
||||
t.Fatalf("DefaultProfileNames() = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupDefaultProfileResolvesKnownProfilesAndRejectsUnknownNames(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
profile, err := LookupDefaultProfile(" strong ")
|
||||
if err != nil {
|
||||
t.Fatalf("LookupDefaultProfile(\" strong \") error = %v", err)
|
||||
}
|
||||
if profile.Name != "strong" {
|
||||
t.Fatalf("LookupDefaultProfile(\" strong \").Name = %q, want %q", profile.Name, "strong")
|
||||
}
|
||||
|
||||
_, err = LookupDefaultProfile("invalid")
|
||||
if !errors.Is(err, ErrUnknownProfile) {
|
||||
t.Fatalf("LookupDefaultProfile(\"invalid\") error = %v, want ErrUnknownProfile", err)
|
||||
}
|
||||
}
|
||||
|
||||
func countFromSet(password, chars string) int {
|
||||
count := 0
|
||||
for _, r := range password {
|
||||
|
||||
Reference in New Issue
Block a user