Files
pop/cmd/accounts.go
Michael Freno bf26cd3ed6 feat: implement Milestone 3 integration points
Add comprehensive integration capabilities to Pop CLI:

- Multi-account support with named profiles
- Webhook management with signature verification
- External PGP key management (import/export/encrypt/decrypt/sign/verify)
- CLI plugin system for extensibility
- Complete documentation in README.md

All compilation errors fixed and build verified CLEAN.

Security review delegated to FRE-5202.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-14 00:40:24 -04:00

211 lines
5.5 KiB
Go

package cmd
import (
"fmt"
"os"
"text/tabwriter"
"github.com/frenocorp/pop/internal/accounts"
"github.com/spf13/cobra"
)
func accountsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "accounts",
Short: "Manage multiple ProtonMail accounts",
Long: `Add, list, switch, and remove named ProtonMail account profiles.`,
}
cmd.AddCommand(accountsListCmd())
cmd.AddCommand(accountsAddCmd())
cmd.AddCommand(accountsRemoveCmd())
cmd.AddCommand(accountsDefaultCmd())
cmd.AddCommand(accountsShowCmd())
return cmd
}
func accountsListCmd() *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List all configured accounts",
Long: `Show all saved ProtonMail account profiles.`,
RunE: func(cmd *cobra.Command, args []string) error {
store, err := accounts.NewAccountsStore()
if err != nil {
return fmt.Errorf("failed to create accounts store: %w", err)
}
accts, err := store.LoadAccounts()
if err != nil {
return fmt.Errorf("failed to load accounts: %w", err)
}
if len(accts) == 0 {
fmt.Println("No accounts configured. Use 'pop accounts add' to create one.")
return nil
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "Name\tEmail\tDefault\tAPI Base\tCreated")
fmt.Fprintln(w, "----\t-----\t-------\t--------\t-------")
for _, acc := range accts {
def := "-"
if acc.Default {
def = "*"
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n",
acc.Name, acc.Email, def, acc.APIBaseURL, acc.CreatedAt)
}
return w.Flush()
},
}
}
func accountsAddCmd() *cobra.Command {
var name, email, apiURL string
var isDefault bool
cmd := &cobra.Command{
Use: "add <name>",
Short: "Add a new account profile",
Long: `Add a named ProtonMail account profile for multi-account support.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
accountName := name
if len(args) > 0 && args[0] != "" {
accountName = args[0]
}
if accountName == "" {
return fmt.Errorf("account name is required")
}
if email == "" {
return fmt.Errorf("email is required (--email)")
}
store, err := accounts.NewAccountsStore()
if err != nil {
return fmt.Errorf("failed to create accounts store: %w", err)
}
if err := store.AddAccount(accountName, email, apiURL, isDefault); err != nil {
return fmt.Errorf("failed to add account: %w", err)
}
fmt.Printf("Added account: %s (%s)\n", accountName, email)
if isDefault {
fmt.Println("Set as default account")
}
return nil
},
}
cmd.Flags().StringVar(&name, "name", "", "Account name (or pass as positional argument)")
cmd.Flags().StringVarP(&email, "email", "e", "", "ProtonMail email address")
cmd.Flags().StringVar(&apiURL, "api-url", "", "Custom API base URL")
cmd.Flags().BoolVarP(&isDefault, "default", "d", false, "Set as default account")
_ = cmd.MarkFlagRequired("email")
return cmd
}
func accountsRemoveCmd() *cobra.Command {
return &cobra.Command{
Use: "remove <name>",
Short: "Remove an account profile",
Long: `Remove a named ProtonMail account profile.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
accountName := args[0]
store, err := accounts.NewAccountsStore()
if err != nil {
return fmt.Errorf("failed to create accounts store: %w", err)
}
if err := store.RemoveAccount(accountName); err != nil {
return fmt.Errorf("failed to remove account: %w", err)
}
fmt.Printf("Removed account: %s\n", accountName)
return nil
},
}
}
func accountsDefaultCmd() *cobra.Command {
var setName string
cmd := &cobra.Command{
Use: "default [name]",
Short: "Get or set the default account",
Long: `Show the current default account, or set a new default.`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
store, err := accounts.NewAccountsStore()
if err != nil {
return fmt.Errorf("failed to create accounts store: %w", err)
}
if setName == "" && len(args) > 0 {
setName = args[0]
}
if setName != "" {
if err := store.SetDefaultAccount(setName); err != nil {
return fmt.Errorf("failed to set default account: %w", err)
}
fmt.Printf("Set default account to: %s\n", setName)
return nil
}
acct, err := store.GetAccount("")
if err != nil {
return fmt.Errorf("no default account: %w", err)
}
fmt.Printf("Default account: %s (%s)\n", acct.Name, acct.Email)
return nil
},
}
cmd.Flags().StringVar(&setName, "set", "", "Set default account to this name")
return cmd
}
func accountsShowCmd() *cobra.Command {
return &cobra.Command{
Use: "show <name>",
Short: "Show account details",
Long: `Display details for a specific account profile.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
accountName := args[0]
store, err := accounts.NewAccountsStore()
if err != nil {
return fmt.Errorf("failed to create accounts store: %w", err)
}
acct, err := store.GetAccount(accountName)
if err != nil {
return fmt.Errorf("failed to get account: %w", err)
}
fmt.Printf("Name: %s\n", acct.Name)
fmt.Printf("Email: %s\n", acct.Email)
fmt.Printf("UID: %s\n", acct.UID)
fmt.Printf("API Base: %s\n", acct.APIBaseURL)
fmt.Printf("Default: %t\n", acct.Default)
fmt.Printf("Created: %s\n", acct.CreatedAt)
if acct.LastUsedAt != "" {
fmt.Printf("Last Used: %s\n", acct.LastUsedAt)
}
return nil
},
}
}