lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 9a32ec335a1d9932469be2cbb6d6e114c881d464
parent c9f3e5560d737fc2159de8adac6dd843313b4790
Author: Sean Enck <sean@ttypty.com>
Date:   Sat, 16 Jul 2022 11:43:37 -0400

cleaning up clipboard

Diffstat:
Mcmd/lb/main.go | 9+++------
Minternal/clip/clipboard.go | 60++++++++++++++++++++++++++++++++++++++++++++++--------------
Minternal/clip/clipboard_test.go | 46+++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/cmd/lb/main.go b/cmd/lb/main.go @@ -251,15 +251,12 @@ func main() { if err != nil { misc.Die("unable to get paste command", err) } - var args []string - if len(clipboard.Paste) > 1 { - args = clipboard.Paste[1:] - } + pCmd, pArgs := clipboard.Args(false) val = strings.TrimSpace(val) - for idx < clip.MaxTime { + for idx < clipboard.MaxTime { idx++ time.Sleep(1 * time.Second) - out, err := exec.Command(clipboard.Paste[0], args...).Output() + out, err := exec.Command(pCmd, pArgs...).Output() if err != nil { continue } diff --git a/internal/clip/clipboard.go b/internal/clip/clipboard.go @@ -6,14 +6,14 @@ import ( "os" "os/exec" "path/filepath" + "strconv" "strings" "github.com/enckse/lockbox/internal/misc" ) const ( - // MaxTime is the max time to let something stay in the clipboard. - MaxTime = 45 + maxTime = 45 pbClipMode = "pb" waylandClipMode = "wayland" xClipMode = "x11" @@ -23,8 +23,9 @@ const ( type ( // Commands represent system clipboard operations. Commands struct { - Copy []string - Paste []string + copying []string + pasting []string + MaxTime int } ) @@ -58,33 +59,64 @@ func NewCommands() (Commands, error) { return Commands{}, errors.New("unable to detect clipboard mode") } } + max := maxTime + useMax := os.Getenv("LOCKBOX_CLIPMAX") + if useMax != "" { + i, err := strconv.Atoi(useMax) + if err != nil { + return Commands{}, err + } + if i < 1 { + return Commands{}, errors.New("clipboard max time must be greater than 0") + } + max = i + } + var copying []string + var pasting []string switch env { case pbClipMode: - return Commands{Copy: []string{"pbcopy"}, Paste: []string{"pbpaste"}}, nil + copying = []string{"pbcopy"} + pasting = []string{"pbpaste"} case xClipMode: - return Commands{Copy: []string{"xclip"}, Paste: []string{"xclip", "-o"}}, nil + copying = []string{"xclip"} + pasting = []string{"xclip", "-o"} case waylandClipMode: - return Commands{Copy: []string{"wl-copy"}, Paste: []string{"wl-paste"}}, nil + copying = []string{"wl-copy"} + pasting = []string{"wl-paste"} case wslMode: - return Commands{Copy: []string{"clip.exe"}, Paste: []string{"powershell.exe", "-command", "Get-Clipboard"}}, nil + copying = []string{"clip.exe"} + pasting = []string{"powershell.exe", "-command", "Get-Clipboard"} default: return Commands{}, errors.New("clipboard is unavailable") } + return Commands{copying: copying, pasting: pasting, MaxTime: max}, nil } // CopyTo will copy to clipboard, if non-empty will clear later. func (c Commands) CopyTo(value, executable string) { - var args []string - if len(c.Copy) > 1 { - args = c.Copy[1:] - } - pipeTo(c.Copy[0], value, true, args...) + cmd, args := c.Args(true) + pipeTo(cmd, value, true, args...) if value != "" { - fmt.Printf("clipboard will clear in %d seconds\n", MaxTime) + fmt.Printf("clipboard will clear in %d seconds\n", c.MaxTime) pipeTo(filepath.Join(filepath.Dir(executable), "lb"), value, false, "clear") } } +// Args returns clipboard args for execution. +func (c Commands) Args(copying bool) (string, []string) { + var using []string + if copying { + using = c.copying + } else { + using = c.pasting + } + var args []string + if len(using) > 1 { + args = using[1:] + } + return using[0], args +} + func pipeTo(command, value string, wait bool, args ...string) { cmd := exec.Command(command, args...) stdin, err := cmd.StdinPipe() diff --git a/internal/clip/clipboard_test.go b/internal/clip/clipboard_test.go @@ -6,6 +6,7 @@ import ( ) func TestNoClipboard(t *testing.T) { + os.Setenv("LOCKBOX_CLIPMAX", "") os.Setenv("LOCKBOX_CLIPMODE", "off") _, err := NewCommands() if err == nil || err.Error() != "clipboard is unavailable" { @@ -13,15 +14,58 @@ func TestNoClipboard(t *testing.T) { } } +func TestMaxTime(t *testing.T) { + os.Setenv("LOCKBOX_CLIPMODE", pbClipMode) + os.Setenv("LOCKBOX_CLIPMAX", "") + c, err := NewCommands() + if err != nil { + t.Errorf("invalid clipboard: %v", err) + } + if c.MaxTime != 45 { + t.Error("invalid default") + } + os.Setenv("LOCKBOX_CLIPMAX", "1") + c, err = NewCommands() + if err != nil { + t.Errorf("invalid clipboard: %v", err) + } + if c.MaxTime != 1 { + t.Error("invalid default") + } + os.Setenv("LOCKBOX_CLIPMAX", "-1") + _, err = NewCommands() + if err == nil || err.Error() != "clipboard max time must be greater than 0" { + t.Errorf("invalid max time error: %v", err) + } + os.Setenv("LOCKBOX_CLIPMAX", "$&(+") + _, err = NewCommands() + if err == nil || err.Error() != "strconv.Atoi: parsing \"$&(+\": invalid syntax" { + t.Errorf("invalid max time error: %v", err) + } +} + func TestClipboardInstances(t *testing.T) { + os.Setenv("LOCKBOX_CLIPMAX", "") for _, item := range []string{pbClipMode, xClipMode, waylandClipMode, wslMode} { os.Setenv("LOCKBOX_CLIPMODE", item) c, err := NewCommands() if err != nil { t.Errorf("invalid clipboard: %v", err) } - if len(c.Copy) == 0 || len(c.Paste) == 0 { + if len(c.copying) == 0 || len(c.pasting) == 0 { t.Error("invalid command retrieved") } } } + +func TestArgs(t *testing.T) { + c := Commands{copying: []string{"cp"}, pasting: []string{"paste", "with", "args"}} + cmd, args := c.Args(true) + if cmd != "cp" || len(args) != 0 { + t.Error("invalid parse") + } + cmd, args = c.Args(false) + if cmd != "paste" || len(args) != 2 || args[0] != "with" || args[1] != "args" { + t.Error("invalid parse") + } +}