Added password generation and hashing helper
This commit is contained in:
parent
b307844596
commit
1111852adf
1
go.mod
1
go.mod
|
@ -2,6 +2,7 @@ module ShareDAV
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1
|
github.com/BurntSushi/toml v0.3.1
|
||||||
|
github.com/sethvargo/go-password v0.1.2
|
||||||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869
|
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -1,5 +1,7 @@
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/sethvargo/go-password v0.1.2 h1:fhBF4thiPVKEZ7R6+CX46GWJiPyCyXshbeqZ7lqEeYo=
|
||||||
|
github.com/sethvargo/go-password v0.1.2/go.mod h1:qKHfdSjT26DpHQWHWWR5+X4BI45jT31dg6j4RI2TEb0=
|
||||||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU=
|
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU=
|
||||||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
||||||
|
|
33
main.go
33
main.go
|
@ -28,15 +28,48 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
pwgen "github.com/sethvargo/go-password/password"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
"golang.org/x/net/webdav"
|
"golang.org/x/net/webdav"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var configFile = flag.String("config", "sharedav.toml", "Config file to be used.")
|
var configFile = flag.String("config", "sharedav.toml", "Config file to be used.")
|
||||||
|
var genPassword = flag.Bool("genpass", false, "If set, a password will be generated and hashed.")
|
||||||
|
var hashPassword = flag.String("hashpass", "", "If set, the given password will be hashed.")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if *genPassword {
|
||||||
|
// math.rand is not secure. For determining the number of digits in a password
|
||||||
|
// it should suffice, though.
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
pwLen := 32
|
||||||
|
pw, err := pwgen.Generate(pwLen, rand.Intn(pwLen/2), 0, false, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(pw), 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Password: %s\n", pw)
|
||||||
|
fmt.Printf(" Hash: %s\n", hash)
|
||||||
|
return
|
||||||
|
} else if *hashPassword != "" {
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(*hashPassword), 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(hash))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c := LoadConfig(*configFile)
|
c := LoadConfig(*configFile)
|
||||||
|
|
||||||
h := &webdav.Handler{}
|
h := &webdav.Handler{}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright 2017 Seth Vargo <seth@sethvargo.com>
|
||||||
|
|
||||||
|
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,242 @@
|
||||||
|
// 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 password
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"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")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generator is the stateful generator which can be used to customize the list
|
||||||
|
// of letters, digits, and/or symbols.
|
||||||
|
type Generator struct {
|
||||||
|
lowerLetters string
|
||||||
|
upperLetters string
|
||||||
|
digits string
|
||||||
|
symbols string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratorInput is used as input to the NewGenerator function.
|
||||||
|
type GeneratorInput struct {
|
||||||
|
LowerLetters string
|
||||||
|
UpperLetters string
|
||||||
|
Digits string
|
||||||
|
Symbols string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.lowerLetters == "" {
|
||||||
|
g.lowerLetters = LowerLetters
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.upperLetters == "" {
|
||||||
|
g.upperLetters = UpperLetters
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.digits == "" {
|
||||||
|
g.digits = Digits
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.symbols == "" {
|
||||||
|
g.symbols = Symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
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(letters)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allowRepeat && strings.Contains(result, ch) {
|
||||||
|
i--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = randomInsert(result, ch)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Digits
|
||||||
|
for i := 0; i < numDigits; i++ {
|
||||||
|
d, err := randomElement(g.digits)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allowRepeat && strings.Contains(result, d) {
|
||||||
|
i--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = randomInsert(result, d)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Symbols
|
||||||
|
for i := 0; i < numSymbols; i++ {
|
||||||
|
sym, err := randomElement(g.symbols)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allowRepeat && strings.Contains(result, sym) {
|
||||||
|
i--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = randomInsert(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
|
||||||
|
}
|
||||||
|
|
||||||
|
// See Generator.Generate for usage.
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See Generator.MustGenerate for usage.
|
||||||
|
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(s, val string) (string, error) {
|
||||||
|
if s == "" {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(s)+1)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
i := n.Int64()
|
||||||
|
return s[0:i] + val + s[i:len(s)], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// randomElement extracts a random element from the given string.
|
||||||
|
func randomElement(s string) (string, error) {
|
||||||
|
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(s))))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(s[n.Int64()]), nil
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
# github.com/BurntSushi/toml v0.3.1
|
# github.com/BurntSushi/toml v0.3.1
|
||||||
github.com/BurntSushi/toml
|
github.com/BurntSushi/toml
|
||||||
|
# github.com/sethvargo/go-password v0.1.2
|
||||||
|
github.com/sethvargo/go-password/password
|
||||||
# golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869
|
# golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869
|
||||||
golang.org/x/crypto/bcrypt
|
golang.org/x/crypto/bcrypt
|
||||||
golang.org/x/crypto/blowfish
|
golang.org/x/crypto/blowfish
|
||||||
|
|
Loading…
Reference in New Issue