Add CLI flags for token, config, and log (#245)

This commit is contained in:
ayntgl 2022-10-15 15:13:42 +05:30 • committed by GitHub
parent 4cb58e0edf
commit c9b4e114e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 113 deletions

View file

@ -65,17 +65,17 @@ sudo mv ./discordo /usr/local/bin
1. Run the `discordo` executable with no arguments.
2. A login view will be displayed on first start-up. You can choose to login using either your email and password or token; the views can be switched using `Ctrl+Space` keybinding.
> If you are logging in using an authentication token, provide the `token` command-line flag to the executable (eg: `--token "OTI2MDU5NTQxNDE2Nzc5ODA2.Yc2KKA.2iZ-5JxgxG-9Ub8GHzBSn-NJjNg"`).
3. Enter your credentials and click on the "Login" button to continue.
2. Enter your email and password and click on the "Login" button to continue.
- If you are logging in with a bot account, prefix the token with `Bot ` (eg: `Bot OTI2MDU5NTQxNDE2Nzc5ODA2.Yc2KKA.2iZ-5JxgxG-9Ub8GHzBSn-NJjNg`).
- Most of the Discord third-party clients store the token in a configuration file unencrypted. Discordo securely stores the token in the default OS-specific keyring.
- Most of the Discord third-party clients store the token in a configuration file unencrypted. Discordo securely stores the token in the default OS-specific keyring.
### Configuration
A default configuration file is created on first start-up at `$HOME/.config/discordo/config.yml` on Unix, `$HOME/Library/Application Support/discordo/config.yml` on Darwin, and `%AppData%/discordo/config.yml` on Windows.
A default configuration file is created on first start-up at `$HOME/.config/discordo.yml` on Unix, `$HOME/Library/Application Support/discordo.yml` on Darwin, and `%AppData%/discordo.yml` on Windows. The configuration file path can be customized using the `config` command-line flag (eg: `--config ~/myconfigs/discordo.yml`).
Similarly, a log file is created on first start-up at `$HOME/.cache/discordo.log` on Unix, `$HOME/Library/Caches/discordo.log` on Darwin, and `%LocalAppData%/discordo.yml` on Windows. The log file path can be customized using the `log` command-line flag.
## Disclaimer

View file

@ -80,9 +80,9 @@ func New() *Config {
}
}
func (cfg *Config) Load() error {
func (cfg *Config) Load(path string) error {
// Open the existing configuration file with read-only flag.
f, err := os.OpenFile(cfg.configPath(), os.O_CREATE|os.O_RDWR, os.ModePerm)
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, os.ModePerm)
if err != nil {
return err
}
@ -101,10 +101,14 @@ func (cfg *Config) Load() error {
return yaml.NewDecoder(f).Decode(&cfg)
}
func (cfg *Config) configPath() string {
// DefaultConfigPath returns the default configuration file path.
func DefaultConfigPath() string {
path, _ := os.UserConfigDir()
path = filepath.Join(path, Name)
// Create the configuration directory if it does not exist already.
_ = os.MkdirAll(path, os.ModePerm)
return filepath.Join(path, "config.yml")
return filepath.Join(path, Name+".yml")
}
// DefaultLogPath returns the default log file path.
func DefaultLogPath() string {
path, _ := os.UserCacheDir()
return filepath.Join(path, Name+".log")
}

59
main.go
View file

@ -1,10 +1,10 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"github.com/ayntgl/discordo/config"
@ -15,27 +15,13 @@ import (
"github.com/zalando/go-keyring"
)
var (
flagToken string
flagConfig string
flagLog string
)
func init() {
path, err := os.UserCacheDir()
if err != nil {
log.Fatal(err)
}
path = filepath.Join(path, config.Name)
err = os.MkdirAll(path, os.ModePerm)
if err != nil {
log.Fatal(err)
}
path = filepath.Join(path, "out.log")
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, os.ModePerm)
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
log.SetFlags(log.LstdFlags | log.Lshortfile)
tview.Borders.TopLeftFocus = tview.Borders.TopLeft
tview.Borders.TopRightFocus = tview.Borders.TopRight
tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft
@ -55,18 +41,41 @@ func init() {
Browser: config.Name,
Device: "",
}
flag.StringVar(&flagToken, "token", "", "The authentication token.")
flag.StringVar(&flagConfig, "config", config.DefaultConfigPath(), "The path to the configuration file.")
flag.StringVar(&flagLog, "log", config.DefaultLogPath(), "The path to the log file.")
}
func main() {
flag.Parse()
if flagLog != "" {
// Set the standard logger output to the provided log file.
f, err := os.OpenFile(flagLog, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
log.SetOutput(f)
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
cfg := config.New()
err := cfg.Load()
err := cfg.Load(flagConfig)
if err != nil {
log.Fatal(err)
}
token, err := keyring.Get(config.Name, "token")
if err != nil {
log.Println(err)
var token string
if flagToken != "" {
token = flagToken
go keyring.Set(config.Name, "token", token)
} else {
token, err = keyring.Get(config.Name, "token")
if err != nil {
log.Println(err)
}
}
c := ui.NewCore(cfg)

View file

@ -6,56 +6,17 @@ import (
"github.com/ayntgl/discordo/config"
"github.com/diamondburned/arikawa/v3/api"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/zalando/go-keyring"
)
const (
emailViewPageName = "email"
tokenViewPageName = "token"
)
func NewLoginView(c *Core) *tview.Pages {
v := tview.NewPages()
v.AddPage(emailViewPageName, newEmailView(c), true, true)
v.AddPage(tokenViewPageName, newTokenView(c), true, true)
// Since the recommended method to login is using the email and password, it is displayed on the screen first.
v.SwitchToPage(emailViewPageName)
v.SetTitle("Login")
v.SetTitleAlign(tview.AlignLeft)
v.SetBorder(true)
v.SetBorderPadding(0, 0, 1, 1)
v.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyCtrlSpace {
name, _ := v.GetFrontPage()
switch name {
case emailViewPageName:
name = tokenViewPageName
case tokenViewPageName:
name = emailViewPageName
}
v.SwitchToPage(name)
return nil
}
return event
})
return v
}
type EmailView struct {
type LoginView struct {
*tview.Form
core *Core
}
func newEmailView(c *Core) *EmailView {
v := &EmailView{
func NewLoginView(c *Core) *LoginView {
v := &LoginView{
Form: tview.NewForm(),
core: c,
}
@ -65,10 +26,15 @@ func newEmailView(c *Core) *EmailView {
v.AddPasswordField("Code (optional)", "", 0, 0, nil)
v.AddButton("Login", v.onLoginButtonSelected)
v.SetTitle("Login")
v.SetTitleAlign(tview.AlignLeft)
v.SetBorder(true)
v.SetBorderPadding(1, 1, 1, 1)
return v
}
func (v *EmailView) onLoginButtonSelected() {
func (v *LoginView) onLoginButtonSelected() {
email := v.GetFormItem(0).(*tview.InputField).GetText()
password := v.GetFormItem(1).(*tview.InputField).GetText()
if email == "" || password == "" {
@ -105,35 +71,3 @@ func (v *EmailView) onLoginButtonSelected() {
v.core.Draw()
go keyring.Set(config.Name, "token", l.Token)
}
type TokenView struct {
*tview.Form
core *Core
}
func newTokenView(c *Core) *TokenView {
v := &TokenView{
Form: tview.NewForm(),
core: c,
}
v.AddPasswordField("Token", "", 0, 0, nil)
v.AddButton("Login", v.onLoginButtonSelected)
return v
}
func (v *TokenView) onLoginButtonSelected() {
token := v.GetFormItem(0).(*tview.InputField).GetText()
if token == "" {
return
}
err := v.core.Run(token)
if err != nil {
log.Fatal(err)
}
v.core.Draw()
go keyring.Set(config.Name, "token", token)
}