liscense-deviceId.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. //go:build windows
  2. // +build windows
  3. package comm
  4. import (
  5. "context"
  6. "crypto/md5"
  7. "crypto/rand"
  8. "encoding/base64"
  9. "encoding/hex"
  10. "fmt"
  11. "net"
  12. "strings"
  13. "unsafe"
  14. "github.com/StackExchange/wmi"
  15. "golang.org/x/sys/windows"
  16. )
  17. func GetPhysicalID() string {
  18. var ids []string
  19. mac := getMACAddress()
  20. if len(mac) < 1 {
  21. mac = "mac"
  22. }
  23. ids = append(ids, mac)
  24. guid, _ := getMachineGuid()
  25. if len(guid) < 1 {
  26. guid = "guid"
  27. }
  28. ids = append(ids, guid)
  29. cpuinfo, err := getCPUInfo()
  30. cpus := []string{}
  31. if err == nil {
  32. for _, c := range cpuinfo {
  33. cpus = append(cpus, c.VendorID+c.PhysicalID)
  34. }
  35. }
  36. cpu := "cpu"
  37. if len(cpu) > 0 {
  38. cpu = strings.Join(cpus, ",")
  39. }
  40. ids = append(ids, cpu)
  41. idsstr := strings.Join(ids, "|")
  42. return idsstr
  43. }
  44. func getMACAddress() string {
  45. netInterfaces, err := net.Interfaces()
  46. if err != nil {
  47. return ""
  48. }
  49. for i := 0; i < len(netInterfaces); i++ {
  50. //fmt.Println(netInterfaces[i])
  51. if (netInterfaces[i].Flags&net.FlagUp) != 0 && (netInterfaces[i].Flags&net.FlagLoopback) == 0 {
  52. addrs, _ := netInterfaces[i].Addrs()
  53. for _, address := range addrs {
  54. ipnet, ok := address.(*net.IPNet)
  55. //fmt.Println(ipnet.IP)
  56. if ok && ipnet.IP.IsGlobalUnicast() {
  57. // 如果IP是全局单拨地址,则返回MAC地址
  58. return netInterfaces[i].HardwareAddr.String()
  59. }
  60. }
  61. }
  62. }
  63. return ""
  64. }
  65. type cpuInfo struct {
  66. CPU int32 `json:"cpu"`
  67. VendorID string `json:"vendorId"`
  68. PhysicalID string `json:"physicalId"`
  69. }
  70. type win32_Processor struct {
  71. Manufacturer string
  72. ProcessorID *string
  73. }
  74. func getCPUInfo() ([]cpuInfo, error) {
  75. var ret []cpuInfo
  76. var dst []win32_Processor
  77. q := wmi.CreateQuery(&dst, "")
  78. fmt.Println(q)
  79. if err := wmiQuery(q, &dst); err != nil {
  80. return ret, err
  81. }
  82. var procID string
  83. for i, l := range dst {
  84. procID = ""
  85. if l.ProcessorID != nil {
  86. procID = *l.ProcessorID
  87. }
  88. cpu := cpuInfo{
  89. CPU: int32(i),
  90. VendorID: l.Manufacturer,
  91. PhysicalID: procID,
  92. }
  93. ret = append(ret, cpu)
  94. }
  95. return ret, nil
  96. }
  97. // WMIQueryWithContext - wraps wmi.Query with a timed-out context to avoid hanging
  98. func wmiQuery(query string, dst interface{}, connectServerArgs ...interface{}) error {
  99. ctx := context.Background()
  100. if _, ok := ctx.Deadline(); !ok {
  101. ctxTimeout, cancel := context.WithTimeout(ctx, 3000000000) //超时时间3s
  102. defer cancel()
  103. ctx = ctxTimeout
  104. }
  105. errChan := make(chan error, 1)
  106. go func() {
  107. errChan <- wmi.Query(query, dst, connectServerArgs...)
  108. }()
  109. select {
  110. case <-ctx.Done():
  111. return ctx.Err()
  112. case err := <-errChan:
  113. return err
  114. }
  115. }
  116. func getMachineGuid() (string, error) {
  117. // there has been reports of issues on 32bit using golang.org/x/sys/windows/registry, see https://github.com/shirou/gopsutil/pull/312#issuecomment-277422612
  118. // for rationale of using windows.RegOpenKeyEx/RegQueryValueEx instead of registry.OpenKey/GetStringValue
  119. var h windows.Handle
  120. err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)
  121. if err != nil {
  122. return "", err
  123. }
  124. defer windows.RegCloseKey(h)
  125. const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16
  126. const uuidLen = 36
  127. var regBuf [windowsRegBufLen]uint16
  128. bufLen := uint32(windowsRegBufLen)
  129. var valType uint32
  130. err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(&regBuf[0])), &bufLen)
  131. if err != nil {
  132. return "", err
  133. }
  134. hostID := windows.UTF16ToString(regBuf[:])
  135. hostIDLen := len(hostID)
  136. if hostIDLen != uuidLen {
  137. return "", fmt.Errorf("HostID incorrect: %q\n", hostID)
  138. }
  139. return hostID, nil
  140. }
  141. // 生成32位md5字串
  142. func GetMd5String(s string, upper bool, half bool) string {
  143. h := md5.New()
  144. h.Write([]byte(s))
  145. result := hex.EncodeToString(h.Sum(nil))
  146. if upper == true {
  147. result = strings.ToUpper(result)
  148. }
  149. if half == true {
  150. result = result[8:24]
  151. }
  152. return result
  153. }
  154. // 利用随机数生成Guid字串
  155. func UniqueId() string {
  156. b := make([]byte, 48)
  157. if _, err := rand.Read(b); err != nil {
  158. return ""
  159. }
  160. return GetMd5String(base64.URLEncoding.EncodeToString(b), true, false)
  161. }
  162. func GetDeviceHash() string {
  163. //校验设备
  164. id := GetPhysicalID()
  165. if len(id) < 1 {
  166. return ""
  167. }
  168. return GetMd5String(id, true, true)
  169. }