blob: 0c10c4e9f5fac01c214dc0b4cdd7bb9619269705 [file] [log] [blame]
Scott Bakered4efab2020-01-13 19:12:25 -08001package uuid
2
3import (
4 "crypto/rand"
5 "encoding/hex"
6 "fmt"
David K. Bainbridgebd6b2882021-08-26 13:31:02 +00007 "io"
Scott Bakered4efab2020-01-13 19:12:25 -08008)
9
10// GenerateRandomBytes is used to generate random bytes of given size.
11func GenerateRandomBytes(size int) ([]byte, error) {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000012 return GenerateRandomBytesWithReader(size, rand.Reader)
13}
14
15// GenerateRandomBytesWithReader is used to generate random bytes of given size read from a given reader.
16func GenerateRandomBytesWithReader(size int, reader io.Reader) ([]byte, error) {
17 if reader == nil {
18 return nil, fmt.Errorf("provided reader is nil")
19 }
Scott Bakered4efab2020-01-13 19:12:25 -080020 buf := make([]byte, size)
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000021 if _, err := io.ReadFull(reader, buf); err != nil {
Scott Bakered4efab2020-01-13 19:12:25 -080022 return nil, fmt.Errorf("failed to read random bytes: %v", err)
23 }
24 return buf, nil
25}
26
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000027
Scott Bakered4efab2020-01-13 19:12:25 -080028const uuidLen = 16
29
30// GenerateUUID is used to generate a random UUID
31func GenerateUUID() (string, error) {
David K. Bainbridgebd6b2882021-08-26 13:31:02 +000032 return GenerateUUIDWithReader(rand.Reader)
33}
34
35// GenerateUUIDWithReader is used to generate a random UUID with a given Reader
36func GenerateUUIDWithReader(reader io.Reader) (string, error) {
37 if reader == nil {
38 return "", fmt.Errorf("provided reader is nil")
39 }
40 buf, err := GenerateRandomBytesWithReader(uuidLen, reader)
Scott Bakered4efab2020-01-13 19:12:25 -080041 if err != nil {
42 return "", err
43 }
44 return FormatUUID(buf)
45}
46
47func FormatUUID(buf []byte) (string, error) {
48 if buflen := len(buf); buflen != uuidLen {
49 return "", fmt.Errorf("wrong length byte slice (%d)", buflen)
50 }
51
52 return fmt.Sprintf("%x-%x-%x-%x-%x",
53 buf[0:4],
54 buf[4:6],
55 buf[6:8],
56 buf[8:10],
57 buf[10:16]), nil
58}
59
60func ParseUUID(uuid string) ([]byte, error) {
61 if len(uuid) != 2 * uuidLen + 4 {
62 return nil, fmt.Errorf("uuid string is wrong length")
63 }
64
65 if uuid[8] != '-' ||
66 uuid[13] != '-' ||
67 uuid[18] != '-' ||
68 uuid[23] != '-' {
69 return nil, fmt.Errorf("uuid is improperly formatted")
70 }
71
72 hexStr := uuid[0:8] + uuid[9:13] + uuid[14:18] + uuid[19:23] + uuid[24:36]
73
74 ret, err := hex.DecodeString(hexStr)
75 if err != nil {
76 return nil, err
77 }
78 if len(ret) != uuidLen {
79 return nil, fmt.Errorf("decoded hex is the wrong length")
80 }
81
82 return ret, nil
83}