telws_handler.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package hhc_telws
  2. import (
  3. "crypto/rand"
  4. "encoding/hex"
  5. "encoding/json"
  6. "fmt"
  7. "git.swzry.com/zry/gorillaws2netconn"
  8. "github.com/gin-gonic/gin"
  9. "github.com/gorilla/websocket"
  10. "github.com/pascaldekloe/jwt"
  11. "github.com/tjfoc/gmsm/sm2"
  12. "io"
  13. "net/http"
  14. "time"
  15. )
  16. const JWT_KEY_LENGTH = 256
  17. type CliBackendHandler struct {
  18. jwtKey []byte
  19. errLog func(err error)
  20. authHandlers map[string]TelwsAuthHandler
  21. authMethodList []string
  22. gingrp *gin.RouterGroup
  23. jwtttl time.Duration
  24. sm2key *sm2.PrivateKey
  25. sm2pubkey string
  26. upgrader *websocket.Upgrader
  27. sessHandlerFactory TelwsSessionHandlerFactory
  28. }
  29. func NewCliBackendHandler(gingrp *gin.RouterGroup, tsfactory TelwsSessionHandlerFactory) *CliBackendHandler {
  30. cbh := &CliBackendHandler{
  31. gingrp: gingrp,
  32. authMethodList: make([]string, 0),
  33. authHandlers: make(map[string]TelwsAuthHandler),
  34. sessHandlerFactory: tsfactory,
  35. }
  36. cbh.upgrader = &websocket.Upgrader{
  37. CheckOrigin: func(r *http.Request) bool {
  38. return true
  39. },
  40. }
  41. cbh.gingrp.GET("/", cbh.handleGetTelwsInfo)
  42. cbh.gingrp.POST("/login.satori", cbh.handleLogin)
  43. cbh.gingrp.GET("/ws.satori", cbh.handleWebSocket)
  44. return cbh
  45. }
  46. func (cbh *CliBackendHandler) InitSecure(jwtttl time.Duration) error {
  47. cbh.jwtttl = jwtttl
  48. jbuf := make([]byte, JWT_KEY_LENGTH)
  49. _, err := io.ReadFull(rand.Reader, jbuf)
  50. if err != nil {
  51. return err
  52. }
  53. cbh.jwtKey = jbuf
  54. pk, err := sm2.GenerateKey()
  55. if err != nil {
  56. return err
  57. }
  58. cbh.sm2key = pk
  59. xenc := hex.EncodeToString(pk.X.Bytes())
  60. yenc := hex.EncodeToString(pk.Y.Bytes())
  61. cbh.sm2pubkey = SM2PubKeyCombine(xenc, yenc)
  62. return nil
  63. }
  64. func (cbh *CliBackendHandler) AddAuthHandler(ah TelwsAuthHandler) {
  65. ahname := ah.Register(cbh.jwtKey, cbh.jwtttl)
  66. cbh.authHandlers[ahname] = ah
  67. cbh.authMethodList = append(cbh.authMethodList, ahname)
  68. }
  69. func (cbh *CliBackendHandler) SetErrorLogFunction(fe func(err error)) {
  70. cbh.errLog = fe
  71. }
  72. func (cbh *CliBackendHandler) handleGetTelwsInfo(ctx *gin.Context) {
  73. ctx.JSON(200, gin.H{
  74. "protocol": "telws",
  75. "protocol_ver": "1.0",
  76. "auth_methods": cbh.authMethodList,
  77. "encrypt": map[string]string{
  78. "method": "sm2",
  79. "pubkey": cbh.sm2pubkey,
  80. "cipherMode": "C1C3C2",
  81. "header": "04",
  82. },
  83. })
  84. }
  85. type postJson_Login struct {
  86. AuthData string `json:"authData"`
  87. }
  88. func (cbh *CliBackendHandler) handleLogin(ctx *gin.Context) {
  89. var pjl postJson_Login
  90. err := ctx.BindJSON(&pjl)
  91. if err != nil {
  92. ctx.JSON(200, gin.H{
  93. "suc": false,
  94. "etype": "input_json_error",
  95. })
  96. return
  97. }
  98. data := pjl.AuthData
  99. if data == "" {
  100. ctx.JSON(200, gin.H{
  101. "suc": false,
  102. "etype": "no_cipher_text",
  103. })
  104. return
  105. }
  106. hdec, err := hex.DecodeString(data)
  107. if err != nil {
  108. ctx.JSON(200, gin.H{
  109. "suc": false,
  110. "etype": "hex_decode",
  111. })
  112. return
  113. }
  114. pt, err := sm2.Decrypt(cbh.sm2key, hdec)
  115. if err != nil {
  116. ctx.JSON(200, gin.H{
  117. "suc": false,
  118. "etype": "sm2_decrypt",
  119. })
  120. return
  121. }
  122. var jdata map[string]string
  123. err = json.Unmarshal(pt, &jdata)
  124. if err != nil {
  125. ctx.JSON(200, gin.H{
  126. "suc": false,
  127. "etype": "decrypted_json_error",
  128. })
  129. return
  130. }
  131. met, ok := jdata["method"]
  132. if !ok {
  133. ctx.JSON(200, gin.H{
  134. "suc": false,
  135. "etype": "no_auth_method_specified",
  136. })
  137. return
  138. }
  139. ah, ok := cbh.authHandlers[met]
  140. if !ok {
  141. ctx.JSON(200, gin.H{
  142. "suc": false,
  143. "etype": "unsupported_auth_method",
  144. })
  145. return
  146. }
  147. suc, jwtstr, emsg := ah.Login(jdata)
  148. if !suc {
  149. ctx.JSON(200, gin.H{
  150. "suc": false,
  151. "etype": "auth_failed",
  152. "auth_error_msg": emsg,
  153. })
  154. return
  155. }
  156. ctx.JSON(200, gin.H{
  157. "suc": true,
  158. "jwt": jwtstr,
  159. })
  160. }
  161. func (cbh *CliBackendHandler) handleWebSocket(ctx *gin.Context) {
  162. jwtstr := ctx.Request.FormValue("token")
  163. ws, err := cbh.upgrader.Upgrade(ctx.Writer, ctx.Request, nil)
  164. if err != nil {
  165. fmt.Println("WS Error:", err.Error())
  166. return
  167. }
  168. defer ws.Close()
  169. nconn := &gorillaws2netconn.NetConn4Gorilla{WS: ws, WriteMessageType: websocket.BinaryMessage}
  170. vclm, err := jwt.HMACCheck([]byte(jwtstr), cbh.jwtKey)
  171. if err != nil {
  172. if cbh.errLog != nil {
  173. cbh.errLog(err)
  174. }
  175. _, _ = fmt.Fprintf(nconn, "Websocket auth failed: %s\r\n", err.Error())
  176. ws.Close()
  177. return
  178. }
  179. tscc := WrapNewTelwsSessionContext()
  180. tscc.SetJwtClaims(vclm)
  181. tscc.SetConn(nconn)
  182. sh := cbh.sessHandlerFactory.GetSessionHandler()
  183. err = sh.HandleConnection(tscc.GetUserContext())
  184. if err != nil {
  185. if cbh.errLog != nil {
  186. cbh.errLog(err)
  187. }
  188. _, _ = fmt.Fprintf(nconn, "Websocket connection end by error: %s\r\n", err.Error())
  189. ws.Close()
  190. return
  191. } else {
  192. _, _ = fmt.Fprintf(nconn, "Websocket connection closed.\r\n")
  193. ws.Close()
  194. }
  195. }