args... still needs charset minimums (how?)
This commit is contained in:
		
							parent
							
								
									1cb6879786
								
							
						
					
					
						commit
						480dcd7e24
					
				
							
								
								
									
										42
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | *.7z | ||||||
|  | *.bak | ||||||
|  | *.deb | ||||||
|  | *.jar | ||||||
|  | *.rar | ||||||
|  | *.run | ||||||
|  | *.sig | ||||||
|  | *.tar | ||||||
|  | *.tar.bz2 | ||||||
|  | *.tar.gz | ||||||
|  | *.tar.xz | ||||||
|  | *.tbz | ||||||
|  | *.tbz2 | ||||||
|  | *.tgz | ||||||
|  | *.txz | ||||||
|  | *.zip | ||||||
|  | .*.swp | ||||||
|  | .editix | ||||||
|  | .idea/ | ||||||
|  | 
 | ||||||
|  | # https://github.com/github/gitignore/blob/master/Go.gitignore | ||||||
|  | # Binaries for programs and plugins | ||||||
|  | *.exe | ||||||
|  | *.exe~ | ||||||
|  | *.dll | ||||||
|  | *.so | ||||||
|  | *.dylib | ||||||
|  | 
 | ||||||
|  | # Test binary, built with `go test -c` | ||||||
|  | *.test | ||||||
|  | !*test.go | ||||||
|  | 
 | ||||||
|  | # Built binaries | ||||||
|  | bin/* | ||||||
|  | /pwgen | ||||||
|  | /cmd/pwgen/pwgen | ||||||
|  | 
 | ||||||
|  | # Output of the go coverage tool, specifically when used with LiteIDE | ||||||
|  | *.out | ||||||
|  | 
 | ||||||
|  | # Dependency directories (remove the comment below to include it) | ||||||
|  | # vendor/ | ||||||
							
								
								
									
										2
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								TODO
									
									
									
									
									
								
							| @ -1,3 +1,5 @@ | |||||||
|  | - whitespace (specifically, ' ') | ||||||
|  | 
 | ||||||
| - "Human Readability"? | - "Human Readability"? | ||||||
| 
 | 
 | ||||||
| - Hash/Salted hash generator | - Hash/Salted hash generator | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								cmd/pwgen/args.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/pwgen/args.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | // Arguments contains the invocation arguments. | ||||||
|  | type Arguments struct { | ||||||
|  | 	NoAlpha       bool `short:"a" long:"disable-alpha" description:"If specified, do NOT include the Alphabetical (letter) charset."` | ||||||
|  | 	NoNum         bool `short:"n" long:"disable-num" description:"If specified, do NOT include the Numerical (number) charset."` | ||||||
|  | 	NoSymbols     bool `short:"s" long:"disable-symbols" description:"If specified, do NOT include the Simple Symbols charset."` | ||||||
|  | 	ExtendSymbols bool `short:"S" long:"enable-extended-symbols" description:"If specified, include the Extended Symbols charset (these characters may cause issues in some applications)."` | ||||||
|  | 	NumUpper      uint `short:"u" long:"count-upper" description:"The number of minimum uppercase characters. If not specified, this is random (if in the charset)."` | ||||||
|  | 	NumLower      uint `short:"U" long:"count-lower" description:"The number of minimum lowercase characters. If not specified, this is random (if in the charset)."` | ||||||
|  | 	NumSymbols    uint `short:"y" long:"count-symbols" description:"The number of minimum simple symbol characters. If not specified, this is random (if in the charset)."` | ||||||
|  | 	NumExtended   uint `short:"Y" long:"count-extended" description:"The number of minimum extended symbol characters. If not specified, this is random (if in the charset)."` | ||||||
|  | 	DisableChars  uint `short:"d" long:"disable-chars" description:"If specified, this string of chars should be explicitly excluded from the charset(s)."` | ||||||
|  | 	MinLen        uint `short:"l" long:"min-length" default:"16" description:"The minimum length for passwords; use 0 for no minimum limit. Set this to the same as -L/--max-length to use a fixed length."` | ||||||
|  | 	MaxLen        uint `short:"L" long:"max-length" default:"64" description:"The maximum length for passwords; use 0 for no maximum limit (this is hard-capped to 256 for performance reasons). Set this to the same as -l/--min-length for a fixed length. Must be >= -l/--min-length."` | ||||||
|  | 	Count         uint `short:"c" long:"count" default:"1" description:"The number of passwords to generate."` | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								cmd/pwgen/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								cmd/pwgen/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 
 | ||||||
|  | 	"github.com/jessevdk/go-flags" | ||||||
|  | 	"r00t2.io/pwgen/pwgenerator" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var a Arguments | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 
 | ||||||
|  | 	var err error | ||||||
|  | 	var genOpts *pwgenerator.GenOpts | ||||||
|  | 
 | ||||||
|  | 	if _, err = flags.Parse(&a); err != nil { | ||||||
|  | 		switch flagsErr := err.(type) { | ||||||
|  | 		case *flags.Error: | ||||||
|  | 			if flagsErr.Type == flags.ErrHelp { | ||||||
|  | 				os.Exit(0) | ||||||
|  | 			} | ||||||
|  | 			log.Panicln(err) | ||||||
|  | 		default: | ||||||
|  | 			log.Panicln(err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	genOpts = &pwgenerator.GenOpts{ | ||||||
|  | 		Alpha:           !a.NoAlpha, | ||||||
|  | 		Numeric:         !a.NoNum, | ||||||
|  | 		Symbols:         !a.NoSymbols, | ||||||
|  | 		ExtendedSymbols: a.ExtendSymbols, | ||||||
|  | 		CountUpper:      a.NumUpper, | ||||||
|  | 		CountLower:      a.NumLower, | ||||||
|  | 		CountSymbols:    a.NumSymbols, | ||||||
|  | 		CountExtended:   a.NumExtended, | ||||||
|  | 		DisabledChars:   nil, | ||||||
|  | 		LengthMin:       a.MinLen, | ||||||
|  | 		LengthMax:       a.MaxLen, | ||||||
|  | 		Count:           a.Count, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fmt.Printf("%#v\n", a) | ||||||
|  | 	fmt.Printf("%#v\n", genOpts) | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								go.mod
									
									
									
									
									
								
							| @ -1,3 +1,10 @@ | |||||||
| module r00t2.io/pwgen | module r00t2.io/pwgen | ||||||
| 
 | 
 | ||||||
| go 1.17 | go 1.17 | ||||||
|  | 
 | ||||||
|  | require ( | ||||||
|  | 	github.com/jessevdk/go-flags v1.5.0 | ||||||
|  | 	r00t2.io/goutils v1.3.1 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | require golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||||
|  | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||||
|  | github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= | ||||||
|  | github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= | ||||||
|  | golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= | ||||||
|  | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | r00t2.io/goutils v1.3.1 h1:mk8B2v7fM3gYoX64CDV206+/j8Z5iSJcszcPFjuvf3o= | ||||||
|  | r00t2.io/goutils v1.3.1/go.mod h1:9ObJI9S71wDLTOahwoOPs19DhZVYrOh4LEHmQ8SW4Lk= | ||||||
|  | r00t2.io/sysutils v1.1.1/go.mod h1:Wlfi1rrJpoKBOjWiYM9rw2FaiZqraD6VpXyiHgoDo/o= | ||||||
| @ -1,5 +1,12 @@ | |||||||
| package pwgenerator | package pwgenerator | ||||||
| 
 | 
 | ||||||
|  | // Defaults. | ||||||
|  | const ( | ||||||
|  | 	DefCount  uint = 1 | ||||||
|  | 	DefMaxLen uint = 256 | ||||||
|  | 	DefMinLin uint = 1 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| // Pre-defined charsets. | // Pre-defined charsets. | ||||||
| var ( | var ( | ||||||
| 	// upper contains the characters from 0x41 to 0x5a ([A-Z]). | 	// upper contains the characters from 0x41 to 0x5a ([A-Z]). | ||||||
|  | |||||||
| @ -6,4 +6,6 @@ import ( | |||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| 	ErrBadType           error = errors.New("cannot typeswitch; unsupported type") | 	ErrBadType           error = errors.New("cannot typeswitch; unsupported type") | ||||||
|  | 	ErrTooSmall          error = errors.New("password max length too short for specified required chars") | ||||||
|  | 	ErrSwitchedLenLimits error = errors.New("the max password length is shorter than the minimum password length") | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -1,6 +1,9 @@ | |||||||
| package pwgenerator | package pwgenerator | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"math/big" | ||||||
| 	"sort" | 	"sort" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -31,3 +34,26 @@ func sortDedupe(charset *CharSet) { | |||||||
| 
 | 
 | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | 	saferRandInt uses crypto/rand instead of math/rand to get a random number. | ||||||
|  | 
 | ||||||
|  | 	While this is cryptographically safer, I guarantee it's a much bigger pain to do. | ||||||
|  | */ | ||||||
|  | func saferRandInt(max int) (randInt int, err error) { | ||||||
|  | 
 | ||||||
|  | 	var max64 int64 = int64(max) | ||||||
|  | 	var cryptoInt *big.Int = big.NewInt(max64) | ||||||
|  | 	var cryptoReader *bytes.Buffer = new(bytes.Buffer) | ||||||
|  | 	var randInt64 int64 | ||||||
|  | 
 | ||||||
|  | 	if cryptoInt, err = rand.Int(cryptoReader, cryptoInt); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	randInt64 = cryptoInt.Int64() | ||||||
|  | 
 | ||||||
|  | 	randInt = int(randInt64) | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | |||||||
| @ -18,6 +18,20 @@ func (c *CharSet) Less(i, j int) (isBefore bool) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // RandChar returns a random character from a CharSet. | ||||||
|  | func (c *CharSet) RandChar() (char Char, err error) { | ||||||
|  | 
 | ||||||
|  | 	var selectIdx int | ||||||
|  | 
 | ||||||
|  | 	if selectIdx, err = saferRandInt(len(*c) - 1); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	char = (*c)[selectIdx] | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // String returns a string from a CharSet. | // String returns a string from a CharSet. | ||||||
| func (c *CharSet) String() (s string) { | func (c *CharSet) String() (s string) { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,12 +2,86 @@ package pwgenerator | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"r00t2.io/goutils/multierr" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Generate generates a list of passwords for a GenOpts. | // Generate generates a list of passwords for a GenOpts. | ||||||
| func (o *GenOpts) Generate() (passwords []string, err error) { | func (o *GenOpts) Generate() (passwords []string, err error) { | ||||||
| 
 | 
 | ||||||
| 	// TODO | 	var passwds []string = make([]string, o.Count) | ||||||
|  | 	var charset CharSet = o.Chars() | ||||||
|  | 	var errs *multierr.MultiError = multierr.NewMultiError(nil) | ||||||
|  | 
 | ||||||
|  | 	if o.Count == 0 { | ||||||
|  | 		o.Count = DefCount | ||||||
|  | 	} | ||||||
|  | 	if o.LengthMax == 0 { | ||||||
|  | 		o.LengthMax = DefMaxLen | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for idx, _ := range passwds { | ||||||
|  | 		if passwds[idx], err = o.generatePassword(charset); err != nil { | ||||||
|  | 			errs.AddError(err) | ||||||
|  | 			err = nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	passwords = passwds | ||||||
|  | 
 | ||||||
|  | 	if !errs.IsEmpty() { | ||||||
|  | 		err = errs | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // generatePassword generates a single password from CharSet c. | ||||||
|  | func (o *GenOpts) generatePassword(c CharSet) (password string, err error) { | ||||||
|  | 
 | ||||||
|  | 	var maxMin uint | ||||||
|  | 	var trueMinLen uint | ||||||
|  | 	var passLenGap uint | ||||||
|  | 	var passLen int | ||||||
|  | 	var passAlloc []rune | ||||||
|  | 
 | ||||||
|  | 	// Sanity checks/error conditions. | ||||||
|  | 	maxMin = o.CountUpper + o.CountLower + o.CountSymbols + o.CountExtended | ||||||
|  | 	if maxMin > o.LengthMax { | ||||||
|  | 		err = ErrTooSmall | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if o.LengthMin > o.LengthMax { | ||||||
|  | 		err = ErrSwitchedLenLimits | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Defaults. | ||||||
|  | 	trueMinLen = o.LengthMin | ||||||
|  | 	if trueMinLen == 0 { | ||||||
|  | 		trueMinLen = DefMinLin | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Get a fixed password length... | ||||||
|  | 	passLenGap = o.LengthMax - trueMinLen | ||||||
|  | 	if passLen, err = saferRandInt(int(passLenGap)); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	passLen = passLen + int(trueMinLen) // (We need to re-add; it was subtracted above to get a zero-shifted number for start in saferRandInt.) | ||||||
|  | 	// And make the rune slice of that length. | ||||||
|  | 	passAlloc = make([]rune, passLen) | ||||||
|  | 
 | ||||||
|  | 	for _, idx := range passAlloc { | ||||||
|  | 		var char Char | ||||||
|  | 
 | ||||||
|  | 		if char, err = c.RandChar(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		passAlloc[idx] = rune(char) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	password = string(passAlloc) | ||||||
| 
 | 
 | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| @ -35,6 +109,8 @@ func (o *GenOpts) Chars() (chars CharSet) { | |||||||
| 		chars = append(chars, extendedSymbols...) | 		chars = append(chars, extendedSymbols...) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// TODO: Count* fields | ||||||
|  | 
 | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user