diff --git a/internal/creds/creds.go b/internal/creds/creds.go index ed2eec3..2d9c24c 100644 --- a/internal/creds/creds.go +++ b/internal/creds/creds.go @@ -11,25 +11,30 @@ import ( const serviceName = "f1viewer" -func LoadCredentials() (string, string, error) { +func LoadCredentials() (string, string, string, error) { ring, err := openRing() if err != nil { - return "", "", fmt.Errorf("failed to open secret store: %w", err) + return "", "", "", fmt.Errorf("failed to open secret store: %w", err) } username, err := ring.Get("username") if err != nil { - return "", "", fmt.Errorf("Could not get username: %w", err) + return "", "", "", fmt.Errorf("Could not get username: %w", err) } password, err := ring.Get("password") if err != nil { - return "", "", fmt.Errorf("Could not get password: %w", err) + return "", "", "", fmt.Errorf("Could not get password: %w", err) } - return string(username.Data), string(password.Data), nil + + token, err := ring.Get("token") + if err != nil { + return string(username.Data), string(password.Data), "", nil + } + return string(username.Data), string(password.Data), string(token.Data), nil } -func SaveCredentials(username, password string) error { +func SaveCredentials(username, password, token string) error { ring, err := openRing() if err != nil { return fmt.Errorf("failed to open secret store: %w", err) @@ -52,6 +57,15 @@ func SaveCredentials(username, password string) error { if err != nil { return fmt.Errorf("could not save password %w", err) } + + err = ring.Set(keyring.Item{ + Description: "F1TV subscription token", + Key: "token", + Data: []byte(token), + }) + if err != nil { + return fmt.Errorf("could not save token %w", err) + } return nil } diff --git a/internal/creds/creds_darwin.go b/internal/creds/creds_darwin.go index 00fb1f8..c23c72c 100644 --- a/internal/creds/creds_darwin.go +++ b/internal/creds/creds_darwin.go @@ -13,21 +13,26 @@ const ( serviceName = "f1viewer" userKey = "username" passKey = "password" + tokenKey = "token" ) -func LoadCredentials() (string, string, error) { +func LoadCredentials() (string, string, string, error) { username, err := keyring.Get(serviceName, userKey) if err != nil { - return "", "", fmt.Errorf("failed to get username: %w", err) + return "", "", "", fmt.Errorf("failed to get username: %w", err) } password, err := keyring.Get(serviceName, passKey) if err != nil { - return "", "", fmt.Errorf("failed to get password: %w", err) + return "", "", "", fmt.Errorf("failed to get password: %w", err) } - return username, password, nil + token, err := keyring.Get(serviceName, tokenKey) + if err != nil { + return username, password, "", nil + } + return username, password, token, nil } -func SaveCredentials(username, password string) error { +func SaveCredentials(username, password, token string) error { err := keyring.Set(serviceName, userKey, username) if err != nil { return fmt.Errorf("failed to save username: %w", err) @@ -36,6 +41,10 @@ func SaveCredentials(username, password string) error { if err != nil { return fmt.Errorf("failed to save password: %w", err) } + keyring.Set(serviceName, tokenKey, token) + if err != nil { + return fmt.Errorf("failed to save token: %w", err) + } return nil } @@ -46,5 +55,8 @@ func RemoveCredentials() error { if err := keyring.Delete(serviceName, passKey); err != nil { return fmt.Errorf("failed to delete password: %w", err) } + if err := keyring.Delete(serviceName, tokenKey); err != nil { + return fmt.Errorf("failed to delete token: %w", err) + } return nil } diff --git a/internal/ui/state.go b/internal/ui/state.go index 11c002e..0a032ea 100644 --- a/internal/ui/state.go +++ b/internal/ui/state.go @@ -180,33 +180,43 @@ func (s *UIState) logout() { } func (s *UIState) loginWithStoredCredentials() error { - username, password, err := creds.LoadCredentials() + username, password, token, err := creds.LoadCredentials() if err != nil { return err } - return s.login(username, password) + return s.login(username, password, token) } -func (s *UIState) login(username, pw string) error { - err := s.v2.Authenticate(username, pw, s.logger) +func (s *UIState) login(username, pw, token string) error { + var err error + if token != "" { + err = s.v2.SetToken(token) + if err == nil { + s.logger.Info("token is valid") + return nil + } + } + err = s.v2.Authenticate(username, pw, s.logger) return err } func (s *UIState) initUIWithForm() { - username, _, _ := creds.LoadCredentials() + username, _, _, _ := creds.LoadCredentials() pw := "" + token := "" form := tview.NewForm(). AddInputField("email", username, 30, nil, func(text string) { username = text }). AddPasswordField("password", "", 30, '*', func(text string) { pw = text }). + AddInputField("token", "", 30, nil, func(text string) { token = text }). AddButton("test", func() { - err := s.login(username, pw) + err := s.login(username, pw, token) if err == nil { s.logger.Info("credentials accepted") } else { s.logger.Error(err) } }). - AddButton("save", func() { s.closeForm(username, pw) }) + AddButton("save", func() { s.closeForm(username, pw, token) }) formTreeFlex := tview.NewFlex() if !s.cfg.HorizontalLayout { @@ -247,11 +257,11 @@ func (s *UIState) initUI() { s.app.SetRoot(flex, true) } -func (s *UIState) closeForm(username, pw string) { - if err := s.login(username, pw); err != nil { +func (s *UIState) closeForm(username, pw, token string) { + if err := s.login(username, pw, token); err != nil { s.logger.Error(err) } - if err := creds.SaveCredentials(username, pw); err != nil { + if err := creds.SaveCredentials(username, pw, token); err != nil { s.logger.Error(err) } s.initUI() diff --git a/pkg/f1tv/v2/api.go b/pkg/f1tv/v2/api.go index c93edc6..0bfd03f 100644 --- a/pkg/f1tv/v2/api.go +++ b/pkg/f1tv/v2/api.go @@ -84,6 +84,15 @@ func NewF1TV(version string) *F1TV { } } +func (f *F1TV) SetToken(token string) error { + f.SubscriptionToken = token + _, err := f.GetPlaybackURL(BIG_SCREEN_HLS, 1000003967, nil) + if err != nil { + return fmt.Errorf("invalid token: %w", err) + } + return nil +} + func (f *F1TV) Authenticate(username, password string, logger util.Logger) error { type request struct { Login string `json:"Login"`