serverpackets.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package remoteauth
  2. import (
  3. "crypto/sha256"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "time"
  8. "github.com/gorilla/websocket"
  9. "github.com/bwmarrin/discordgo"
  10. )
  11. type serverPacket interface {
  12. process(client *Client) error
  13. }
  14. func (c *Client) processMessages() {
  15. type rawPacket struct {
  16. OP string `json:"op"`
  17. }
  18. defer c.close()
  19. for {
  20. c.Lock()
  21. _, packet, err := c.conn.ReadMessage()
  22. c.Unlock()
  23. if err != nil {
  24. if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
  25. c.Lock()
  26. c.err = err
  27. c.Unlock()
  28. }
  29. return
  30. }
  31. raw := rawPacket{}
  32. if err := json.Unmarshal(packet, &raw); err != nil {
  33. c.Lock()
  34. c.err = err
  35. c.Unlock()
  36. return
  37. }
  38. var dest interface{}
  39. switch raw.OP {
  40. case "hello":
  41. dest = new(serverHello)
  42. case "nonce_proof":
  43. dest = new(serverNonceProof)
  44. case "pending_remote_init":
  45. dest = new(serverPendingRemoteInit)
  46. case "pending_ticket":
  47. dest = new(serverPendingTicket)
  48. case "pending_login":
  49. dest = new(serverPendingLogin)
  50. case "cancel":
  51. dest = new(serverCancel)
  52. case "heartbeat_ack":
  53. dest = new(serverHeartbeatAck)
  54. default:
  55. c.Lock()
  56. c.err = fmt.Errorf("unknown op %s", raw.OP)
  57. c.Unlock()
  58. return
  59. }
  60. if err := json.Unmarshal(packet, dest); err != nil {
  61. c.Lock()
  62. c.err = err
  63. c.Unlock()
  64. return
  65. }
  66. op := dest.(serverPacket)
  67. err = op.process(c)
  68. if err != nil {
  69. c.Lock()
  70. c.err = err
  71. c.Unlock()
  72. return
  73. }
  74. }
  75. }
  76. // /////////////////////////////////////////////////////////////////////////////
  77. // Hello
  78. // /////////////////////////////////////////////////////////////////////////////
  79. type serverHello struct {
  80. Timeout int `json:"timeout_ms"`
  81. HeartbeatInterval int `json:"heartbeat_interval"`
  82. }
  83. func (h *serverHello) process(client *Client) error {
  84. // Create our heartbeat handler
  85. ticker := time.NewTicker(time.Duration(h.HeartbeatInterval) * time.Millisecond)
  86. go func() {
  87. defer ticker.Stop()
  88. for {
  89. select {
  90. // case <-client.ctx.Done():
  91. // return
  92. case <-ticker.C:
  93. h := clientHeartbeat{}
  94. if err := h.send(client); err != nil {
  95. client.Lock()
  96. client.err = err
  97. client.Unlock()
  98. return
  99. }
  100. }
  101. }
  102. }()
  103. go func() {
  104. duration := time.Duration(h.Timeout) * time.Millisecond
  105. <-time.After(duration)
  106. client.Lock()
  107. client.err = fmt.Errorf("Timed out after %s", duration)
  108. client.close()
  109. client.Unlock()
  110. }()
  111. i := clientInit{}
  112. return i.send(client)
  113. }
  114. // /////////////////////////////////////////////////////////////////////////////
  115. // NonceProof
  116. // /////////////////////////////////////////////////////////////////////////////
  117. type serverNonceProof struct {
  118. EncryptedNonce string `json:"encrypted_nonce"`
  119. }
  120. func (n *serverNonceProof) process(client *Client) error {
  121. plaintext, err := client.decrypt(n.EncryptedNonce)
  122. if err != nil {
  123. return err
  124. }
  125. rawProof := sha256.Sum256(plaintext)
  126. // The [:] syntax is to return an unsized slice as the sum function returns
  127. // one.
  128. proof := base64.RawURLEncoding.EncodeToString(rawProof[:])
  129. c := clientNonceProof{Proof: proof}
  130. return c.send(client)
  131. }
  132. // /////////////////////////////////////////////////////////////////////////////
  133. // HeartbeatAck
  134. // /////////////////////////////////////////////////////////////////////////////
  135. type serverHeartbeatAck struct{}
  136. func (h *serverHeartbeatAck) process(client *Client) error {
  137. client.heartbeats -= 1
  138. return nil
  139. }
  140. // /////////////////////////////////////////////////////////////////////////////
  141. // PendingRemoteInit
  142. // /////////////////////////////////////////////////////////////////////////////
  143. type serverPendingRemoteInit struct {
  144. Fingerprint string `json:"fingerprint"`
  145. }
  146. func (p *serverPendingRemoteInit) process(client *Client) error {
  147. url := "https://discordapp.com/ra/" + p.Fingerprint
  148. client.qrChan <- url
  149. close(client.qrChan)
  150. return nil
  151. }
  152. // /////////////////////////////////////////////////////////////////////////////
  153. // PendingFinish
  154. // /////////////////////////////////////////////////////////////////////////////
  155. type serverPendingTicket struct {
  156. EncryptedUserPayload string `json:"encrypted_user_payload"`
  157. }
  158. func (p *serverPendingTicket) process(client *Client) error {
  159. plaintext, err := client.decrypt(p.EncryptedUserPayload)
  160. if err != nil {
  161. return err
  162. }
  163. return client.user.update(string(plaintext))
  164. }
  165. // /////////////////////////////////////////////////////////////////////////////
  166. // Finish
  167. // /////////////////////////////////////////////////////////////////////////////
  168. type serverPendingLogin struct {
  169. Ticket string `json:"ticket"`
  170. }
  171. func (p *serverPendingLogin) process(client *Client) error {
  172. sess, err := discordgo.New("")
  173. if err != nil {
  174. return err
  175. }
  176. encryptedToken, err := sess.RemoteAuthLogin(p.Ticket)
  177. if err != nil {
  178. return err
  179. }
  180. plaintext, err := client.decrypt(encryptedToken)
  181. if err != nil {
  182. return err
  183. }
  184. client.user.Token = string(plaintext)
  185. client.close()
  186. return nil
  187. }
  188. // /////////////////////////////////////////////////////////////////////////////
  189. // Cancel
  190. // /////////////////////////////////////////////////////////////////////////////
  191. type serverCancel struct{}
  192. func (c *serverCancel) process(client *Client) error {
  193. client.close()
  194. return nil
  195. }