package main import ( "github.com/ayntgl/discordgo" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" "github.com/zalando/go-keyring" ) const service = "discordo" var ( app *tview.Application loginForm *tview.Form channelsTree *tview.TreeView messagesView *tview.TextView messageInputField *tview.InputField mainFlex *tview.Flex conf *config session *discordgo.Session ) func main() { conf = loadConfig() tview.Borders = conf.Borders tview.Styles.PrimitiveBackgroundColor = tcell.GetColor(conf.Theme.Background.Primitive) tview.Styles.ContrastBackgroundColor = tcell.GetColor(conf.Theme.Background.Contrast) tview.Styles.MoreContrastBackgroundColor = tcell.GetColor(conf.Theme.Background.MoreContrast) tview.Styles.BorderColor = tcell.GetColor(conf.Theme.Border) tview.Styles.TitleColor = tcell.GetColor(conf.Theme.Title) tview.Styles.GraphicsColor = tcell.GetColor(conf.Theme.Graphics) tview.Styles.PrimaryTextColor = tcell.GetColor(conf.Theme.Text.Primary) tview.Styles.SecondaryTextColor = tcell.GetColor(conf.Theme.Text.Secondary) tview.Styles.TertiaryTextColor = tcell.GetColor(conf.Theme.Text.Tertiary) tview.Styles.InverseTextColor = tcell.GetColor(conf.Theme.Text.Inverse) tview.Styles.ContrastSecondaryTextColor = tcell.GetColor(conf.Theme.Text.ContrastSecondary) app = newApp() channelsTree = newChannelsTree() messagesView = newMessagesView() messageInputField = newMessageInputField() rightFlex := tview.NewFlex(). SetDirection(tview.FlexRow). AddItem(messagesView, 0, 1, false). AddItem(messageInputField, 3, 1, false) mainFlex = tview.NewFlex(). AddItem(channelsTree, 0, 1, false). AddItem(rightFlex, 0, 4, false) token := conf.Token if t, _ := keyring.Get(service, "token"); t != "" { token = t } if token != "" { app. SetRoot(mainFlex, true). SetFocus(channelsTree) session = newSession() session.Token = token session.Identify.Token = token if err := session.Open(); err != nil { panic(err) } } else { loginForm = newLoginForm(onLoginFormLoginButtonSelected, false) app.SetRoot(loginForm, true) } if err := app.Run(); err != nil { panic(err) } } func onLoginFormLoginButtonSelected() { email := loginForm.GetFormItem(0).(*tview.InputField).GetText() password := loginForm.GetFormItem(1).(*tview.InputField).GetText() if email == "" || password == "" { return } session = newSession() // Login using the email and password lr, err := login(email, password) if err != nil { panic(err) } if lr.Token != "" && !lr.MFA { app. SetRoot(mainFlex, true). SetFocus(channelsTree) session.Token = lr.Token session.Identify.Token = lr.Token if err = session.Open(); err != nil { panic(err) } go keyring.Set(service, "token", lr.Token) } else if lr.MFA { // The account has MFA enabled, reattempt login with code and ticket. loginForm = newLoginForm(func() { code := loginForm.GetFormItem(0).(*tview.InputField).GetText() if code == "" { return } lr, err = totp(code, lr.Ticket) if err != nil { panic(err) } app. SetRoot(mainFlex, true). SetFocus(channelsTree) session.Token = lr.Token session.Identify.Token = lr.Token if err = session.Open(); err != nil { panic(err) } go keyring.Set(service, "token", lr.Token) }, true) app.SetRoot(loginForm, true) } }