Nagy Károly Gábriel
4 years ago
commit
21a8e20140
10 changed files with 542 additions and 0 deletions
@ -0,0 +1,19 @@
|
||||
# http://editorconfig.org |
||||
|
||||
root = true |
||||
|
||||
[*] |
||||
charset = utf-8 |
||||
end_of_line = lf |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
indent_size = 4 |
||||
indent_style = space |
||||
|
||||
[*.go] |
||||
indent_style = tab |
||||
indent_size = 4 |
||||
|
||||
[Makefile] |
||||
indent_style = tab |
||||
|
@ -0,0 +1,26 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects) |
||||
*.o |
||||
*.a |
||||
*.so |
||||
|
||||
# Folders |
||||
_obj |
||||
_test |
||||
|
||||
# Architecture specific extensions/prefixes |
||||
*.[568vq] |
||||
[568vq].out |
||||
|
||||
*.cgo1.go |
||||
*.cgo2.c |
||||
_cgo_defun.c |
||||
_cgo_gotypes.go |
||||
_cgo_export.* |
||||
|
||||
_testmain.go |
||||
|
||||
*.exe |
||||
*.test |
||||
*.prof |
||||
bin/ |
||||
release/ |
@ -0,0 +1,12 @@
|
||||
FROM golang:alpine as build |
||||
|
||||
WORKDIR /go/src/ranpass |
||||
COPY . /go/src/ranpass |
||||
RUN CGO_ENABLED=0 go build -o /go/bin/ranpass |
||||
|
||||
FROM scratch |
||||
COPY --from=build /go/bin/ranpass / |
||||
|
||||
EXPOSE 8080 |
||||
ENTRYPOINT ["./ranpass"] |
||||
|
@ -0,0 +1,21 @@
|
||||
MIT License |
||||
|
||||
Copyright (c) 2019 Nagy Károly Gábriel |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,57 @@
|
||||
# Makefile for projects using go mod.
|
||||
|
||||
|
||||
#V := 1 # When V is set, print commands and build progress.
|
||||
|
||||
ARCHES:=amd64 arm64
|
||||
OSES:=linux
|
||||
BINARY:=ranpass
|
||||
|
||||
all: release |
||||
|
||||
build: |
||||
$Q for arch in $(ARCHES) ; do \
|
||||
for os in $(OSES); do \
|
||||
CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build $(VERSION_FLAGS) -a -installsuffix cgo -o ./bin/$(BINARY)-$$os-$$arch $(IMPORT_PATH); \
|
||||
done ; \
|
||||
done
|
||||
|
||||
release: clean build |
||||
$Q mkdir -p ./release
|
||||
$Q for arch in $(ARCHES) ; do \
|
||||
for os in $(OSES) ; do \
|
||||
rm -rf ./tmp/$(BINARY) ; \
|
||||
mkdir -p ./tmp/$(BINARY) ; \
|
||||
cp -a ./bin/$(BINARY)-$$os-$$arch ./tmp/$(BINARY)/$(BINARY) ; \
|
||||
tar -cz -C ./tmp -f ./release/$(BINARY)-$$os-$$arch-$(VERSION).tar.gz ./$(BINARY) ; \
|
||||
rm -rf ./tmp ; \
|
||||
done ; \
|
||||
done
|
||||
|
||||
##### =====> Utility targets <===== #####
|
||||
|
||||
.PHONY: clean gen setup |
||||
|
||||
clean: |
||||
$Q rm -rf bin
|
||||
$Q rm -rf /release/*-$(VERSION)*
|
||||
|
||||
gen: |
||||
@echo "Running go generate"
|
||||
$Q go generate
|
||||
@echo "Done!"
|
||||
|
||||
setup: |
||||
@echo "Running go mod init"
|
||||
$Q go mod init
|
||||
@echo "Done!"
|
||||
|
||||
.PHONY: all build release |
||||
|
||||
##### =====> Internals <===== #####
|
||||
|
||||
Q := $(if $V,,@)
|
||||
IMPORT_PATH := $(shell awk -F" " '$$1=="module"{print $$2;exit;}' go.mod)
|
||||
VERSION := $(shell git describe --tags --always --dirty="-dev")
|
||||
DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC')
|
||||
VERSION_FLAGS := -ldflags='-s -w -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"'
|
@ -0,0 +1,5 @@
|
||||
# gonew |
||||
This is the go mod version of gonew. |
||||
If you want the previous version that is |
||||
using some hackery around GOPATH please |
||||
use the GOPATH branch https://github.com/karasz/gonew/tree/GOPATH |
@ -0,0 +1,11 @@
|
||||
module git.jpi.io/JPI/ranpass |
||||
|
||||
go 1.14 |
||||
|
||||
require ( |
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect |
||||
github.com/labstack/echo v3.3.10+incompatible |
||||
github.com/labstack/gommon v0.3.0 // indirect |
||||
github.com/valyala/fasttemplate v1.2.1 // indirect |
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect |
||||
) |
@ -0,0 +1,50 @@
|
||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= |
||||
github.com/GeertJohan/go.rice v1.0.2 h1:PtRw+Tg3oa3HYwiDBZyvOJ8LdIyf6lAovJJtr7YOAYk= |
||||
github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4= |
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= |
||||
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= |
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= |
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
||||
github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM= |
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= |
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= |
||||
github.com/foolin/echo-template v0.0.0-20190415034849-543a88245eec h1:BurQ3oNjJkB5+zibQGHw97kZOBN/DLlAKYlvfsacBD0= |
||||
github.com/foolin/echo-template v0.0.0-20190415034849-543a88245eec/go.mod h1:4ePCtze3Ivy48ps0gJWfSByLgfqvT0rF+RpKQFe4Ja0= |
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= |
||||
github.com/labstack/echo v1.4.4 h1:1bEiBNeGSUKxcPDGfZ/7IgdhJJZx8wV/pICJh4W2NJI= |
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= |
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= |
||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= |
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= |
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= |
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= |
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= |
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= |
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= |
||||
github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= |
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
||||
github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI= |
||||
github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE= |
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= |
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= |
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= |
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= |
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= |
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= |
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= |
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= |
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= |
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= |
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= |
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= |
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
@ -0,0 +1,93 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"flag" |
||||
"net/http" |
||||
"strconv" |
||||
|
||||
"github.com/labstack/echo" |
||||
"github.com/labstack/echo/middleware" |
||||
) |
||||
|
||||
type passwordData struct { |
||||
Length int |
||||
Digits int |
||||
Symbols int |
||||
NoUpper bool |
||||
DenyRepeat bool |
||||
Password string |
||||
} |
||||
|
||||
var d, defaults passwordData |
||||
|
||||
func generatePassword(c echo.Context) error { |
||||
|
||||
var err error |
||||
|
||||
d.Length, err = strconv.Atoi(c.FormValue("length")) |
||||
if err != nil { |
||||
d.Length = defaults.Length |
||||
} |
||||
|
||||
d.Digits, err = strconv.Atoi(c.FormValue("digits")) |
||||
if err != nil { |
||||
d.Digits = defaults.Digits |
||||
} |
||||
|
||||
d.Symbols, err = strconv.Atoi(c.FormValue("symbols")) |
||||
if err != nil { |
||||
d.Symbols = defaults.Symbols |
||||
} |
||||
|
||||
if c.FormValue("noupper") == "on" { |
||||
d.NoUpper = true |
||||
} |
||||
|
||||
if c.FormValue("denyrepeat") == "on" { |
||||
d.DenyRepeat = true |
||||
} |
||||
|
||||
// Generate a password
|
||||
d.Password, err = generate(d.Length, d.Digits, d.Symbols, d.NoUpper, !d.DenyRepeat) |
||||
if err != nil { |
||||
d.Password = "Error: " + err.Error() |
||||
} |
||||
if d.Length == 0 { |
||||
d.Password = "Error: password can not have zero length" |
||||
} |
||||
|
||||
return c.String(http.StatusOK, d.Password) |
||||
} |
||||
|
||||
func checkHealth(c echo.Context) error { |
||||
s := `{"status":"OK"}` |
||||
return c.String(http.StatusOK, s) |
||||
} |
||||
|
||||
func main() { |
||||
|
||||
// Set defaults
|
||||
portPtr := flag.Int("listen", 8080, "Specify on which port to listen") |
||||
lengthPtr := flag.Int("length", 16, "Specify the password length") |
||||
digitsPtr := flag.Int("digits", 2, "Specify the the number of digits in the password") |
||||
symbolsPtr := flag.Int("symbols", 2, "Specify the the number of symbols in the password") |
||||
flag.Parse() |
||||
|
||||
defaults.Length = *lengthPtr |
||||
defaults.Digits = *digitsPtr |
||||
defaults.Symbols = *symbolsPtr |
||||
|
||||
e := echo.New() |
||||
e.HideBanner = true |
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger()) |
||||
e.Use(middleware.Recover()) |
||||
|
||||
e.GET("/", generatePassword) |
||||
e.POST("/", generatePassword) |
||||
|
||||
e.GET("/health", checkHealth) |
||||
|
||||
e.Logger.Fatal(e.Start(":" + strconv.Itoa(*portPtr))) |
||||
} |
@ -0,0 +1,248 @@
|
||||
// Package password provides a library for generating high-entropy random
|
||||
// password strings via the crypto/rand package.
|
||||
//
|
||||
// res, err := Generate(64, 10, 10, false, false)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// log.Printf(res)
|
||||
//
|
||||
// Most functions are safe for concurrent use.
|
||||
package main |
||||
|
||||
import ( |
||||
"crypto/rand" |
||||
"errors" |
||||
"io" |
||||
"math/big" |
||||
"strings" |
||||
) |
||||
|
||||
const ( |
||||
// LowerLetters is the list of lowercase letters.
|
||||
LowerLetters = "abcdefghijklmnopqrstuvwxyz" |
||||
|
||||
// UpperLetters is the list of uppercase letters.
|
||||
UpperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
||||
|
||||
// Digits is the list of permitted digits.
|
||||
Digits = "0123456789" |
||||
|
||||
// Symbols is the list of symbols.
|
||||
Symbols = "~!@#$%^&*()_+`-={}|[]\\:\"<>?,./" |
||||
) |
||||
|
||||
var ( |
||||
// ErrExceedsTotalLength is the error returned with the number of digits and
|
||||
// symbols is greater than the total length.
|
||||
ErrExceedsTotalLength = errors.New("number of digits and symbols must be less than total length") |
||||
|
||||
// ErrLettersExceedsAvailable is the error returned with the number of letters
|
||||
// exceeds the number of available letters and repeats are not allowed.
|
||||
ErrLettersExceedsAvailable = errors.New("number of letters exceeds available letters and repeats are not allowed") |
||||
|
||||
// ErrDigitsExceedsAvailable is the error returned with the number of digits
|
||||
// exceeds the number of available digits and repeats are not allowed.
|
||||
ErrDigitsExceedsAvailable = errors.New("number of digits exceeds available digits and repeats are not allowed") |
||||
|
||||
// ErrSymbolsExceedsAvailable is the error returned with the number of symbols
|
||||
// exceeds the number of available symbols and repeats are not allowed.
|
||||
ErrSymbolsExceedsAvailable = errors.New("number of symbols exceeds available symbols and repeats are not allowed") |
||||
) |
||||
|
||||
type generator struct { |
||||
lowerLetters string |
||||
upperLetters string |
||||
digits string |
||||
symbols string |
||||
reader io.Reader |
||||
} |
||||
|
||||
// GeneratorInput is used as input to the NewGenerator function.
|
||||
type generatorInput struct { |
||||
LowerLetters string |
||||
UpperLetters string |
||||
Digits string |
||||
Symbols string |
||||
Reader io.Reader // rand.Reader by default
|
||||
} |
||||
|
||||
// NewGenerator creates a new Generator from the specified configuration. If no
|
||||
// input is given, all the default values are used. This function is safe for
|
||||
// concurrent use.
|
||||
func newGenerator(i *generatorInput) (*generator, error) { |
||||
if i == nil { |
||||
i = new(generatorInput) |
||||
} |
||||
|
||||
g := &generator{ |
||||
lowerLetters: i.LowerLetters, |
||||
upperLetters: i.UpperLetters, |
||||
digits: i.Digits, |
||||
symbols: i.Symbols, |
||||
reader: i.Reader, |
||||
} |
||||
|
||||
if g.lowerLetters == "" { |
||||
g.lowerLetters = LowerLetters |
||||
} |
||||
|
||||
if g.upperLetters == "" { |
||||
g.upperLetters = UpperLetters |
||||
} |
||||
|
||||
if g.digits == "" { |
||||
g.digits = Digits |
||||
} |
||||
|
||||
if g.symbols == "" { |
||||
g.symbols = Symbols |
||||
} |
||||
|
||||
if g.reader == nil { |
||||
g.reader = rand.Reader |
||||
} |
||||
|
||||
return g, nil |
||||
} |
||||
|
||||
// Generate generates a password with the given requirements. length is the
|
||||
// total number of characters in the password. numDigits is the number of digits
|
||||
// to include in the result. numSymbols is the number of symbols to include in
|
||||
// the result. noUpper excludes uppercase letters from the results. allowRepeat
|
||||
// allows characters to repeat.
|
||||
//
|
||||
// The algorithm is fast, but it's not designed to be performant; it favors
|
||||
// entropy over speed. This function is safe for concurrent use.
|
||||
func (g *generator) generate(length, numDigits, numSymbols int, noUpper, allowRepeat bool) (string, error) { |
||||
letters := g.lowerLetters |
||||
if !noUpper { |
||||
letters += g.upperLetters |
||||
} |
||||
|
||||
chars := length - numDigits - numSymbols |
||||
if chars < 0 { |
||||
return "", ErrExceedsTotalLength |
||||
} |
||||
|
||||
if !allowRepeat && chars > len(letters) { |
||||
return "", ErrLettersExceedsAvailable |
||||
} |
||||
|
||||
if !allowRepeat && numDigits > len(g.digits) { |
||||
return "", ErrDigitsExceedsAvailable |
||||
} |
||||
|
||||
if !allowRepeat && numSymbols > len(g.symbols) { |
||||
return "", ErrSymbolsExceedsAvailable |
||||
} |
||||
|
||||
var result string |
||||
|
||||
// Characters
|
||||
for i := 0; i < chars; i++ { |
||||
ch, err := randomElement(g.reader, letters) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !allowRepeat && strings.Contains(result, ch) { |
||||
i-- |
||||
continue |
||||
} |
||||
|
||||
result, err = randomInsert(g.reader, result, ch) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
} |
||||
|
||||
// Digits
|
||||
for i := 0; i < numDigits; i++ { |
||||
d, err := randomElement(g.reader, g.digits) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !allowRepeat && strings.Contains(result, d) { |
||||
i-- |
||||
continue |
||||
} |
||||
|
||||
result, err = randomInsert(g.reader, result, d) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
} |
||||
|
||||
// Symbols
|
||||
for i := 0; i < numSymbols; i++ { |
||||
sym, err := randomElement(g.reader, g.symbols) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !allowRepeat && strings.Contains(result, sym) { |
||||
i-- |
||||
continue |
||||
} |
||||
|
||||
result, err = randomInsert(g.reader, result, sym) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
} |
||||
|
||||
return result, nil |
||||
} |
||||
|
||||
// MustGenerate is the same as Generate, but panics on error.
|
||||
func (g *generator) mustGenerate(length, numDigits, numSymbols int, noUpper, allowRepeat bool) string { |
||||
res, err := g.generate(length, numDigits, numSymbols, noUpper, allowRepeat) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return res |
||||
} |
||||
|
||||
// Generate is the package shortcut for Generator.Generate.
|
||||
func generate(length, numDigits, numSymbols int, noUpper, allowRepeat bool) (string, error) { |
||||
gen, err := newGenerator(nil) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return gen.generate(length, numDigits, numSymbols, noUpper, allowRepeat) |
||||
} |
||||
|
||||
// MustGenerate is the package shortcut for Generator.MustGenerate.
|
||||
func mustGenerate(length, numDigits, numSymbols int, noUpper, allowRepeat bool) string { |
||||
res, err := generate(length, numDigits, numSymbols, noUpper, allowRepeat) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return res |
||||
} |
||||
|
||||
// randomInsert randomly inserts the given value into the given string.
|
||||
func randomInsert(reader io.Reader, s, val string) (string, error) { |
||||
if s == "" { |
||||
return val, nil |
||||
} |
||||
|
||||
n, err := rand.Int(reader, big.NewInt(int64(len(s)+1))) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
i := n.Int64() |
||||
return s[0:i] + val + s[i:], nil |
||||
} |
||||
|
||||
// randomElement extracts a random element from the given string.
|
||||
func randomElement(reader io.Reader, s string) (string, error) { |
||||
n, err := rand.Int(reader, big.NewInt(int64(len(s)))) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
return string(s[n.Int64()]), nil |
||||
} |
Loading…
Reference in new issue