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>
This commit is contained in:
210
cmd/accounts.go
Normal file
210
cmd/accounts.go
Normal file
@@ -0,0 +1,210 @@
|
||||
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
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user