1// Package stringid provides helper functions for dealing with string identifiers
2package stringid // import "github.com/docker/docker/pkg/stringid"
3
4import (
5	"crypto/rand"
6	"encoding/hex"
7	"fmt"
8	"regexp"
9	"strconv"
10	"strings"
11)
12
13const shortLen = 12
14
15var (
16	validShortID = regexp.MustCompile("^[a-f0-9]{12}$")
17	validHex     = regexp.MustCompile(`^[a-f0-9]{64}$`)
18)
19
20// IsShortID determines if an arbitrary string *looks like* a short ID.
21func IsShortID(id string) bool {
22	return validShortID.MatchString(id)
23}
24
25// TruncateID returns a shorthand version of a string identifier for convenience.
26// A collision with other shorthands is very unlikely, but possible.
27// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
28// will need to use a longer prefix, or the full-length Id.
29func TruncateID(id string) string {
30	if i := strings.IndexRune(id, ':'); i >= 0 {
31		id = id[i+1:]
32	}
33	if len(id) > shortLen {
34		id = id[:shortLen]
35	}
36	return id
37}
38
39// GenerateRandomID returns a unique id.
40func GenerateRandomID() string {
41	b := make([]byte, 32)
42	for {
43		if _, err := rand.Read(b); err != nil {
44			panic(err) // This shouldn't happen
45		}
46		id := hex.EncodeToString(b)
47		// if we try to parse the truncated for as an int and we don't have
48		// an error then the value is all numeric and causes issues when
49		// used as a hostname. ref #3869
50		if _, err := strconv.ParseInt(TruncateID(id), 10, 64); err == nil {
51			continue
52		}
53		return id
54	}
55}
56
57// ValidateID checks whether an ID string is a valid image ID.
58func ValidateID(id string) error {
59	if ok := validHex.MatchString(id); !ok {
60		return fmt.Errorf("image ID %q is invalid", id)
61	}
62	return nil
63}
64