@@ -22,15 +22,20 @@ import (
const tokenValidationTimeout = 10 * time.Second
+// handleKeyringError prints keyring error messages and returns a wrapped error.
+func handleKeyringError(out io.Writer, err error) error {
+ fmt.Fprintln(out, ui.Error.Render("Failed to access system keyring: "+err.Error()))
+ fmt.Fprintln(out, "Please resolve the keyring issue and try again.")
+
+ return fmt.Errorf("keyring access failed: %w", err)
+}
+
func configureAccessToken(cmd *cobra.Command) error {
out := cmd.OutOrStdout()
hasToken, keyringErr := client.HasKeyringToken()
if keyringErr != nil {
- fmt.Fprintln(out, ui.Error.Render("Failed to access system keyring: "+keyringErr.Error()))
- fmt.Fprintln(out, "Please resolve the keyring issue and try again.")
-
- return fmt.Errorf("keyring access failed: %w", keyringErr)
+ return handleKeyringError(out, keyringErr)
}
if hasToken {
@@ -47,6 +52,55 @@ func configureAccessToken(cmd *cobra.Command) error {
return promptForToken(out)
}
+// ensureAccessToken checks for a token in the keyring and prompts for one if
+// missing or invalid. Used at the start of reconfigure mode so users copying
+// config to a new device are immediately prompted for their token.
+func ensureAccessToken(cmd *cobra.Command) error {
+ out := cmd.OutOrStdout()
+
+ hasToken, keyringErr := client.HasKeyringToken()
+ if keyringErr != nil {
+ return handleKeyringError(out, keyringErr)
+ }
+
+ if !hasToken {
+ fmt.Fprintln(out, ui.Warning.Render("No access token found in system keyring."))
+
+ return promptForToken(out)
+ }
+
+ existingToken, err := client.GetToken()
+ if err != nil {
+ return fmt.Errorf("reading access token from keyring: %w", err)
+ }
+
+ if err := validateWithSpinner(existingToken); err != nil {
+ fmt.Fprintln(out, ui.Warning.Render("Existing access token failed validation: "+err.Error()))
+
+ var replace bool
+
+ confirmErr := huh.NewConfirm().
+ Title("Would you like to provide a new access token?").
+ Affirmative("Yes").
+ Negative("No").
+ Value(&replace).
+ Run()
+ if confirmErr != nil {
+ if errors.Is(confirmErr, huh.ErrUserAborted) {
+ return errQuit
+ }
+
+ return confirmErr
+ }
+
+ if replace {
+ return promptForToken(out)
+ }
+ }
+
+ return nil
+}
+
func handleExistingToken(out io.Writer) (bool, error) {
existingToken, err := client.GetToken()
if err != nil {
@@ -131,6 +131,10 @@ func runReconfigure(cmd *cobra.Command, cfg *config.Config) error {
fmt.Fprintln(cmd.OutOrStdout(), ui.Bold.Render("lune configuration"))
fmt.Fprintln(cmd.OutOrStdout())
+ if err := ensureAccessToken(cmd); err != nil {
+ return err
+ }
+
handlers := map[string]func() error{
"areas": func() error { return manageAreas(cfg) },
"notebooks": func() error { return manageNotebooks(cfg) },