You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
5.9 KiB

  1. // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining
  4. // a copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to
  8. // permit persons to whom the Software is furnished to do so, subject to
  9. // the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be
  12. // included in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. package uuid
  22. import (
  23. "crypto/md5"
  24. "crypto/rand"
  25. "crypto/sha1"
  26. "encoding/binary"
  27. "hash"
  28. "net"
  29. "os"
  30. "sync"
  31. "time"
  32. )
  33. // Difference in 100-nanosecond intervals between
  34. // UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
  35. const epochStart = 122192928000000000
  36. var (
  37. global = newDefaultGenerator()
  38. epochFunc = unixTimeFunc
  39. posixUID = uint32(os.Getuid())
  40. posixGID = uint32(os.Getgid())
  41. )
  42. // NewV1 returns UUID based on current timestamp and MAC address.
  43. func NewV1() UUID {
  44. return global.NewV1()
  45. }
  46. // NewV2 returns DCE Security UUID based on POSIX UID/GID.
  47. func NewV2(domain byte) UUID {
  48. return global.NewV2(domain)
  49. }
  50. // NewV3 returns UUID based on MD5 hash of namespace UUID and name.
  51. func NewV3(ns UUID, name string) UUID {
  52. return global.NewV3(ns, name)
  53. }
  54. // NewV4 returns random generated UUID.
  55. func NewV4() UUID {
  56. return global.NewV4()
  57. }
  58. // NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
  59. func NewV5(ns UUID, name string) UUID {
  60. return global.NewV5(ns, name)
  61. }
  62. // Generator provides interface for generating UUIDs.
  63. type Generator interface {
  64. NewV1() UUID
  65. NewV2(domain byte) UUID
  66. NewV3(ns UUID, name string) UUID
  67. NewV4() UUID
  68. NewV5(ns UUID, name string) UUID
  69. }
  70. // Default generator implementation.
  71. type generator struct {
  72. storageOnce sync.Once
  73. storageMutex sync.Mutex
  74. lastTime uint64
  75. clockSequence uint16
  76. hardwareAddr [6]byte
  77. }
  78. func newDefaultGenerator() Generator {
  79. return &generator{}
  80. }
  81. // NewV1 returns UUID based on current timestamp and MAC address.
  82. func (g *generator) NewV1() UUID {
  83. u := UUID{}
  84. timeNow, clockSeq, hardwareAddr := g.getStorage()
  85. binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
  86. binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
  87. binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
  88. binary.BigEndian.PutUint16(u[8:], clockSeq)
  89. copy(u[10:], hardwareAddr)
  90. u.SetVersion(V1)
  91. u.SetVariant(VariantRFC4122)
  92. return u
  93. }
  94. // NewV2 returns DCE Security UUID based on POSIX UID/GID.
  95. func (g *generator) NewV2(domain byte) UUID {
  96. u := UUID{}
  97. timeNow, clockSeq, hardwareAddr := g.getStorage()
  98. switch domain {
  99. case DomainPerson:
  100. binary.BigEndian.PutUint32(u[0:], posixUID)
  101. case DomainGroup:
  102. binary.BigEndian.PutUint32(u[0:], posixGID)
  103. }
  104. binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
  105. binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
  106. binary.BigEndian.PutUint16(u[8:], clockSeq)
  107. u[9] = domain
  108. copy(u[10:], hardwareAddr)
  109. u.SetVersion(V2)
  110. u.SetVariant(VariantRFC4122)
  111. return u
  112. }
  113. // NewV3 returns UUID based on MD5 hash of namespace UUID and name.
  114. func (g *generator) NewV3(ns UUID, name string) UUID {
  115. u := newFromHash(md5.New(), ns, name)
  116. u.SetVersion(V3)
  117. u.SetVariant(VariantRFC4122)
  118. return u
  119. }
  120. // NewV4 returns random generated UUID.
  121. func (g *generator) NewV4() UUID {
  122. u := UUID{}
  123. g.safeRandom(u[:])
  124. u.SetVersion(V4)
  125. u.SetVariant(VariantRFC4122)
  126. return u
  127. }
  128. // NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
  129. func (g *generator) NewV5(ns UUID, name string) UUID {
  130. u := newFromHash(sha1.New(), ns, name)
  131. u.SetVersion(V5)
  132. u.SetVariant(VariantRFC4122)
  133. return u
  134. }
  135. func (g *generator) initStorage() {
  136. g.initClockSequence()
  137. g.initHardwareAddr()
  138. }
  139. func (g *generator) initClockSequence() {
  140. buf := make([]byte, 2)
  141. g.safeRandom(buf)
  142. g.clockSequence = binary.BigEndian.Uint16(buf)
  143. }
  144. func (g *generator) initHardwareAddr() {
  145. interfaces, err := net.Interfaces()
  146. if err == nil {
  147. for _, iface := range interfaces {
  148. if len(iface.HardwareAddr) >= 6 {
  149. copy(g.hardwareAddr[:], iface.HardwareAddr)
  150. return
  151. }
  152. }
  153. }
  154. // Initialize hardwareAddr randomly in case
  155. // of real network interfaces absence
  156. g.safeRandom(g.hardwareAddr[:])
  157. // Set multicast bit as recommended in RFC 4122
  158. g.hardwareAddr[0] |= 0x01
  159. }
  160. func (g *generator) safeRandom(dest []byte) {
  161. if _, err := rand.Read(dest); err != nil {
  162. panic(err)
  163. }
  164. }
  165. // Returns UUID v1/v2 storage state.
  166. // Returns epoch timestamp, clock sequence, and hardware address.
  167. func (g *generator) getStorage() (uint64, uint16, []byte) {
  168. g.storageOnce.Do(g.initStorage)
  169. g.storageMutex.Lock()
  170. defer g.storageMutex.Unlock()
  171. timeNow := epochFunc()
  172. // Clock changed backwards since last UUID generation.
  173. // Should increase clock sequence.
  174. if timeNow <= g.lastTime {
  175. g.clockSequence++
  176. }
  177. g.lastTime = timeNow
  178. return timeNow, g.clockSequence, g.hardwareAddr[:]
  179. }
  180. // Returns difference in 100-nanosecond intervals between
  181. // UUID epoch (October 15, 1582) and current time.
  182. // This is default epoch calculation function.
  183. func unixTimeFunc() uint64 {
  184. return epochStart + uint64(time.Now().UnixNano()/100)
  185. }
  186. // Returns UUID based on hashing of namespace UUID and name.
  187. func newFromHash(h hash.Hash, ns UUID, name string) UUID {
  188. u := UUID{}
  189. h.Write(ns[:])
  190. h.Write([]byte(name))
  191. copy(u[:], h.Sum(nil))
  192. return u
  193. }