events.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package qr
  2. import (
  3. "crypto/rand"
  4. "crypto/rsa"
  5. "crypto/sha256"
  6. "crypto/x509"
  7. "encoding/base64"
  8. "encoding/json"
  9. "errors"
  10. "strings"
  11. "time"
  12. "github.com/ayn2op/discordo/internal/http"
  13. "github.com/ayn2op/tview"
  14. "github.com/diamondburned/arikawa/v3/utils/httputil"
  15. "github.com/gdamore/tcell/v3"
  16. "github.com/gorilla/websocket"
  17. "github.com/skip2/go-qrcode"
  18. )
  19. type TokenEvent struct {
  20. tcell.EventTime
  21. Token string
  22. }
  23. const remoteAuthGatewayURL = "wss://remote-auth-gateway.discord.gg/?v=2"
  24. type connCreateEvent struct {
  25. tcell.EventTime
  26. conn *websocket.Conn
  27. }
  28. type connCloseEvent struct{ tcell.EventTime }
  29. func (m *Model) connect() tview.Command {
  30. return func() tcell.Event {
  31. headers := http.Headers()
  32. headers.Set("User-Agent", http.BrowserUserAgent)
  33. conn, _, err := websocket.DefaultDialer.Dial(remoteAuthGatewayURL, headers)
  34. if err != nil {
  35. return tcell.NewEventError(err)
  36. }
  37. event := &connCreateEvent{conn: conn}
  38. event.SetEventNow()
  39. return event
  40. }
  41. }
  42. func (m *Model) close() tview.Command {
  43. return func() tcell.Event {
  44. if m.conn != nil {
  45. if err := m.conn.Close(); err != nil {
  46. return tcell.NewEventError(err)
  47. }
  48. }
  49. event := &connCloseEvent{}
  50. event.SetEventNow()
  51. return event
  52. }
  53. }
  54. type helloEvent struct {
  55. tcell.EventTime
  56. heartbeatInterval int
  57. timeoutMS int
  58. }
  59. type nonceProofEvent struct {
  60. tcell.EventTime
  61. encryptedNonce string
  62. }
  63. type pendingRemoteInitEvent struct {
  64. tcell.EventTime
  65. fingerprint string
  66. }
  67. type pendingTicketEvent struct {
  68. tcell.EventTime
  69. encryptedUserPayload string
  70. }
  71. type pendingLoginEvent struct {
  72. tcell.EventTime
  73. ticket string
  74. }
  75. type cancelEvent struct{ tcell.EventTime }
  76. func (m *Model) listen() tview.Command {
  77. return func() tcell.Event {
  78. if m.conn == nil {
  79. return nil
  80. }
  81. _, data, err := m.conn.ReadMessage()
  82. if err != nil {
  83. return tcell.NewEventError(err)
  84. }
  85. var payload struct {
  86. Op string `json:"op"`
  87. }
  88. if err := json.Unmarshal(data, &payload); err != nil {
  89. return tcell.NewEventError(err)
  90. }
  91. switch payload.Op {
  92. case "hello":
  93. var payload struct {
  94. HeartbeatInterval int `json:"heartbeat_interval"`
  95. TimeoutMS int `json:"timeout_ms"`
  96. }
  97. if err := json.Unmarshal(data, &payload); err != nil {
  98. return tcell.NewEventError(err)
  99. }
  100. event := &helloEvent{heartbeatInterval: payload.HeartbeatInterval, timeoutMS: payload.TimeoutMS}
  101. event.SetEventNow()
  102. return event
  103. case "nonce_proof":
  104. var payload struct {
  105. EncryptedNonce string `json:"encrypted_nonce"`
  106. }
  107. if err := json.Unmarshal(data, &payload); err != nil {
  108. return tcell.NewEventError(err)
  109. }
  110. event := &nonceProofEvent{encryptedNonce: payload.EncryptedNonce}
  111. event.SetEventNow()
  112. return event
  113. case "pending_remote_init":
  114. var payload struct {
  115. Fingerprint string `json:"fingerprint"`
  116. }
  117. if err := json.Unmarshal(data, &payload); err != nil {
  118. return tcell.NewEventError(err)
  119. }
  120. event := &pendingRemoteInitEvent{fingerprint: payload.Fingerprint}
  121. event.SetEventNow()
  122. return event
  123. case "pending_ticket":
  124. var payload struct {
  125. EncryptedUserPayload string `json:"encrypted_user_payload"`
  126. }
  127. if err := json.Unmarshal(data, &payload); err != nil {
  128. return tcell.NewEventError(err)
  129. }
  130. event := &pendingTicketEvent{encryptedUserPayload: payload.EncryptedUserPayload}
  131. event.SetEventNow()
  132. return event
  133. case "cancel":
  134. event := &cancelEvent{}
  135. event.SetEventNow()
  136. return event
  137. case "pending_login":
  138. var payload struct {
  139. Ticket string `json:"ticket"`
  140. }
  141. if err := json.Unmarshal(data, &payload); err != nil {
  142. return tcell.NewEventError(err)
  143. }
  144. event := &pendingLoginEvent{ticket: payload.Ticket}
  145. event.SetEventNow()
  146. return event
  147. default:
  148. return nil
  149. }
  150. }
  151. }
  152. type heartbeatTickEvent struct{ tcell.EventTime }
  153. func (m *Model) heartbeat() tview.Command {
  154. return func() tcell.Event {
  155. time.Sleep(m.heartbeatInterval)
  156. event := &heartbeatTickEvent{}
  157. event.SetEventNow()
  158. return event
  159. }
  160. }
  161. func (m *Model) sendHeartbeat() tview.Command {
  162. return func() tcell.Event {
  163. if m.conn == nil {
  164. return nil
  165. }
  166. data := struct {
  167. Op string `json:"op"`
  168. }{"heartbeat"}
  169. if err := m.conn.WriteJSON(data); err != nil {
  170. return tcell.NewEventError(err)
  171. }
  172. return nil
  173. }
  174. }
  175. type privateKeyEvent struct {
  176. tcell.EventTime
  177. privateKey *rsa.PrivateKey
  178. }
  179. func (m *Model) generatePrivateKey() tview.Command {
  180. return func() tcell.Event {
  181. privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
  182. if err != nil {
  183. return tcell.NewEventError(err)
  184. }
  185. event := &privateKeyEvent{privateKey: privateKey}
  186. event.SetEventNow()
  187. return event
  188. }
  189. }
  190. func (m *Model) sendInit() tview.Command {
  191. return func() tcell.Event {
  192. if m.privateKey == nil {
  193. return tcell.NewEventError(errors.New("missing private key"))
  194. }
  195. spki, err := x509.MarshalPKIXPublicKey(m.privateKey.Public())
  196. if err != nil {
  197. return tcell.NewEventError(err)
  198. }
  199. encodedPublicKey := base64.StdEncoding.EncodeToString(spki)
  200. data := struct {
  201. Op string `json:"op"`
  202. EncodedPublicKey string `json:"encoded_public_key"`
  203. }{"init", encodedPublicKey}
  204. if err := m.conn.WriteJSON(data); err != nil {
  205. return tcell.NewEventError(err)
  206. }
  207. return nil
  208. }
  209. }
  210. func (m *Model) sendNonceProof(encryptedNonce string) tview.Command {
  211. return func() tcell.Event {
  212. decodedNonce, err := base64.StdEncoding.DecodeString(encryptedNonce)
  213. if err != nil {
  214. return tcell.NewEventError(err)
  215. }
  216. decryptedNonce, err := rsa.DecryptOAEP(sha256.New(), nil, m.privateKey, decodedNonce, nil)
  217. if err != nil {
  218. return tcell.NewEventError(err)
  219. }
  220. encodedNonce := base64.RawURLEncoding.EncodeToString(decryptedNonce)
  221. data := struct {
  222. Op string `json:"op"`
  223. Nonce string `json:"nonce"`
  224. }{"nonce_proof", encodedNonce}
  225. if err := m.conn.WriteJSON(data); err != nil {
  226. return tcell.NewEventError(err)
  227. }
  228. return nil
  229. }
  230. }
  231. type qrCodeEvent struct {
  232. tcell.EventTime
  233. qrCode *qrcode.QRCode
  234. }
  235. func (m *Model) generateQRCode(fingerprint string) tview.Command {
  236. return func() tcell.Event {
  237. content := "https://discord.com/ra/" + fingerprint
  238. qrCode, err := qrcode.New(content, qrcode.Low)
  239. if err != nil {
  240. return tcell.NewEventError(err)
  241. }
  242. qrCode.DisableBorder = true
  243. event := &qrCodeEvent{qrCode: qrCode}
  244. event.SetEventNow()
  245. return event
  246. }
  247. }
  248. type userEvent struct {
  249. tcell.EventTime
  250. discriminator string
  251. username string
  252. }
  253. func (m *Model) decryptUserPayload(encryptedPayload string) tview.Command {
  254. return func() tcell.Event {
  255. decodedPayload, err := base64.StdEncoding.DecodeString(encryptedPayload)
  256. if err != nil {
  257. return tcell.NewEventError(err)
  258. }
  259. decryptedPayload, err := rsa.DecryptOAEP(sha256.New(), nil, m.privateKey, decodedPayload, nil)
  260. if err != nil {
  261. return tcell.NewEventError(err)
  262. }
  263. parts := strings.Split(string(decryptedPayload), ":")
  264. if len(parts) != 4 {
  265. return tcell.NewEventError(errors.New("invalid user payload"))
  266. }
  267. event := &userEvent{discriminator: parts[1], username: parts[3]}
  268. event.SetEventNow()
  269. return event
  270. }
  271. }
  272. func (m *Model) exchangeTicket(ticket string) tview.Command {
  273. return func() tcell.Event {
  274. headers := http.Headers()
  275. headers.Set("Referer", "https://discord.com/login")
  276. if m.fingerprint != "" {
  277. headers.Set("X-Fingerprint", m.fingerprint)
  278. }
  279. client := http.NewClient("")
  280. client.OnRequest = append(client.OnRequest, httputil.WithHeaders(headers))
  281. encryptedToken, err := client.ExchangeRemoteAuthTicket(ticket)
  282. if err != nil {
  283. return tcell.NewEventError(err)
  284. }
  285. decodedToken, err := base64.StdEncoding.DecodeString(encryptedToken)
  286. if err != nil {
  287. return tcell.NewEventError(err)
  288. }
  289. decryptedToken, err := rsa.DecryptOAEP(sha256.New(), nil, m.privateKey, decodedToken, nil)
  290. if err != nil {
  291. return tcell.NewEventError(err)
  292. }
  293. event := &TokenEvent{Token: string(decryptedToken)}
  294. event.SetEventNow()
  295. return event
  296. }
  297. }