actions.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package main
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "errors"
  6. "fmt"
  7. "math/rand"
  8. "net/http"
  9. "sparrow/pkg/models"
  10. "sparrow/pkg/rpcs"
  11. "sparrow/pkg/server"
  12. "sparrow/pkg/token"
  13. "strconv"
  14. "strings"
  15. "github.com/martini-contrib/render"
  16. )
  17. const (
  18. ErrOK = 0
  19. ErrSystemFault = 10001
  20. ErrDeviceNotFound = 10002
  21. ErrWrongSecret = 10003
  22. ErrProtocolNotSuported = 10004
  23. )
  24. func renderError(code int, err error) Common {
  25. result := Common{}
  26. result.Code = code
  27. result.Message = err.Error()
  28. server.Log.Error(err.Error())
  29. return result
  30. }
  31. // DeviceRegisterArgs device register args
  32. type DeviceRegisterArgs struct {
  33. ProductKey string `json:"product_key" binding:"required"`
  34. DeviceCode string `json:"device_code" binding:"required"`
  35. Version string `json:"version" binding:"required"`
  36. ModuleName string `json:"module" binding:"required"`
  37. }
  38. // DeviceAuthArgs device authentication args
  39. type DeviceAuthArgs struct {
  40. DeviceId int64 `json:"device_id" binding:"required"`
  41. DeviceSecret string `json:"device_secret" binding:"required"`
  42. Protocol string `json:"protocol" binding:"required"`
  43. }
  44. type AccessAuthArgs struct {
  45. UserName string `json:"username"`
  46. Password string `json:"password"`
  47. }
  48. type AccessAuthResp struct {
  49. Result string `json:"result"` // 可选 "allow" | "deny" | "ignore"
  50. IsSuperuser bool `json:"is_superuser"` // false
  51. }
  52. // RegisterDevice 设备激活
  53. func RegisterDevice(args DeviceRegisterArgs, r render.Render) {
  54. server.Log.Printf("ACTION RegisterDevice, args:: %v ", args)
  55. rpcargs := &rpcs.ArgsDeviceRegister{
  56. ProductKey: args.ProductKey,
  57. DeviceCode: args.DeviceCode,
  58. DeviceVersion: args.Version,
  59. ModuleName: args.ModuleName,
  60. }
  61. device := &models.Device{}
  62. err := server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.RegisterDevice", rpcargs, device)
  63. if err != nil {
  64. r.JSON(http.StatusOK, renderError(ErrSystemFault, err))
  65. return
  66. }
  67. server.Log.Infof("register device success: %v", device)
  68. result := DeviceRegisterResponse{}
  69. result.Data = DeviceRegisterData{
  70. DeviceId: int64(device.ID),
  71. DeviceSecret: device.DeviceSecret,
  72. DeviceKey: device.DeviceKey,
  73. DeviceIdentifier: device.DeviceIdentifier,
  74. }
  75. r.JSON(http.StatusOK, result)
  76. return
  77. }
  78. // DeviceAccessAuth emqx 设备接入认证
  79. func DeviceAccessAuth(args AccessAuthArgs, r render.Render) {
  80. server.Log.Printf("ACTION DeviceAccessAuth, args:: %v", args)
  81. result := AccessAuthResp{}
  82. if (args.UserName == "sparrow_test" && args.Password == "sparrow_test") || args.Password == "z6Kq9F3LbT" {
  83. result.Result = "allow"
  84. r.JSON(http.StatusOK, result)
  85. return
  86. }
  87. deviceId, err := ClientIDToDeviceID(args.UserName)
  88. if err != nil {
  89. server.Log.Errorf("invalid Identify: %s", args.UserName)
  90. result.Result = "deny"
  91. r.JSON(http.StatusOK, result)
  92. return
  93. }
  94. device := &models.Device{}
  95. err = server.RPCCallByName(nil, rpcs.RegistryServerName, "Registry.FindDeviceById", deviceId, device)
  96. if err != nil {
  97. server.Log.Errorf("device not found %d", deviceId)
  98. result.Result = "deny"
  99. r.JSON(http.StatusOK, result)
  100. return
  101. }
  102. // parse token
  103. token, err := hex.DecodeString(args.Password)
  104. if err != nil {
  105. server.Log.Errorf("token format error : %v", err)
  106. result.Result = "deny"
  107. r.JSON(http.StatusOK, result)
  108. return
  109. }
  110. // validate token
  111. if err := validateToken(device.RecordId, token); err != nil {
  112. server.Log.Errorf("validate token error : %v", err)
  113. result.Result = "deny"
  114. r.JSON(http.StatusOK, result)
  115. return
  116. }
  117. result.Result = "allow"
  118. r.JSON(http.StatusOK, result)
  119. }
  120. func validateToken(deviceRecordId string, token []byte) error {
  121. args := rpcs.ArgsValidateDeviceAccessToken{
  122. Id: deviceRecordId,
  123. AccessToken: token,
  124. }
  125. reply := rpcs.ReplyValidateDeviceAccessToken{}
  126. err := server.RPCCallByName(nil, rpcs.DeviceManagerName, "DeviceManager.ValidateDeviceAccessToken", args, &reply)
  127. if err != nil {
  128. return err
  129. }
  130. return nil
  131. }
  132. // AuthDevice device auth
  133. func AuthDevice(args DeviceAuthArgs, r render.Render) {
  134. device := &models.Device{}
  135. arg := uint64(args.DeviceId)
  136. err := server.RPCCallByName(context.Background(), rpcs.RegistryServerName, "Registry.FindDeviceById", &arg, device)
  137. if err != nil {
  138. r.JSON(http.StatusOK, renderError(ErrDeviceNotFound, err))
  139. return
  140. }
  141. fmt.Printf(fmt.Sprintf("%s, %s", device.DeviceSecret, args.DeviceSecret))
  142. if device.DeviceSecret != args.DeviceSecret {
  143. // device secret is wrong.
  144. r.JSON(http.StatusOK, renderError(ErrWrongSecret, errors.New("wrong device secret.")))
  145. return
  146. }
  147. hepler := token.NewHelper(*confRedisHost, *confRedisPort, *confRedisDb)
  148. token, err := hepler.GenerateToken(device.RecordId)
  149. if err != nil {
  150. r.JSON(http.StatusOK, renderError(ErrSystemFault, err))
  151. return
  152. }
  153. var hosts []string
  154. switch strings.ToLower(args.Protocol) {
  155. case "http":
  156. hosts, err = server.GetServerHosts(strings.ToUpper(args.Protocol)+"Access", "httphost")
  157. case "mqtt":
  158. hosts, err = server.GetServerHosts(strings.ToUpper(args.Protocol)+"Access", "tcphost")
  159. case "coap":
  160. hosts, err = server.GetServerHosts(strings.ToUpper(args.Protocol)+"Access", "udphost")
  161. case "mqttx": // TODO: 增加配置文件支持
  162. hosts = []string{
  163. "114.115.251.196:1883",
  164. }
  165. default:
  166. err = errors.New("unsuported protocol: " + args.Protocol)
  167. }
  168. if err != nil {
  169. r.JSON(http.StatusOK, renderError(ErrProtocolNotSuported, err))
  170. return
  171. }
  172. // just get a random host
  173. host := hosts[rand.Intn(len(hosts))]
  174. result := DeviceAuthResponse{}
  175. result.Data = DeviceAuthData{
  176. AccessToken: hex.EncodeToString(token),
  177. AccessAddr: host,
  178. }
  179. server.Log.Infof("auth device success: %v, token: %x, access: %v", device, token, host)
  180. r.JSON(http.StatusOK, result)
  181. return
  182. }
  183. func ClientIDToDeviceID(identify string) (uint64, error) {
  184. deviceId, err := strconv.ParseUint(identify, 16, 64)
  185. if err != nil {
  186. return uint64(0), err
  187. }
  188. return deviceId, nil
  189. }