serverpackets.go 4.6 KB

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