main.go 2.9 KB

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