Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c979561fa5 | |||
| fe11983dab | |||
| 1e93add7bd | |||
| c328726ed0 | |||
| 7e826b75d7 | |||
| 72f4797428 | |||
| aad2144e7c | |||
| a1c8d6e531 | |||
| 0d5d7503ec | |||
| ee1a0fedcc | |||
| 3fc3f35bb5 | |||
| 9a98788476 | |||
| 43b8d3b618 | |||
| 6d1e700d8b | |||
| 1b2fcd72b9 | |||
| 6c20c7bb8b | |||
| f5289baecd |
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -5,8 +5,8 @@ package main
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -14,8 +14,9 @@ import (
|
||||
var allowedCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()_+[]\\{}|;':,./<>?")
|
||||
|
||||
const (
|
||||
Version = "1.3.0"
|
||||
symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?"
|
||||
Version = "1.3.5"
|
||||
symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?"
|
||||
chunkSize = 16 // The size of each chunk of the password to be generated by the worker goroutines
|
||||
)
|
||||
|
||||
func matchArguments(args []string) string {
|
||||
@@ -26,11 +27,10 @@ func matchArguments(args []string) string {
|
||||
|
||||
// First argument is special, must be an integer, -v, or -h
|
||||
var size = 0 // Password length
|
||||
err := error(nil)
|
||||
if size, err = strconv.Atoi(args[0]); err == nil { // If first argument is an integer
|
||||
} else if args[0] == "-v" {
|
||||
switch args[0] {
|
||||
case "-v":
|
||||
return "GoPass version " + Version
|
||||
} else if args[0] == "-h" {
|
||||
case "-h":
|
||||
return "GoPass - A simple password generator written in Go\n" +
|
||||
"Usage: gopass [length] [disallowed characters] [optional remove symbols -s]\n" +
|
||||
" Example: gopass 16\n" +
|
||||
@@ -38,16 +38,23 @@ func matchArguments(args []string) string {
|
||||
" Example: gopass 16 -s\n" +
|
||||
"\nFor help (this output): gopass -h\n" +
|
||||
"For version: gopass -v\n"
|
||||
default:
|
||||
var err error
|
||||
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++ {
|
||||
v := args[i]
|
||||
if v == "-s" {
|
||||
switch {
|
||||
case v == "-s":
|
||||
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
|
||||
removeDisallowed([]rune(v[2:]))
|
||||
} else {
|
||||
default:
|
||||
return "Invalid argument (\"" + v + "\") supplied! (Type gopass -h for help)"
|
||||
}
|
||||
}
|
||||
@@ -61,28 +68,88 @@ func matchArguments(args []string) string {
|
||||
|
||||
// Remove all disallowed characters from the allowedCharacters slice
|
||||
func removeDisallowed(disallowed []rune) {
|
||||
disallowedMap := make(map[rune]bool, len(disallowed))
|
||||
for _, r := range disallowed {
|
||||
for i, v := range allowedCharacters {
|
||||
if v == r {
|
||||
allowedCharacters = append(allowedCharacters[:i], allowedCharacters[i+1:]...)
|
||||
}
|
||||
disallowedMap[r] = true
|
||||
}
|
||||
|
||||
i := 0
|
||||
for _, v := range allowedCharacters {
|
||||
if !disallowedMap[v] {
|
||||
allowedCharacters[i] = v
|
||||
i++
|
||||
}
|
||||
}
|
||||
allowedCharacters = allowedCharacters[:i]
|
||||
}
|
||||
|
||||
func generatePassword(size int) string {
|
||||
// Make empty array of runes with size of size
|
||||
pass := make([]rune, size)
|
||||
|
||||
// Assign every slot of pass to a random allowedCharacter
|
||||
for i := range pass {
|
||||
// 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))))
|
||||
if err != nil {
|
||||
println("Error securely generating random character!")
|
||||
return ""
|
||||
}
|
||||
pass[i] = allowedCharacters[index.Int64()]
|
||||
// Create a channel to receive chunks of the password
|
||||
passChan := make(chan []rune)
|
||||
|
||||
// Determine the number of worker goroutines to use
|
||||
numWorkers := runtime.NumCPU()
|
||||
|
||||
// Launch the worker goroutines
|
||||
for range numWorkers {
|
||||
go func() {
|
||||
allowedLen := len(allowedCharacters)
|
||||
|
||||
// Calculate the rejection limit to avoid modulo bias.
|
||||
// Any random byte value > maxByte must be discarded.
|
||||
maxByte := 255 - (256 % allowedLen)
|
||||
|
||||
// Create a buffer for random bytes.
|
||||
// We read enough bytes for the whole chunk at once (plus some extra
|
||||
// in case of rejections) to reduce system calls.
|
||||
randBuf := make([]byte, chunkSize*2)
|
||||
|
||||
for {
|
||||
// Fill the buffer initially
|
||||
if _, err := rand.Read(randBuf); err != nil {
|
||||
println("Error securely generating random character chunk!")
|
||||
return
|
||||
}
|
||||
bufIdx := 0
|
||||
|
||||
chunk := make([]rune, chunkSize)
|
||||
for i := range chunk {
|
||||
for {
|
||||
// If we exhausted the buffer due to rejections, refill it
|
||||
if bufIdx >= len(randBuf) {
|
||||
if _, err := rand.Read(randBuf); err != nil {
|
||||
println("Error securely generating random character chunk!")
|
||||
return
|
||||
}
|
||||
bufIdx = 0
|
||||
}
|
||||
|
||||
b := randBuf[bufIdx]
|
||||
bufIdx++
|
||||
|
||||
// If the byte causes bias, discard and retry
|
||||
if int(b) > maxByte {
|
||||
continue
|
||||
}
|
||||
|
||||
// Safe to map to character set
|
||||
chunk[i] = allowedCharacters[int(b)%allowedLen]
|
||||
break
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# The current version number of the program
|
||||
VERSION := 1.3.0
|
||||
VERSION := 1.3.5
|
||||
|
||||
# List of OS and architecture combinations to build
|
||||
BUILD_OS_ARCH := \
|
||||
@@ -24,64 +24,64 @@ all: $(BUILD_OS_ARCH)
|
||||
darwin/amd64:
|
||||
GOOS=darwin \
|
||||
GOARCH=amd64 \
|
||||
go build -ldflags="-s -w" -o "gopass-darwin-amd64-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-darwin-amd64-$(VERSION)" main.go
|
||||
|
||||
freebsd/386:
|
||||
GOOS=freebsd \
|
||||
GOARCH=386 \
|
||||
go build -ldflags="-s -w" -o "gopass-freebsd-386-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-386-$(VERSION)" main.go
|
||||
|
||||
freebsd/amd64:
|
||||
GOOS=freebsd \
|
||||
GOARCH=amd64 \
|
||||
go build -ldflags="-s -w" -o "gopass-freebsd-amd64-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-amd64-$(VERSION)" main.go
|
||||
|
||||
freebsd/arm:
|
||||
GOOS=freebsd \
|
||||
GOARCH=arm \
|
||||
go build -ldflags="-s -w" -o "gopass-freebsd-arm-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-arm-$(VERSION)" main.go
|
||||
|
||||
linux/386:
|
||||
GOOS=linux \
|
||||
GOARCH=386 \
|
||||
go build -ldflags="-s -w" -o "gopass-linux-386-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-386-$(VERSION)" main.go
|
||||
|
||||
linux/amd64:
|
||||
GOOS=linux \
|
||||
GOARCH=amd64 \
|
||||
go build -ldflags="-s -w" -o "gopass-linux-amd64-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-amd64-$(VERSION)" main.go
|
||||
|
||||
linux/arm:
|
||||
GOOS=linux \
|
||||
GOARCH=arm \
|
||||
go build -ldflags="-s -w" -o "gopass-linux-arm-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-arm-$(VERSION)" main.go
|
||||
|
||||
plan9/386:
|
||||
GOOS=plan9 \
|
||||
GOARCH=386 \
|
||||
go build -ldflags="-s -w" -o "gopass-plan9-386-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-386-$(VERSION)" main.go
|
||||
|
||||
plan9/amd64:
|
||||
GOOS=plan9 \
|
||||
GOARCH=amd64 \
|
||||
go build -ldflags="-s -w" -o "gopass-plan9-amd64-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-amd64-$(VERSION)" main.go
|
||||
|
||||
plan9/arm:
|
||||
GOOS=plan9 \
|
||||
GOARCH=arm \
|
||||
go build -ldflags="-s -w" -o "gopass-plan9-arm-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-arm-$(VERSION)" main.go
|
||||
|
||||
windows/386:
|
||||
GOOS=windows \
|
||||
GOARCH=386 \
|
||||
go build -ldflags="-s -w" -o "gopass-windows-386-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-386-$(VERSION)" main.go
|
||||
|
||||
windows/amd64:
|
||||
GOOS=windows \
|
||||
GOARCH=amd64 \
|
||||
go build -ldflags="-s -w" -o "gopass-windows-amd64-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-amd64-$(VERSION)" main.go
|
||||
|
||||
windows/arm:
|
||||
GOOS=windows \
|
||||
GOARCH=arm \
|
||||
go build -ldflags="-s -w" -o "gopass-windows-arm-$(VERSION)" main.go
|
||||
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-arm-$(VERSION)" main.go
|
||||
|
||||
Reference in New Issue
Block a user