Skip to content

Commit

Permalink
Merge pull request #17 from Scalingo/feat/database-dashboard/659/stre…
Browse files Browse the repository at this point in the history
…ngthen_passwords

[STORY-648] feat: simplify passwords generation
  • Loading branch information
sc-david-voisin authored Aug 28, 2024
2 parents c855cf0 + c866c85 commit f5b4d7f
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## To be Released

* chore(go): use go 1.22
* Raise default length from 20 to 64
* Allow `_` only as special character

## 1.0.3

* chore(go): use go 1.20
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Simple password generator in Go. Use `crypto/rand`

```go
// Passowrd of 20 characters
// Password of 64 characters
gopassword.Generate()

// Password of 42 characters
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/Scalingo/gopassword

go 1.20
go 1.22

require github.com/stretchr/testify v1.9.0

Expand Down
17 changes: 6 additions & 11 deletions gopassword.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package gopassword
import (
"crypto/rand"
"encoding/base64"
"fmt"
"strings"
)

const defaultLength = 64
const defaultSpecialChar = "_"

func Generate(n ...int) string {
length := 20
length := defaultLength
if len(n) > 0 {
length = n[0]
}
Expand All @@ -23,15 +25,8 @@ func Generate(n ...int) string {
randString := base64.StdEncoding.EncodeToString(randBytes)

password := randString[:length]
password = strings.Replace(password, "+", "_", -1)
password = strings.Replace(password, "/", "-", -1)

if password[0] == '-' {
password = fmt.Sprintf("_%s", password[1:])
}
if password[length-1] == '-' {
password = fmt.Sprintf("%s_", password[:length-1])
}
password = strings.ReplaceAll(password, "+", defaultSpecialChar)
password = strings.ReplaceAll(password, "/", defaultSpecialChar)

return password
}
23 changes: 18 additions & 5 deletions gopassword_test.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
package gopassword

import (
"regexp"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGenerate(t *testing.T) {
t.Run("When we want to generate a password", func(t *testing.T) {
t.Run("By default, it should be 20 characters", func(t *testing.T) {
assert.Len(t, Generate(), 20)
t.Run("By default, it must be 64 characters", func(t *testing.T) {
assert.Len(t, Generate(), 64)
})

t.Run("With an argument, the generated password should have its length", func(t *testing.T) {
t.Run("With an argument, the generated password must have its length", func(t *testing.T) {
assert.Len(t, Generate(10), 10)
assert.Len(t, Generate(42), 42)
assert.Len(t, Generate(999), 999)
})

t.Run("With several arguments, only the first should be considered", func(t *testing.T) {
t.Run("With several arguments, only the first must be considered", func(t *testing.T) {
assert.Len(t, Generate(10, 20, 30), 10)
})

t.Run("It must contain only alphanumeric or underscore characters", func(t *testing.T) {
allowedCharacters := regexp.MustCompile("^[a-zA-Z0-9_]+$")

// Try various times to ensure the result is not casual
for range 1000 {
passwd := Generate(99)
assert.True(t, allowedCharacters.MatchString(passwd))
}
})
})

t.Run("Given a generated password", func(t *testing.T) {
passwd := Generate(20)
t.Run("The character frequency should be low", func(t *testing.T) {
t.Run("The character frequency must be low", func(t *testing.T) {
fm := frequencyMap(passwd)
maxFreq := max(fm)
assert.LessOrEqual(t, maxFreq, 3)
Expand Down

0 comments on commit f5b4d7f

Please sign in to comment.