5 Commits

23 changed files with 61 additions and 24 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/gopass-linux-386-1.3.1 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/gopass-linux-arm-1.3.1 Normal file

Binary file not shown.

BIN
bin/gopass-plan9-386-1.3.0 → bin/gopass-plan9-386-1.3.1 Executable file → Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/gopass-plan9-arm-1.3.0 → bin/gopass-plan9-arm-1.3.1 Executable file → Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

2
go.mod
View File

@ -1,3 +1,3 @@
module GoPass module GoPass
go 1.19 go 1.20

0
go.sum Normal file
View File

75
main.go
View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"runtime"
"strconv" "strconv"
"strings" "strings"
) )
@ -14,8 +15,9 @@ import (
var allowedCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()_+[]\\{}|;':,./<>?") var allowedCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()_+[]\\{}|;':,./<>?")
const ( const (
Version = "1.3.0" Version = "1.3.1"
symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?" symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?"
chunkSize = 16 // The size of each chunk of the password to be generated by the worker goroutines
) )
func matchArguments(args []string) string { func matchArguments(args []string) string {
@ -26,11 +28,10 @@ func matchArguments(args []string) string {
// First argument is special, must be an integer, -v, or -h // First argument is special, must be an integer, -v, or -h
var size = 0 // Password length var size = 0 // Password length
err := error(nil) switch args[0] {
if size, err = strconv.Atoi(args[0]); err == nil { // If first argument is an integer case "-v":
} else if args[0] == "-v" {
return "GoPass version " + Version return "GoPass version " + Version
} else if args[0] == "-h" { case "-h":
return "GoPass - A simple password generator written in Go\n" + return "GoPass - A simple password generator written in Go\n" +
"Usage: gopass [length] [disallowed characters] [optional remove symbols -s]\n" + "Usage: gopass [length] [disallowed characters] [optional remove symbols -s]\n" +
" Example: gopass 16\n" + " Example: gopass 16\n" +
@ -38,16 +39,23 @@ func matchArguments(args []string) string {
" Example: gopass 16 -s\n" + " Example: gopass 16 -s\n" +
"\nFor help (this output): gopass -h\n" + "\nFor help (this output): gopass -h\n" +
"For version: gopass -v\n" "For version: gopass -v\n"
default:
err := error(nil)
size, err = strconv.Atoi(args[0])
if err != nil {
return "Invalid first argument (\"" + args[0] + "\") supplied! (Type gopass -h for help)"
}
} }
for i := 1; i < len(args); i++ { for i := 1; i < len(args); i++ {
v := args[i] v := args[i]
if v == "-s" { switch {
case v == "-s":
removeDisallowed([]rune(symbols)) removeDisallowed([]rune(symbols))
} else if strings.HasPrefix(v, "-r=") { // If argument starts with -r= case strings.HasPrefix(v, "-r="):
// Remove all characters after the = until next whitespace // Remove all characters after the = until next whitespace
removeDisallowed([]rune(v[2:])) removeDisallowed([]rune(v[2:]))
} else { default:
return "Invalid argument (\"" + v + "\") supplied! (Type gopass -h for help)" return "Invalid argument (\"" + v + "\") supplied! (Type gopass -h for help)"
} }
} }
@ -61,28 +69,57 @@ func matchArguments(args []string) string {
// Remove all disallowed characters from the allowedCharacters slice // Remove all disallowed characters from the allowedCharacters slice
func removeDisallowed(disallowed []rune) { func removeDisallowed(disallowed []rune) {
disallowedMap := make(map[rune]bool, len(disallowed))
for _, r := range disallowed { for _, r := range disallowed {
for i, v := range allowedCharacters { disallowedMap[r] = true
if v == r { }
allowedCharacters = append(allowedCharacters[:i], allowedCharacters[i+1:]...)
} i := 0
for _, v := range allowedCharacters {
if !disallowedMap[v] {
allowedCharacters[i] = v
i++
} }
} }
allowedCharacters = allowedCharacters[:i]
} }
func generatePassword(size int) string { func generatePassword(size int) string {
// Make empty array of runes with size of size // Make empty array of runes with size of size
pass := make([]rune, size) pass := make([]rune, size)
// Assign every slot of pass to a random allowedCharacter // Create a channel to receive chunks of the password
for i := range pass { passChan := make(chan []rune)
// Generate a random int greater than 0 and not to exceed the length of allowedCharacters
index, err := rand.Int(rand.Reader, big.NewInt(int64(len(allowedCharacters)))) // Determine the number of worker goroutines to use
numWorkers := runtime.NumCPU()
// Launch the worker goroutines
for i := 0; i < numWorkers; i++ {
go func() {
allowedLen := len(allowedCharacters)
for {
// Generate a chunk of the password
chunk := make([]rune, chunkSize)
for i := range chunk {
index, err := rand.Int(rand.Reader, big.NewInt(int64(allowedLen)))
if err != nil { if err != nil {
println("Error securely generating random character!") println("Error securely generating random character chunk!")
return "" return
} }
pass[i] = allowedCharacters[index.Int64()] chunk[i] = allowedCharacters[index.Int64()]
}
// Send the chunk of the password to the main goroutine
passChan <- chunk
}
}()
}
// Collect the chunks of the password from the channel
for i := 0; i < size; i += chunkSize {
chunk := <-passChan
copy(pass[i:], chunk)
} }
return string(pass) return string(pass)

View File

@ -1,5 +1,5 @@
# The current version number of the program # The current version number of the program
VERSION := 1.3.0 VERSION := 1.3.1
# List of OS and architecture combinations to build # List of OS and architecture combinations to build
BUILD_OS_ARCH := \ BUILD_OS_ARCH := \