blob: 2404efc940d0abd3c3dc2f7cc6ceded796d1d663 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2013 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package utils
5
6import (
7 "crypto/rand"
8 "encoding/hex"
9 "fmt"
10 "io"
11 "regexp"
12 "strings"
13)
14
15// UUID represent a universal identifier with 16 octets.
16type UUID [16]byte
17
18// regex for validating that the UUID matches RFC 4122.
19// This package generates version 4 UUIDs but
20// accepts any UUID version.
21// http://www.ietf.org/rfc/rfc4122.txt
22var (
23 block1 = "[0-9a-f]{8}"
24 block2 = "[0-9a-f]{4}"
25 block3 = "[0-9a-f]{4}"
26 block4 = "[0-9a-f]{4}"
27 block5 = "[0-9a-f]{12}"
28
29 UUIDSnippet = block1 + "-" + block2 + "-" + block3 + "-" + block4 + "-" + block5
30 validUUID = regexp.MustCompile("^" + UUIDSnippet + "$")
31)
32
33func UUIDFromString(s string) (UUID, error) {
34 if !IsValidUUIDString(s) {
35 return UUID{}, fmt.Errorf("invalid UUID: %q", s)
36 }
37 s = strings.Replace(s, "-", "", 4)
38 raw, err := hex.DecodeString(s)
39 if err != nil {
40 return UUID{}, err
41 }
42 var uuid UUID
43 copy(uuid[:], raw)
44 return uuid, nil
45}
46
47// IsValidUUIDString returns true, if the given string matches a valid UUID (version 4, variant 2).
48func IsValidUUIDString(s string) bool {
49 return validUUID.MatchString(s)
50}
51
52// MustNewUUID returns a new uuid, if an error occurs it panics.
53func MustNewUUID() UUID {
54 uuid, err := NewUUID()
55 if err != nil {
56 panic(err)
57 }
58 return uuid
59}
60
61// NewUUID generates a new version 4 UUID relying only on random numbers.
62func NewUUID() (UUID, error) {
63 uuid := UUID{}
64 if _, err := io.ReadFull(rand.Reader, []byte(uuid[0:16])); err != nil {
65 return UUID{}, err
66 }
67 // Set version (4) and variant (2) according to RfC 4122.
68 var version byte = 4 << 4
69 var variant byte = 8 << 4
70 uuid[6] = version | (uuid[6] & 15)
71 uuid[8] = variant | (uuid[8] & 15)
72 return uuid, nil
73}
74
75// Copy returns a copy of the UUID.
76func (uuid UUID) Copy() UUID {
77 uuidCopy := uuid
78 return uuidCopy
79}
80
81// Raw returns a copy of the UUID bytes.
82func (uuid UUID) Raw() [16]byte {
83 return [16]byte(uuid)
84}
85
86// String returns a hexadecimal string representation with
87// standardized separators.
88func (uuid UUID) String() string {
89 return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
90}