123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- // Package stringid provides helper functions for dealing with string identifiers
- package stringid
- import (
- cryptorand "crypto/rand"
- "encoding/hex"
- "fmt"
- "io"
- "math"
- "math/big"
- "math/rand"
- "regexp"
- "strconv"
- "strings"
- "time"
- )
- const shortLen = 12
- var (
- validShortID = regexp.MustCompile("^[a-f0-9]{12}$")
- validHex = regexp.MustCompile(`^[a-f0-9]{64}$`)
- )
- // IsShortID determines if an arbitrary string *looks like* a short ID.
- func IsShortID(id string) bool {
- return validShortID.MatchString(id)
- }
- // TruncateID returns a shorthand version of a string identifier for convenience.
- // A collision with other shorthands is very unlikely, but possible.
- // In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
- // will need to use a longer prefix, or the full-length Id.
- func TruncateID(id string) string {
- if i := strings.IndexRune(id, ':'); i >= 0 {
- id = id[i+1:]
- }
- if len(id) > shortLen {
- id = id[:shortLen]
- }
- return id
- }
- func generateID(r io.Reader) string {
- b := make([]byte, 32)
- for {
- if _, err := io.ReadFull(r, b); err != nil {
- panic(err) // This shouldn't happen
- }
- id := hex.EncodeToString(b)
- // if we try to parse the truncated for as an int and we don't have
- // an error then the value is all numeric and causes issues when
- // used as a hostname. ref #3869
- if _, err := strconv.ParseInt(TruncateID(id), 10, 64); err == nil {
- continue
- }
- return id
- }
- }
- // GenerateRandomID returns a unique id.
- func GenerateRandomID() string {
- return generateID(cryptorand.Reader)
- }
- // GenerateNonCryptoID generates unique id without using cryptographically
- // secure sources of random.
- // It helps you to save entropy.
- func GenerateNonCryptoID() string {
- return generateID(readerFunc(rand.Read))
- }
- // ValidateID checks whether an ID string is a valid image ID.
- func ValidateID(id string) error {
- if ok := validHex.MatchString(id); !ok {
- return fmt.Errorf("image ID %q is invalid", id)
- }
- return nil
- }
- func init() {
- // safely set the seed globally so we generate random ids. Tries to use a
- // crypto seed before falling back to time.
- var seed int64
- if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil {
- // This should not happen, but worst-case fallback to time-based seed.
- seed = time.Now().UnixNano()
- } else {
- seed = cryptoseed.Int64()
- }
- rand.Seed(seed)
- }
- type readerFunc func(p []byte) (int, error)
- func (fn readerFunc) Read(p []byte) (int, error) {
- return fn(p)
- }
|