2019-08-06 19:44:08 +08:00
|
|
|
// Package random holds a few functions for working with random numbers
|
|
|
|
package random
|
|
|
|
|
2019-08-25 15:39:31 +08:00
|
|
|
import (
|
2020-11-18 20:03:01 +08:00
|
|
|
cryptorand "crypto/rand"
|
2019-08-25 15:39:31 +08:00
|
|
|
"encoding/base64"
|
2021-11-04 18:12:57 +08:00
|
|
|
"fmt"
|
2023-11-24 03:58:22 +08:00
|
|
|
"io"
|
2019-08-25 15:39:31 +08:00
|
|
|
)
|
|
|
|
|
2021-04-10 20:42:17 +08:00
|
|
|
// StringFn create a random string for test purposes using the random
|
|
|
|
// number generator function passed in.
|
2019-08-25 15:39:31 +08:00
|
|
|
//
|
|
|
|
// Do not use these for passwords.
|
2023-11-24 03:58:22 +08:00
|
|
|
func StringFn(n int, randReader io.Reader) string {
|
2019-08-06 19:44:08 +08:00
|
|
|
const (
|
|
|
|
vowel = "aeiou"
|
|
|
|
consonant = "bcdfghjklmnpqrstvwxyz"
|
|
|
|
digit = "0123456789"
|
|
|
|
)
|
2023-11-24 03:58:22 +08:00
|
|
|
var (
|
|
|
|
pattern = []string{consonant, vowel, consonant, vowel, consonant, vowel, consonant, digit}
|
|
|
|
out = make([]byte, n)
|
|
|
|
p = 0
|
|
|
|
)
|
|
|
|
_, err := io.ReadFull(randReader, out)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("internal error: failed to read from random reader: %v", err))
|
|
|
|
}
|
2019-08-06 19:44:08 +08:00
|
|
|
for i := range out {
|
|
|
|
source := pattern[p]
|
|
|
|
p = (p + 1) % len(pattern)
|
2023-11-24 03:58:22 +08:00
|
|
|
// this generation method means the distribution is slightly biased. However these
|
|
|
|
// strings are not for passwords so this is deemed OK.
|
|
|
|
out[i] = source[out[i]%byte(len(source))]
|
2019-08-06 19:44:08 +08:00
|
|
|
}
|
|
|
|
return string(out)
|
|
|
|
}
|
2019-08-25 15:39:31 +08:00
|
|
|
|
2021-04-10 20:42:17 +08:00
|
|
|
// String create a random string for test purposes.
|
|
|
|
//
|
|
|
|
// Do not use these for passwords.
|
|
|
|
func String(n int) string {
|
2023-11-24 03:58:22 +08:00
|
|
|
return StringFn(n, cryptorand.Reader)
|
2021-04-10 20:42:17 +08:00
|
|
|
}
|
|
|
|
|
2019-08-25 15:39:31 +08:00
|
|
|
// Password creates a crypto strong password which is just about
|
|
|
|
// memorable. The password is composed of printable ASCII characters
|
2024-03-12 17:30:47 +08:00
|
|
|
// from the URL encoding base64 alphabet (A-Za-z0-9_-).
|
2019-08-25 15:39:31 +08:00
|
|
|
//
|
Spelling fixes
Fix spelling of: above, already, anonymous, associated,
authentication, bandwidth, because, between, blocks, calculate,
candidates, cautious, changelog, cleaner, clipboard, command,
completely, concurrently, considered, constructs, corrupt, current,
daemon, dependencies, deprecated, directory, dispatcher, download,
eligible, ellipsis, encrypter, endpoint, entrieslist, essentially,
existing writers, existing, expires, filesystem, flushing, frequently,
hierarchy, however, implementation, implements, inaccurate,
individually, insensitive, longer, maximum, metadata, modified,
multipart, namedirfirst, nextcloud, obscured, opened, optional,
owncloud, pacific, passphrase, password, permanently, persimmon,
positive, potato, protocol, quota, receiving, recommends, referring,
requires, revisited, satisfied, satisfies, satisfy, semver,
serialized, session, storage, strategies, stringlist, successful,
supported, surprise, temporarily, temporary, transactions, unneeded,
update, uploads, wrapped
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-10-09 08:17:24 +08:00
|
|
|
// Requires password strength in bits.
|
2019-08-25 15:39:31 +08:00
|
|
|
// 64 is just about memorable
|
|
|
|
// 128 is secure
|
|
|
|
func Password(bits int) (password string, err error) {
|
|
|
|
bytes := bits / 8
|
|
|
|
if bits%8 != 0 {
|
|
|
|
bytes++
|
|
|
|
}
|
|
|
|
var pw = make([]byte, bytes)
|
2020-11-18 20:03:01 +08:00
|
|
|
n, err := cryptorand.Read(pw)
|
2019-08-25 15:39:31 +08:00
|
|
|
if err != nil {
|
2021-11-04 18:12:57 +08:00
|
|
|
return "", fmt.Errorf("password read failed: %w", err)
|
2019-08-25 15:39:31 +08:00
|
|
|
}
|
|
|
|
if n != bytes {
|
2021-11-04 18:12:57 +08:00
|
|
|
return "", fmt.Errorf("password short read: %d", n)
|
2019-08-25 15:39:31 +08:00
|
|
|
}
|
|
|
|
password = base64.RawURLEncoding.EncodeToString(pw)
|
|
|
|
return password, nil
|
|
|
|
}
|