Skip to content

Commit 781e4b1

Browse files
authored
sequencer -> odometer (#3)
1 parent 337419c commit 781e4b1

23 files changed

+793
-878
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
default: test
44

55
bench:
6-
go test -bench=. -benchmem ./passphrase ./password ./password/sequencer
6+
go test -bench=. -benchmem ./passphrase ./password ./odometer
77

88
cyclo:
99
gocyclo -over 13 ./*/*.go

README.md

+61-81
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
Passphrase & Password generation library for GoLang.
99

1010
## Passphrases
11+
12+
Passphrases are made up of 2 or more words connected by a separator and may have
13+
capitalized words, and numbers. These are easier for humans to remember compared
14+
to passwords.
15+
16+
The `passphrase` package helps generate these and supports the following rules
17+
that be used during generation:
18+
* Capitalize words used in the passphrase (foo -> Foo)
19+
* Use a custom dictionary of words instead of built-in English dictionary
20+
* Use X number of Words
21+
* Insert a random number behind one of the words
22+
* Use a custom separator
23+
* Use words with a specific length-range
24+
25+
### Example
1126
```golang
1227
g, err := passphrase.NewGenerator(
1328
passphrase.WithCapitalizedWords(true),
@@ -41,6 +56,18 @@ Passphrase # 10: "Mirks6-Woofer-Lase"
4156
</details>
4257

4358
## Passwords
59+
60+
Passwords are a random amalgamation of characters.
61+
62+
The `password` package helps generate these and supports the following rules
63+
that be used during generation:
64+
* Use a specific character-set
65+
* Restrict the length of the password
66+
* Use *at least* X lower-case characters
67+
* Use *at least* X upper-case characters
68+
* Use *at least* X and *at most* Y symbols
69+
70+
### Example
4471
```golang
4572
g, err := password.NewGenerator(
4673
password.WithCharset(charset.AllChars.WithoutAmbiguity().WithoutDuplicates()),
@@ -72,23 +99,30 @@ Password # 10: "kmQVb&fPqexj"
7299
</pre>
73100
</details>
74101

75-
### Sequential Passwords
102+
## Odometer
103+
104+
Odometer helps generate all possible string combinations of characters given a
105+
list of characters and the expected length of the string.
106+
107+
The `odometer` package provides optimal interfaces to move through the list:
108+
* Decrement()
109+
* DecrementN(n)
110+
* GoTo(n)
111+
* Increment()
112+
* IncrementN(n)
113+
* etc.
76114

115+
### Example
77116
```golang
78-
s, err := sequencer.New(
79-
sequencer.WithCharset(charset.AllChars.WithoutAmbiguity()),
80-
sequencer.WithLength(8),
81-
)
82-
if err != nil {
83-
panic(err.Error())
84-
}
117+
o := odometer.New(charset.AlphabetsUpper, 8)
118+
85119
for idx := 1; idx <= 10; idx++ {
86-
fmt.Printf("Password #%3d: %#v\n", idx, s.Get())
120+
fmt.Printf("Password #%3d: %#v\n", idx, o.String())
87121

88-
if !s.HasNext() {
122+
if o.AtEnd() {
89123
break
90124
}
91-
s.Next()
125+
o.Increment()
92126
}
93127
```
94128
<details>
@@ -102,65 +136,8 @@ Password # 5: "AAAAAAAE"
102136
Password # 6: "AAAAAAAF"
103137
Password # 7: "AAAAAAAG"
104138
Password # 8: "AAAAAAAH"
105-
Password # 9: "AAAAAAAJ"
106-
Password # 10: "AAAAAAAK"
107-
</pre>
108-
</details>
109-
110-
#### Streamed (for async processing)
111-
```golang
112-
s, err := sequencer.New(
113-
sequencer.WithCharset(charset.Charset("AB")),
114-
sequencer.WithLength(4),
115-
)
116-
if err != nil {
117-
panic(err.Error())
118-
}
119-
120-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
121-
defer cancel()
122-
123-
chPasswords := make(chan string, 1)
124-
go func() {
125-
err := s.Stream(ctx, chPasswords)
126-
if err != nil {
127-
panic(err.Error())
128-
}
129-
}()
130-
131-
idx := 0
132-
for {
133-
select {
134-
case <-ctx.Done():
135-
panic("timed out")
136-
case pw, ok := <-chPasswords:
137-
if !ok {
138-
return
139-
}
140-
idx++
141-
fmt.Printf("Password #%3d: %#v\n", idx, pw)
142-
}
143-
}
144-
```
145-
<details>
146-
<summary>Output...</summary>
147-
<pre>
148-
Password # 1: "AAAA"
149-
Password # 2: "AAAB"
150-
Password # 3: "AABA"
151-
Password # 4: "AABB"
152-
Password # 5: "ABAA"
153-
Password # 6: "ABAB"
154-
Password # 7: "ABBA"
155-
Password # 8: "ABBB"
156-
Password # 9: "BAAA"
157-
Password # 10: "BAAB"
158-
Password # 11: "BABA"
159-
Password # 12: "BABB"
160-
Password # 13: "BBAA"
161-
Password # 14: "BBAB"
162-
Password # 15: "BBBA"
163-
Password # 16: "BBBB"
139+
Password # 9: "AAAAAAAI"
140+
Password # 10: "AAAAAAAJ"
164141
</pre>
165142
</details>
166143

@@ -170,27 +147,30 @@ goos: linux
170147
goarch: amd64
171148
pkg: github.com/jedib0t/go-passwords/passphrase
172149
cpu: AMD Ryzen 9 5900X 12-Core Processor
173-
BenchmarkGenerator_Generate-12 4030634 292.0 ns/op 144 B/op 5 allocs/op
150+
BenchmarkGenerator_Generate-12 3979081 294.8 ns/op 144 B/op 5 allocs/op
174151
PASS
175-
ok github.com/jedib0t/go-passwords/passphrase 1.603s
152+
ok github.com/jedib0t/go-passwords/passphrase 1.503s
176153
177154
goos: linux
178155
goarch: amd64
179156
pkg: github.com/jedib0t/go-passwords/password
180157
cpu: AMD Ryzen 9 5900X 12-Core Processor
181-
BenchmarkGenerator_Generate-12 6263398 187.5 ns/op 40 B/op 2 allocs/op
158+
BenchmarkGenerator_Generate-12 5977402 199.4 ns/op 40 B/op 2 allocs/op
182159
PASS
183-
ok github.com/jedib0t/go-passwords/password 1.375s
160+
ok github.com/jedib0t/go-passwords/password 1.414s
184161
185162
goos: linux
186163
goarch: amd64
187-
pkg: github.com/jedib0t/go-passwords/password/sequencer
164+
pkg: github.com/jedib0t/go-passwords/odometer
188165
cpu: AMD Ryzen 9 5900X 12-Core Processor
189-
BenchmarkSequencer_GotoN-12 4355002 274.6 ns/op 32 B/op 3 allocs/op
190-
BenchmarkSequencer_Next-12 13614666 88.99 ns/op 16 B/op 1 allocs/op
191-
BenchmarkSequencer_NextN-12 6216072 187.2 ns/op 32 B/op 3 allocs/op
192-
BenchmarkSequencer_Prev-12 13569340 87.69 ns/op 16 B/op 1 allocs/op
193-
BenchmarkSequencer_PrevN-12 4230654 277.9 ns/op 32 B/op 3 allocs/op
166+
BenchmarkOdometer_Decrement-12 56414820 21.25 ns/op 0 B/op 0 allocs/op
167+
BenchmarkOdometer_Decrement_Big-12 44742920 27.37 ns/op 0 B/op 0 allocs/op
168+
BenchmarkOdometer_DecrementN-12 6536234 177.3 ns/op 16 B/op 2 allocs/op
169+
BenchmarkOdometer_GotoLocation-12 5184144 220.7 ns/op 56 B/op 4 allocs/op
170+
BenchmarkOdometer_Increment-12 61866901 19.37 ns/op 0 B/op 0 allocs/op
171+
BenchmarkOdometer_Increment_Big-12 67560506 17.68 ns/op 0 B/op 0 allocs/op
172+
BenchmarkOdometer_IncrementN-12 7371675 172.7 ns/op 16 B/op 2 allocs/op
173+
BenchmarkOdometer_String-12 14852208 75.40 ns/op 16 B/op 1 allocs/op
194174
PASS
195-
ok github.com/jedib0t/go-passwords/password/sequencer 6.888s
175+
ok github.com/jedib0t/go-passwords/odometer 10.282s
196176
```

main.go

+13-59
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,30 @@
11
package main
22

33
import (
4-
"context"
54
"fmt"
6-
"time"
75

86
"github.com/jedib0t/go-passwords/charset"
7+
"github.com/jedib0t/go-passwords/odometer"
98
"github.com/jedib0t/go-passwords/passphrase"
109
"github.com/jedib0t/go-passwords/passphrase/dictionaries"
1110
"github.com/jedib0t/go-passwords/password"
12-
"github.com/jedib0t/go-passwords/password/sequencer"
1311
)
1412

1513
func main() {
1614
fmt.Println("Passphrases:")
17-
passphraseGenerator()
15+
demoPassphraseGenerator()
1816
fmt.Println()
1917

2018
fmt.Println("Passwords:")
21-
passwordGenerator()
19+
demoPasswordGenerator()
2220
fmt.Println()
2321

24-
fmt.Println("Passwords Sequenced:")
25-
passwordSequencer()
26-
fmt.Println()
27-
28-
fmt.Println("Passwords Sequenced & Streamed:")
29-
passwordSequencerStreaming()
22+
fmt.Println("Odometer:")
23+
demoOdometer()
3024
fmt.Println()
3125
}
3226

33-
func passphraseGenerator() {
27+
func demoPassphraseGenerator() {
3428
g, err := passphrase.NewGenerator(
3529
passphrase.WithCapitalizedWords(true),
3630
passphrase.WithDictionary(dictionaries.English()),
@@ -47,7 +41,7 @@ func passphraseGenerator() {
4741
}
4842
}
4943

50-
func passwordGenerator() {
44+
func demoPasswordGenerator() {
5145
g, err := password.NewGenerator(
5246
password.WithCharset(charset.AllChars.WithoutAmbiguity().WithoutDuplicates()),
5347
password.WithLength(12),
@@ -63,55 +57,15 @@ func passwordGenerator() {
6357
}
6458
}
6559

66-
func passwordSequencer() {
67-
s, err := sequencer.New(
68-
sequencer.WithCharset(charset.AllChars.WithoutAmbiguity()),
69-
sequencer.WithLength(8),
70-
)
71-
if err != nil {
72-
panic(err.Error())
73-
}
60+
func demoOdometer() {
61+
o := odometer.New(charset.AlphabetsUpper, 8)
62+
7463
for idx := 1; idx <= 10; idx++ {
75-
fmt.Printf("Password #%3d: %#v\n", idx, s.Get())
64+
fmt.Printf("Password #%3d: %#v\n", idx, o.String())
7665

77-
if !s.HasNext() {
66+
if o.AtEnd() {
7867
break
7968
}
80-
s.Next()
81-
}
82-
}
83-
84-
func passwordSequencerStreaming() {
85-
s, err := sequencer.New(
86-
sequencer.WithCharset(charset.Charset("AB")),
87-
sequencer.WithLength(4),
88-
)
89-
if err != nil {
90-
panic(err.Error())
91-
}
92-
93-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
94-
defer cancel()
95-
96-
chPasswords := make(chan string, 1)
97-
go func() {
98-
err := s.Stream(ctx, chPasswords)
99-
if err != nil {
100-
panic(err.Error())
101-
}
102-
}()
103-
104-
idx := 0
105-
for {
106-
select {
107-
case <-ctx.Done():
108-
panic("timed out")
109-
case pw, ok := <-chPasswords:
110-
if !ok {
111-
return
112-
}
113-
idx++
114-
fmt.Printf("Password #%3d: %#v\n", idx, pw)
115-
}
69+
o.Increment()
11670
}
11771
}

odometer/errors.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package odometer
2+
3+
import "errors"
4+
5+
var (
6+
ErrInvalidLocation = errors.New("invalid location")
7+
)

0 commit comments

Comments
 (0)