From aa3580c248a0cff125c13e8ce636d9576a907f43 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Sun, 26 Feb 2023 10:24:06 +0100 Subject: [PATCH] Migrat pkg/password to using pkglib package --- internal/config/password.go | 9 +- internal/config/template.go | 12 ++- internal/dis/component/auth/user.go | 5 +- internal/dis/component/exporter/exporter.go | 7 +- internal/passwordx/charset.go | 9 ++ internal/passwordx/common.go | 23 +++++ .../passwordx}/common/top10_000.txt | 0 .../passwordx}/common/wisski.txt | 0 .../wisski/ingredient/php/users/password.go | 5 +- pkg/password/common.go | 96 ------------------- pkg/password/password.go | 48 ---------- 11 files changed, 56 insertions(+), 158 deletions(-) create mode 100644 internal/passwordx/charset.go create mode 100644 internal/passwordx/common.go rename {pkg/password => internal/passwordx}/common/top10_000.txt (100%) rename {pkg/password => internal/passwordx}/common/wisski.txt (100%) delete mode 100644 pkg/password/common.go delete mode 100644 pkg/password/password.go diff --git a/internal/config/password.go b/internal/config/password.go index e44dd25..49e44a1 100644 --- a/internal/config/password.go +++ b/internal/config/password.go @@ -1,8 +1,13 @@ package config -import "github.com/FAU-CDI/wisski-distillery/pkg/password" +import ( + "crypto/rand" + + "github.com/FAU-CDI/wisski-distillery/internal/passwordx" + "github.com/tkw1536/pkglib/password" +) // NewPassword returns a new password using the password settings from this configuration func (cfg Config) NewPassword() (string, error) { - return password.Password(cfg.PasswordLength) + return password.Generate(rand.Reader, cfg.PasswordLength, passwordx.Charset) } diff --git a/internal/config/template.go b/internal/config/template.go index 0477d8d..2f9357f 100644 --- a/internal/config/template.go +++ b/internal/config/template.go @@ -1,13 +1,15 @@ package config import ( + "crypto/rand" "path/filepath" "time" "github.com/FAU-CDI/wisski-distillery/internal/bootstrap" + "github.com/FAU-CDI/wisski-distillery/internal/passwordx" "github.com/FAU-CDI/wisski-distillery/pkg/environment" - "github.com/FAU-CDI/wisski-distillery/pkg/password" "github.com/tkw1536/pkglib/hostname" + "github.com/tkw1536/pkglib/password" ) // Template is a template for the configuration file @@ -47,7 +49,7 @@ func (tpl *Template) SetDefaults(env environment.Environment) (err error) { } if tpl.TriplestoreAdminPassword == "" { - tpl.TriplestoreAdminPassword, err = password.Password(64) + tpl.TriplestoreAdminPassword, err = password.Generate(rand.Reader, 64, passwordx.Charset) if err != nil { return err } @@ -58,14 +60,14 @@ func (tpl *Template) SetDefaults(env environment.Environment) (err error) { } if tpl.MysqlAdminPassword == "" { - tpl.MysqlAdminPassword, err = password.Password(64) + tpl.MysqlAdminPassword, err = password.Generate(rand.Reader, 64, passwordx.Charset) if err != nil { return err } } if tpl.DockerNetworkName == "" { - tpl.DockerNetworkName, err = password.Password(10) + tpl.DockerNetworkName, err = password.Generate(rand.Reader, 10, passwordx.Charset) if err != nil { return err } @@ -73,7 +75,7 @@ func (tpl *Template) SetDefaults(env environment.Environment) (err error) { } if tpl.SessionSecret == "" { - tpl.SessionSecret, err = password.Password(100) + tpl.SessionSecret, err = password.Generate(rand.Reader, 100, passwordx.Charset) if err != nil { return err } diff --git a/internal/dis/component/auth/user.go b/internal/dis/component/auth/user.go index 1330c3e..435f169 100644 --- a/internal/dis/component/auth/user.go +++ b/internal/dis/component/auth/user.go @@ -9,10 +9,11 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/dis/component" "github.com/FAU-CDI/wisski-distillery/internal/models" - "github.com/FAU-CDI/wisski-distillery/pkg/password" + "github.com/FAU-CDI/wisski-distillery/internal/passwordx" "github.com/pkg/errors" "github.com/pquerna/otp" "github.com/pquerna/otp/totp" + "github.com/tkw1536/pkglib/password" "github.com/tkw1536/pkglib/pools" "github.com/tkw1536/pkglib/reflectx" "golang.org/x/crypto/bcrypt" @@ -263,7 +264,7 @@ func (auth *Auth) CheckPasswordPolicy(candidate string, username string) error { return ErrPolicyTooShort } - if err := password.CheckCommonPassword(func(common string) (bool, error) { return common == candidate, nil }); err != nil { + if err := password.CheckCommonPassword(func(common string) (bool, error) { return common == candidate, nil }, passwordx.Sources...); err != nil { return ErrPolicyKnown } diff --git a/internal/dis/component/exporter/exporter.go b/internal/dis/component/exporter/exporter.go index 2f60cd1..bd46a12 100644 --- a/internal/dis/component/exporter/exporter.go +++ b/internal/dis/component/exporter/exporter.go @@ -1,18 +1,19 @@ package exporter import ( + "crypto/rand" "fmt" "path/filepath" "time" "github.com/FAU-CDI/wisski-distillery/internal/dis/component" - "github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter/logger" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances" "github.com/FAU-CDI/wisski-distillery/internal/dis/component/sql" + "github.com/FAU-CDI/wisski-distillery/internal/passwordx" "github.com/FAU-CDI/wisski-distillery/pkg/environment" "github.com/FAU-CDI/wisski-distillery/pkg/fsx" - "github.com/FAU-CDI/wisski-distillery/pkg/password" + "github.com/tkw1536/pkglib/password" ) // Exporter manages snapshots and backups @@ -59,7 +60,7 @@ func (dis *Exporter) NewArchivePath(prefix string) (path string) { // newSnapshot name returns a new basename for a snapshot with the provided prefix. // The name is guaranteed to be unique within this process. func (*Exporter) newSnapshotName(prefix string) string { - suffix, _ := password.Password(10) // silently ignore any errors! + suffix, _ := password.Generate(rand.Reader, 10, passwordx.Snapshot) // silently ignore any errors! if prefix == "" { prefix = "backup" } else { diff --git a/internal/passwordx/charset.go b/internal/passwordx/charset.go new file mode 100644 index 0000000..de62126 --- /dev/null +++ b/internal/passwordx/charset.go @@ -0,0 +1,9 @@ +package passwordx + +import "github.com/tkw1536/pkglib/password" + +// Charset is a Charset safe for usage within the distillery +const Charset = password.DefaultCharSet + +// Snapshot is a charset to be used to generate snapshot ids +const Snapshot = password.DefaultCharSet diff --git a/internal/passwordx/common.go b/internal/passwordx/common.go new file mode 100644 index 0000000..f266b89 --- /dev/null +++ b/internal/passwordx/common.go @@ -0,0 +1,23 @@ +package passwordx + +import ( + "embed" + + "github.com/tkw1536/pkglib/password" +) + +//go:embed common +var commonEmbed embed.FS + +var Sources []password.PasswordSource + +func init() { + var err error + Sources, err = password.NewSources(commonEmbed, "**/*.txt") + if err != nil { + panic(err) + } + if len(Sources) == 0 { + panic("no sources") + } +} diff --git a/pkg/password/common/top10_000.txt b/internal/passwordx/common/top10_000.txt similarity index 100% rename from pkg/password/common/top10_000.txt rename to internal/passwordx/common/top10_000.txt diff --git a/pkg/password/common/wisski.txt b/internal/passwordx/common/wisski.txt similarity index 100% rename from pkg/password/common/wisski.txt rename to internal/passwordx/common/wisski.txt diff --git a/internal/wisski/ingredient/php/users/password.go b/internal/wisski/ingredient/php/users/password.go index c502e3e..7c7e95e 100644 --- a/internal/wisski/ingredient/php/users/password.go +++ b/internal/wisski/ingredient/php/users/password.go @@ -6,8 +6,9 @@ import ( "fmt" "io" + "github.com/FAU-CDI/wisski-distillery/internal/passwordx" "github.com/FAU-CDI/wisski-distillery/internal/phpx" - "github.com/FAU-CDI/wisski-distillery/pkg/password" + "github.com/tkw1536/pkglib/password" ) var errGetValidator = errors.New("GetPasswordValidator: Unknown Error") @@ -64,7 +65,7 @@ func (pv PasswordValidator) CheckDictionary(ctx context.Context, writer io.Write } return errPasswordUsername } - for candidate := range password.CommonPasswords() { + for candidate := range password.Passwords(passwordx.Sources...) { if ctx.Err() != nil { continue } diff --git a/pkg/password/common.go b/pkg/password/common.go deleted file mode 100644 index df359b2..0000000 --- a/pkg/password/common.go +++ /dev/null @@ -1,96 +0,0 @@ -package password - -import ( - "bufio" - "embed" - "fmt" - "io/fs" - "strings" -) - -// CommonPasswordError -type CommonPasswordError struct { - CommonPassword -} - -func (cpe CommonPasswordError) Error() string { - return fmt.Sprintf("%q from %q", cpe.Password, cpe.Source) -} - -type CommonPassword struct { - Password string - Source string -} - -//go:embed common -var commonEmbed embed.FS - -// CommonPasswords returns a channel that contains all passwords. -// The caller must drain the channel. -func CommonPasswords() <-chan CommonPassword { - pChan := make(chan CommonPassword, 10) - go func() { - defer close(pChan) - - fs.WalkDir(commonEmbed, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - - // get the full path - if d.IsDir() || !strings.HasSuffix(path, ".txt") { - return nil - } - - // open it - file, err := commonEmbed.Open(path) - if err != nil { - return err - } - defer file.Close() - - // scan it line by line - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "//") { - continue - } - pChan <- CommonPassword{ - Password: line, - Source: path, - } - } - - return scanner.Err() - }) - }() - return pChan -} - -// CheckCommonPassword checks if a password is a common password. -// -// check is called with each candidate password to perform the check. -// check should return a boolean indicating if the password in question corresponds to the candidate. -// -// CheckCommonPassword returns one of three error values. -// -// - a CommonPasswordError (when a password matches a common password) -// - an error returned by check (assuming some check went wrong) -// - or nil (when a password is not a common password -func CheckCommonPassword(check func(candidate string) (bool, error)) error { - for commmon := range CommonPasswords() { - ok, err := check(commmon.Password) - if err != nil { - return err - } - - // password validation passed - if ok { - return CommonPasswordError{ - CommonPassword: commmon, - } - } - } - return nil -} diff --git a/pkg/password/password.go b/pkg/password/password.go deleted file mode 100644 index 0957bd6..0000000 --- a/pkg/password/password.go +++ /dev/null @@ -1,48 +0,0 @@ -// Package password allows generating random passwords -package password - -import ( - "crypto/rand" - "math/big" - - "github.com/tkw1536/pkglib/pools" -) - -// NOTE(twiesing): A bunch of scripts cannot properly handle the extra characters in the password. -// For now it is disabled, but it should be re-enabled later. -const PasswordCharSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // + "!@#$%&*" -var passwordCharCount = big.NewInt(int64(len(PasswordCharSet))) - -// Password returns a randomly generated string with the provided length. -// It consists of alphanumeric characters only. -// -// When an error occurs, it is guaranteed to return "", err. -// [rand.Reader] is used as the source of randomness. -func Password(length int) (string, error) { - if length < 0 { - panic("length < 0") - } - - // create a buffer to write the string to! - password := pools.GetBuilder() - defer pools.ReleaseBuilder(password) - password.Grow(length) - - for i := 0; i < length; i++ { - - // grab a random bIndex! - bIndex, err := rand.Int(rand.Reader, passwordCharCount) - if err != nil { - return "", err - } - - // and use that index! - index := int(bIndex.Int64()) - if err := password.WriteByte(PasswordCharSet[index]); err != nil { - return "", err - } - } - - // return the password! - return password.String(), nil -}