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]).
|
||||||
|
@ -5,5 +5,7 @@ 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…
Reference in New Issue
Block a user