main.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package main
  2. import (
  3. "encoding/json"
  4. "os"
  5. "github.com/ayntgl/discordgo"
  6. "github.com/ayntgl/discordo/config"
  7. "github.com/ayntgl/discordo/ui"
  8. "github.com/rivo/tview"
  9. "github.com/zalando/go-keyring"
  10. )
  11. const service = "discordo"
  12. func main() {
  13. app := ui.NewApp()
  14. app.EnableMouse(config.General.Mouse)
  15. token := os.Getenv("DISCORDO_TOKEN")
  16. if token == "" {
  17. token, _ = keyring.Get(service, "token")
  18. }
  19. if token != "" {
  20. err := app.Connect(token)
  21. if err != nil {
  22. panic(err)
  23. }
  24. ui.DrawMainFlex(app)
  25. app.
  26. SetRoot(app.MainFlex, true).
  27. SetFocus(app.GuildsList)
  28. } else {
  29. app.LoginForm = ui.NewLoginForm(func() {
  30. onLoginFormLoginButtonSelected(app)
  31. }, false)
  32. app.SetRoot(app.LoginForm, true)
  33. }
  34. if err := app.Run(); err != nil {
  35. panic(err)
  36. }
  37. }
  38. func onLoginFormLoginButtonSelected(app *ui.App) {
  39. email := app.LoginForm.GetFormItem(0).(*tview.InputField).GetText()
  40. password := app.LoginForm.GetFormItem(1).(*tview.InputField).GetText()
  41. if email == "" || password == "" {
  42. return
  43. }
  44. // Login using the email and password
  45. lr, err := login(app.Session, email, password)
  46. if err != nil {
  47. panic(err)
  48. }
  49. if lr.Token != "" && !lr.MFA {
  50. app.
  51. SetRoot(app.MainFlex, true).
  52. SetFocus(app.GuildsList)
  53. err = app.Connect(lr.Token)
  54. if err != nil {
  55. panic(err)
  56. }
  57. go keyring.Set(service, "token", lr.Token)
  58. } else if lr.MFA {
  59. // The account has MFA enabled, reattempt login with code and ticket.
  60. app.LoginForm = ui.NewLoginForm(func() {
  61. code := app.LoginForm.GetFormItem(0).(*tview.InputField).GetText()
  62. if code == "" {
  63. return
  64. }
  65. lr, err = totp(app.Session, code, lr.Ticket)
  66. if err != nil {
  67. panic(err)
  68. }
  69. app.
  70. SetRoot(app.MainFlex, true).
  71. SetFocus(app.GuildsList)
  72. err = app.Connect(lr.Token)
  73. if err != nil {
  74. panic(err)
  75. }
  76. go keyring.Set(service, "token", lr.Token)
  77. }, true)
  78. app.SetRoot(app.LoginForm, true)
  79. }
  80. }
  81. type loginResponse struct {
  82. MFA bool `json:"mfa"`
  83. SMS bool `json:"sms"`
  84. Ticket string `json:"ticket"`
  85. Token string `json:"token"`
  86. }
  87. func login(s *discordgo.Session, email string, password string) (*loginResponse, error) {
  88. data := struct {
  89. Email string `json:"email"`
  90. Password string `json:"password"`
  91. }{email, password}
  92. resp, err := s.RequestWithBucketID(
  93. "POST",
  94. discordgo.EndpointLogin,
  95. data,
  96. discordgo.EndpointLogin,
  97. )
  98. if err != nil {
  99. return nil, err
  100. }
  101. var lr loginResponse
  102. err = json.Unmarshal(resp, &lr)
  103. if err != nil {
  104. return nil, err
  105. }
  106. return &lr, nil
  107. }
  108. func totp(s *discordgo.Session, code string, ticket string) (*loginResponse, error) {
  109. data := struct {
  110. Code string `json:"code"`
  111. Ticket string `json:"ticket"`
  112. }{code, ticket}
  113. e := discordgo.EndpointAuth + "mfa/totp"
  114. resp, err := s.RequestWithBucketID("POST", e, data, e)
  115. if err != nil {
  116. return nil, err
  117. }
  118. var lr loginResponse
  119. err = json.Unmarshal(resp, &lr)
  120. if err != nil {
  121. return nil, err
  122. }
  123. return &lr, nil
  124. }