uuid.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // Copyright 2018 Google Inc. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package uuid
  5. import (
  6. "bytes"
  7. "crypto/rand"
  8. "encoding/hex"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "strings"
  13. "sync"
  14. )
  15. // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
  16. // 4122.
  17. type UUID [16]byte
  18. // A Version represents a UUID's version.
  19. type Version byte
  20. // A Variant represents a UUID's variant.
  21. type Variant byte
  22. // Constants returned by Variant.
  23. const (
  24. Invalid = Variant(iota) // Invalid UUID
  25. RFC4122 // The variant specified in RFC4122
  26. Reserved // Reserved, NCS backward compatibility.
  27. Microsoft // Reserved, Microsoft Corporation backward compatibility.
  28. Future // Reserved for future definition.
  29. )
  30. const randPoolSize = 16 * 16
  31. var (
  32. rander = rand.Reader // random function
  33. poolEnabled = false
  34. poolMu sync.Mutex
  35. poolPos = randPoolSize // protected with poolMu
  36. pool [randPoolSize]byte // protected with poolMu
  37. )
  38. type invalidLengthError struct{ len int }
  39. func (err invalidLengthError) Error() string {
  40. return fmt.Sprintf("invalid UUID length: %d", err.len)
  41. }
  42. // IsInvalidLengthError is matcher function for custom error invalidLengthError
  43. func IsInvalidLengthError(err error) bool {
  44. _, ok := err.(invalidLengthError)
  45. return ok
  46. }
  47. // Parse decodes s into a UUID or returns an error if it cannot be parsed. Both
  48. // the standard UUID forms defined in RFC 4122
  49. // (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
  50. // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition,
  51. // Parse accepts non-standard strings such as the raw hex encoding
  52. // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings,
  53. // e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are
  54. // examined in the latter case. Parse should not be used to validate strings as
  55. // it parses non-standard encodings as indicated above.
  56. func Parse(s string) (UUID, error) {
  57. var uuid UUID
  58. switch len(s) {
  59. // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  60. case 36:
  61. // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  62. case 36 + 9:
  63. if !strings.EqualFold(s[:9], "urn:uuid:") {
  64. return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
  65. }
  66. s = s[9:]
  67. // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  68. case 36 + 2:
  69. s = s[1:]
  70. // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  71. case 32:
  72. var ok bool
  73. for i := range uuid {
  74. uuid[i], ok = xtob(s[i*2], s[i*2+1])
  75. if !ok {
  76. return uuid, errors.New("invalid UUID format")
  77. }
  78. }
  79. return uuid, nil
  80. default:
  81. return uuid, invalidLengthError{len(s)}
  82. }
  83. // s is now at least 36 bytes long
  84. // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  85. if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
  86. return uuid, errors.New("invalid UUID format")
  87. }
  88. for i, x := range [16]int{
  89. 0, 2, 4, 6,
  90. 9, 11,
  91. 14, 16,
  92. 19, 21,
  93. 24, 26, 28, 30, 32, 34,
  94. } {
  95. v, ok := xtob(s[x], s[x+1])
  96. if !ok {
  97. return uuid, errors.New("invalid UUID format")
  98. }
  99. uuid[i] = v
  100. }
  101. return uuid, nil
  102. }
  103. // ParseBytes is like Parse, except it parses a byte slice instead of a string.
  104. func ParseBytes(b []byte) (UUID, error) {
  105. var uuid UUID
  106. switch len(b) {
  107. case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  108. case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  109. if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
  110. return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
  111. }
  112. b = b[9:]
  113. case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  114. b = b[1:]
  115. case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  116. var ok bool
  117. for i := 0; i < 32; i += 2 {
  118. uuid[i/2], ok = xtob(b[i], b[i+1])
  119. if !ok {
  120. return uuid, errors.New("invalid UUID format")
  121. }
  122. }
  123. return uuid, nil
  124. default:
  125. return uuid, invalidLengthError{len(b)}
  126. }
  127. // s is now at least 36 bytes long
  128. // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  129. if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
  130. return uuid, errors.New("invalid UUID format")
  131. }
  132. for i, x := range [16]int{
  133. 0, 2, 4, 6,
  134. 9, 11,
  135. 14, 16,
  136. 19, 21,
  137. 24, 26, 28, 30, 32, 34,
  138. } {
  139. v, ok := xtob(b[x], b[x+1])
  140. if !ok {
  141. return uuid, errors.New("invalid UUID format")
  142. }
  143. uuid[i] = v
  144. }
  145. return uuid, nil
  146. }
  147. // MustParse is like Parse but panics if the string cannot be parsed.
  148. // It simplifies safe initialization of global variables holding compiled UUIDs.
  149. func MustParse(s string) UUID {
  150. uuid, err := Parse(s)
  151. if err != nil {
  152. panic(`uuid: Parse(` + s + `): ` + err.Error())
  153. }
  154. return uuid
  155. }
  156. // FromBytes creates a new UUID from a byte slice. Returns an error if the slice
  157. // does not have a length of 16. The bytes are copied from the slice.
  158. func FromBytes(b []byte) (uuid UUID, err error) {
  159. err = uuid.UnmarshalBinary(b)
  160. return uuid, err
  161. }
  162. // Must returns uuid if err is nil and panics otherwise.
  163. func Must(uuid UUID, err error) UUID {
  164. if err != nil {
  165. panic(err)
  166. }
  167. return uuid
  168. }
  169. // Validate returns an error if s is not a properly formatted UUID in one of the following formats:
  170. // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  171. // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  172. // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  173. // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  174. // It returns an error if the format is invalid, otherwise nil.
  175. func Validate(s string) error {
  176. switch len(s) {
  177. // Standard UUID format
  178. case 36:
  179. // UUID with "urn:uuid:" prefix
  180. case 36 + 9:
  181. if !strings.EqualFold(s[:9], "urn:uuid:") {
  182. return fmt.Errorf("invalid urn prefix: %q", s[:9])
  183. }
  184. s = s[9:]
  185. // UUID enclosed in braces
  186. case 36 + 2:
  187. if s[0] != '{' || s[len(s)-1] != '}' {
  188. return fmt.Errorf("invalid bracketed UUID format")
  189. }
  190. s = s[1 : len(s)-1]
  191. // UUID without hyphens
  192. case 32:
  193. for i := 0; i < len(s); i += 2 {
  194. _, ok := xtob(s[i], s[i+1])
  195. if !ok {
  196. return errors.New("invalid UUID format")
  197. }
  198. }
  199. default:
  200. return invalidLengthError{len(s)}
  201. }
  202. // Check for standard UUID format
  203. if len(s) == 36 {
  204. if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
  205. return errors.New("invalid UUID format")
  206. }
  207. for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
  208. if _, ok := xtob(s[x], s[x+1]); !ok {
  209. return errors.New("invalid UUID format")
  210. }
  211. }
  212. }
  213. return nil
  214. }
  215. // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  216. // , or "" if uuid is invalid.
  217. func (uuid UUID) String() string {
  218. var buf [36]byte
  219. encodeHex(buf[:], uuid)
  220. return string(buf[:])
  221. }
  222. // URN returns the RFC 2141 URN form of uuid,
  223. // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
  224. func (uuid UUID) URN() string {
  225. var buf [36 + 9]byte
  226. copy(buf[:], "urn:uuid:")
  227. encodeHex(buf[9:], uuid)
  228. return string(buf[:])
  229. }
  230. func encodeHex(dst []byte, uuid UUID) {
  231. hex.Encode(dst, uuid[:4])
  232. dst[8] = '-'
  233. hex.Encode(dst[9:13], uuid[4:6])
  234. dst[13] = '-'
  235. hex.Encode(dst[14:18], uuid[6:8])
  236. dst[18] = '-'
  237. hex.Encode(dst[19:23], uuid[8:10])
  238. dst[23] = '-'
  239. hex.Encode(dst[24:], uuid[10:])
  240. }
  241. // Variant returns the variant encoded in uuid.
  242. func (uuid UUID) Variant() Variant {
  243. switch {
  244. case (uuid[8] & 0xc0) == 0x80:
  245. return RFC4122
  246. case (uuid[8] & 0xe0) == 0xc0:
  247. return Microsoft
  248. case (uuid[8] & 0xe0) == 0xe0:
  249. return Future
  250. default:
  251. return Reserved
  252. }
  253. }
  254. // Version returns the version of uuid.
  255. func (uuid UUID) Version() Version {
  256. return Version(uuid[6] >> 4)
  257. }
  258. func (v Version) String() string {
  259. if v > 15 {
  260. return fmt.Sprintf("BAD_VERSION_%d", v)
  261. }
  262. return fmt.Sprintf("VERSION_%d", v)
  263. }
  264. func (v Variant) String() string {
  265. switch v {
  266. case RFC4122:
  267. return "RFC4122"
  268. case Reserved:
  269. return "Reserved"
  270. case Microsoft:
  271. return "Microsoft"
  272. case Future:
  273. return "Future"
  274. case Invalid:
  275. return "Invalid"
  276. }
  277. return fmt.Sprintf("BadVariant%d", int(v))
  278. }
  279. // SetRand sets the random number generator to r, which implements io.Reader.
  280. // If r.Read returns an error when the package requests random data then
  281. // a panic will be issued.
  282. //
  283. // Calling SetRand with nil sets the random number generator to the default
  284. // generator.
  285. func SetRand(r io.Reader) {
  286. if r == nil {
  287. rander = rand.Reader
  288. return
  289. }
  290. rander = r
  291. }
  292. // EnableRandPool enables internal randomness pool used for Random
  293. // (Version 4) UUID generation. The pool contains random bytes read from
  294. // the random number generator on demand in batches. Enabling the pool
  295. // may improve the UUID generation throughput significantly.
  296. //
  297. // Since the pool is stored on the Go heap, this feature may be a bad fit
  298. // for security sensitive applications.
  299. //
  300. // Both EnableRandPool and DisableRandPool are not thread-safe and should
  301. // only be called when there is no possibility that New or any other
  302. // UUID Version 4 generation function will be called concurrently.
  303. func EnableRandPool() {
  304. poolEnabled = true
  305. }
  306. // DisableRandPool disables the randomness pool if it was previously
  307. // enabled with EnableRandPool.
  308. //
  309. // Both EnableRandPool and DisableRandPool are not thread-safe and should
  310. // only be called when there is no possibility that New or any other
  311. // UUID Version 4 generation function will be called concurrently.
  312. func DisableRandPool() {
  313. poolEnabled = false
  314. defer poolMu.Unlock()
  315. poolMu.Lock()
  316. poolPos = randPoolSize
  317. }
  318. // UUIDs is a slice of UUID types.
  319. type UUIDs []UUID
  320. // Strings returns a string slice containing the string form of each UUID in uuids.
  321. func (uuids UUIDs) Strings() []string {
  322. var uuidStrs = make([]string, len(uuids))
  323. for i, uuid := range uuids {
  324. uuidStrs[i] = uuid.String()
  325. }
  326. return uuidStrs
  327. }