From bf985e9da90630951655711b0917cdc0a4a30432 Mon Sep 17 00:00:00 2001 From: PiMaDaum Date: Sun, 19 Feb 2023 00:23:16 +0100 Subject: [PATCH] Implementing output to clipboard for resources subcommand --- resource/clipboard.go | 158 ++++++++++++++++++++++++++++++++++++++++++ util/clipboard.go | 27 ++++++++ 2 files changed, 185 insertions(+) create mode 100644 resource/clipboard.go create mode 100644 util/clipboard.go diff --git a/resource/clipboard.go b/resource/clipboard.go new file mode 100644 index 0000000..31a1e9f --- /dev/null +++ b/resource/clipboard.go @@ -0,0 +1,158 @@ +package resource + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "github.com/alessio/shellescape" + "github.com/passbolt/go-passbolt-cli/util" + "github.com/passbolt/go-passbolt/api" + "github.com/passbolt/go-passbolt/helper" + "github.com/pterm/pterm" + "github.com/spf13/cobra" + "golang.design/x/clipboard" + "golang.org/x/exp/slices" +) + +var ResourceToClipboardCommand = &cobra.Command{ + Use: "resource", + Short: "Copies Resorces column entries to the clipboard.", + Aliases: []string{"resources"}, + RunE: ResourceToClipboard, +} + +func init() { + ResourceToClipboardCommand.Flags().StringArrayP("column", "c", []string{"Username", "Password"}, "Columns to return, possible Columns:\nID, FolderParentID, Name, Username, URI, Password, Description, CreatedTimestamp, ModifiedTimestamp") +} + +func ResourceToClipboard(cmd *cobra.Command, args []string) error { + columns, err := cmd.Flags().GetStringArray("column") + if err != nil { + return err + } + if len(columns) == 0 { + return fmt.Errorf("You need to specify atleast one column to return") + } + celFilter, err := cmd.Flags().GetString("filter") + if err != nil { + return err + } + delay, err := cmd.Flags().GetInt("delay") + if err != nil { + return err + } + + ctx := util.GetContext() + + client, err := util.GetClient(ctx) + if err != nil { + return err + } + defer client.Logout(context.TODO()) + cmd.SilenceUsage = true + + resources, err := client.GetResources(ctx, &api.GetResourcesOptions{}) + if err != nil { + return fmt.Errorf("Listing Resource: %w", err) + } + + resources, err = filterResources(&resources, celFilter, ctx, client) + if err != nil { + return err + } + + singleResource, err := choseResourceEntry(&resources) + if err != nil { + return err + } + if singleResource == nil { + return nil + } + + err = clipboard.Init() + if err != nil { + return err + } + util.SetDelay(delay) + + var password string + var description string + if slices.Contains(columns, "Password") || + slices.Contains(columns, "password") || + slices.Contains(columns, "description") || + slices.Contains(columns, "Description") { + _, _, _, _, password, description, err = helper.GetResource(ctx, client, singleResource.ID) + if err != nil { + return fmt.Errorf("Get Resource %w", err) + } + } + + for _, c := range columns { + switch strings.ToLower(c) { + case "id": + util.CopyValueToClipboard(c, singleResource.ID) + case "folderparentid": + util.CopyValueToClipboard(c, singleResource.FolderParentID) + case "name": + util.CopyValueToClipboard(c, shellescape.StripUnsafe(singleResource.Name)) + case "username": + util.CopyValueToClipboard(c, shellescape.StripUnsafe(singleResource.Username)) + case "uri": + util.CopyValueToClipboard(c, shellescape.StripUnsafe(singleResource.URI)) + case "password": + util.CopyValueToClipboard(c, shellescape.StripUnsafe(password)) + case "description": + util.CopyValueToClipboard(c, shellescape.StripUnsafe(description)) + case "createdtimestamp": + util.CopyValueToClipboard(c, singleResource.Created.Format(time.RFC3339)) + case "modifiedtimestamp": + util.CopyValueToClipboard(c, singleResource.Modified.Format(time.RFC3339)) + default: + cmd.SilenceUsage = false + return fmt.Errorf("Unknown Column: %v", c) + } + } + return nil +} + +// If more than one resource are selected, print an table an ask for selection of entry +func choseResourceEntry(resources *[]api.Resource) (*api.Resource, error) { + if len(*resources) == 0 { + return nil, fmt.Errorf("No resources to select!") + } + + if len(*resources) == 1 { + return &(*resources)[0], nil + } + + data := pterm.TableData{[]string{"Index", "Name", "Username", "URI"}} + for i, resource := range *resources { + index := i + 1 + data = append(data, []string{strconv.Itoa(index), resource.Name, resource.Username, resource.URI}) + } + + var selectedResource *api.Resource + for selectedResource == nil { + pterm.DefaultTable.WithHasHeader().WithData(data).Render() + fmt.Print("Please chose an index of Resource (c to abbort): ") + var cliInput string + fmt.Scanln(&cliInput) + if cliInput == "c" { + return nil, nil + } + + selectedIndex, err := strconv.Atoi(cliInput) + if err != nil || selectedIndex <= 0 || selectedIndex > len(*resources) { + fmt.Printf("Input %s is not a valid index!\n", cliInput) + fmt.Println() + continue + } + + selectedResource = &(*resources)[selectedIndex-1] + } + + return selectedResource, nil +} diff --git a/util/clipboard.go b/util/clipboard.go new file mode 100644 index 0000000..0685d59 --- /dev/null +++ b/util/clipboard.go @@ -0,0 +1,27 @@ +package util + +import ( + "fmt" + "time" + + "golang.design/x/clipboard" +) + +var delaySeconds int = 5 + +// SetDelay Set the delay between entries +func SetDelay(delay int) { + delaySeconds = delay +} + +/* +CopyValueToClipboard Copy the given value to clipboard and sleeps for seconds defined with SetDelay (default: 5 seconds). + +After the delay the clipboard will be emptied +*/ +func CopyValueToClipboard(entryName string, value string) { + clipboard.Write(clipboard.FmtText, []byte(value)) + fmt.Printf("Copying %s to clipboard...\n", entryName) + time.Sleep(time.Duration(delaySeconds) * time.Second) + clipboard.Write(clipboard.FmtText, []byte{}) +}