lockbox

password manager
Log | Files | Refs | README | LICENSE

commit afcb399d0e3d33abefd2c11b251522e8adb19e03
parent 9966e450120bb63fb87a07e784abb62c742b0228
Author: Sean Enck <sean@ttypty.com>
Date:   Sat, 16 Jul 2022 09:59:49 -0400

moved clipboard

Diffstat:
MMakefile | 3++-
Mcmd/lb-totp/main.go | 5+++--
Mcmd/lb/main.go | 9+++++----
Dinternal/clip.go | 108-------------------------------------------------------------------------------
Dinternal/clip_test.go | 27---------------------------
Ainternal/clipboard/clip.go | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainternal/clipboard/clip_test.go | 27+++++++++++++++++++++++++++
7 files changed, 147 insertions(+), 142 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,12 +5,13 @@ TARGETS := $(BUILD)lb $(BUILD)lb-rw $(BUILD)lb-rekey $(BUILD)lb-textconv $(BUILD LIBEXEC := $(DESTDIR)libexec/lockbox/ MAIN := $(DESTDIR)bin/lb TESTDIR := $(shell find internal -type f -name "*test.go" -exec dirname {} \; | sort -u) +SOURCE := $(shell find . -type f -name "*.go") .PHONY: $(TESTDIR) all: $(TARGETS) -$(TARGETS): cmd/**/*.go internal/*.go internal/**/*.go go.* +$(TARGETS): $(SOURCE) go build -ldflags '-X main.version=$(VERSION) -X main.libExec=$(LIBEXEC) -X main.mainExe=$(MAIN)' -trimpath -buildmode=pie -mod=readonly -modcacherw -o $@ cmd/$(shell basename $@)/main.go $(TESTDIR): $(TARGETS) diff --git a/cmd/lb-totp/main.go b/cmd/lb-totp/main.go @@ -13,6 +13,7 @@ import ( "github.com/enckse/lockbox/internal" "github.com/enckse/lockbox/internal/cli" + "github.com/enckse/lockbox/internal/clipboard" otp "github.com/pquerna/otp/totp" ) @@ -118,9 +119,9 @@ func display(token string, args cli.Arguments) error { clear() } } - clip := internal.ClipboardCommands{} + clip := clipboard.Commands{} if args.Clip { - clip, err = internal.NewClipboardCommands() + clip, err = clipboard.NewCommands() if err != nil { internal.Die("invalid clipboard", err) } diff --git a/cmd/lb/main.go b/cmd/lb/main.go @@ -13,6 +13,7 @@ import ( "github.com/enckse/lockbox/internal" "github.com/enckse/lockbox/internal/cli" + "github.com/enckse/lockbox/internal/clipboard" ) const ( @@ -187,9 +188,9 @@ func main() { internal.Die("unable to get color for terminal", err) } dumpData := []Dump{} - clip := internal.ClipboardCommands{} + clip := clipboard.Commands{} if !isShow { - clip, err = internal.NewClipboardCommands() + clip, err = clipboard.NewCommands() if err != nil { internal.Die("unable to get clipboard", err) } @@ -256,7 +257,7 @@ func main() { if err != nil { internal.Die("unable to read value to clear", err) } - clip, err := internal.NewClipboardCommands() + clip, err := clipboard.NewCommands() if err != nil { internal.Die("unable to get paste command", err) } @@ -265,7 +266,7 @@ func main() { args = clip.Paste[1:] } val = strings.TrimSpace(val) - for idx < internal.MaxClipTime { + for idx < clipboard.MaxTime { idx++ time.Sleep(1 * time.Second) out, err := exec.Command(clip.Paste[0], args...).Output() diff --git a/internal/clip.go b/internal/clip.go @@ -1,108 +0,0 @@ -package internal - -import ( - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" -) - -const ( - // MaxClipTime is the max time to let something stay in the clipboard. - MaxClipTime = 45 - pbClipMode = "pb" - waylandClipMode = "wayland" - xClipMode = "x11" - wslMode = "wsl" -) - -type ( - // ClipboardCommands represent system clipboard operations. - ClipboardCommands struct { - Copy []string - Paste []string - } -) - -// NewClipboardCommands will retrieve the commands to use for clipboard operations. -func NewClipboardCommands() (ClipboardCommands, error) { - env := strings.TrimSpace(os.Getenv("LOCKBOX_CLIPMODE")) - if env == "" { - b, err := exec.Command("uname", "-a").Output() - if err != nil { - return ClipboardCommands{}, err - } - raw := strings.TrimSpace(string(b)) - parts := strings.Split(raw, " ") - switch parts[0] { - case "Darwin": - env = pbClipMode - case "Linux": - if strings.Contains(raw, "microsoft-standard-WSL2") { - env = wslMode - } else { - if strings.TrimSpace(os.Getenv("WAYLAND_DISPLAY")) == "" { - if strings.TrimSpace(os.Getenv("DISPLAY")) == "" { - return ClipboardCommands{}, errors.New("unable to detect linux clipboard mode") - } - env = xClipMode - } else { - env = waylandClipMode - } - } - default: - return ClipboardCommands{}, errors.New("unable to detect clipboard mode") - } - } - switch env { - case pbClipMode: - return ClipboardCommands{Copy: []string{"pbcopy"}, Paste: []string{"pbpaste"}}, nil - case xClipMode: - return ClipboardCommands{Copy: []string{"xclip"}, Paste: []string{"xclip", "-o"}}, nil - case waylandClipMode: - return ClipboardCommands{Copy: []string{"wl-copy"}, Paste: []string{"wl-paste"}}, nil - case wslMode: - return ClipboardCommands{Copy: []string{"clip.exe"}, Paste: []string{"powershell.exe", "-command", "Get-Clipboard"}}, nil - default: - return ClipboardCommands{}, errors.New("clipboard is unavailable") - } -} - -// CopyToClipboard will copy to clipboard, if non-empty will clear later. -func (c ClipboardCommands) CopyToClipboard(value, executable string) { - var args []string - if len(c.Copy) > 1 { - args = c.Copy[1:] - } - pipeTo(c.Copy[0], value, true, args...) - if value != "" { - fmt.Printf("clipboard will clear in %d seconds\n", MaxClipTime) - pipeTo(filepath.Join(filepath.Dir(executable), "lb"), value, false, "clear") - } -} - -func pipeTo(command, value string, wait bool, args ...string) { - cmd := exec.Command(command, args...) - stdin, err := cmd.StdinPipe() - if err != nil { - Die("unable to get stdin pipe", err) - } - - go func() { - defer stdin.Close() - if _, err := stdin.Write([]byte(value)); err != nil { - fmt.Printf("failed writing to stdin: %v\n", err) - } - }() - var ran error - if wait { - ran = cmd.Run() - } else { - ran = cmd.Start() - } - if ran != nil { - Die("failed to run command", ran) - } -} diff --git a/internal/clip_test.go b/internal/clip_test.go @@ -1,27 +0,0 @@ -package internal - -import ( - "os" - "testing" -) - -func TestNoClipboard(t *testing.T) { - os.Setenv("LOCKBOX_CLIPMODE", "off") - _, err := NewClipboardCommands() - if err == nil || err.Error() != "clipboard is unavailable" { - t.Errorf("invalid error: %v", err) - } -} - -func TestClipboardInstances(t *testing.T) { - for _, item := range []string{pbClipMode, xClipMode, waylandClipMode, wslMode} { - os.Setenv("LOCKBOX_CLIPMODE", item) - c, err := NewClipboardCommands() - if err != nil { - t.Errorf("invalid clipboard: %v", err) - } - if len(c.Copy) == 0 || len(c.Paste) == 0 { - t.Error("invalid command retrieved") - } - } -} diff --git a/internal/clipboard/clip.go b/internal/clipboard/clip.go @@ -0,0 +1,110 @@ +package clipboard + +import ( + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/enckse/lockbox/internal" +) + +const ( + // MaxTime is the max time to let something stay in the clipboard. + MaxTime = 45 + pbClipMode = "pb" + waylandClipMode = "wayland" + xClipMode = "x11" + wslMode = "wsl" +) + +type ( + // Commands represent system clipboard operations. + Commands struct { + Copy []string + Paste []string + } +) + +// NewCommands will retrieve the commands to use for clipboard operations. +func NewCommands() (Commands, error) { + env := strings.TrimSpace(os.Getenv("LOCKBOX_CLIPMODE")) + if env == "" { + b, err := exec.Command("uname", "-a").Output() + if err != nil { + return Commands{}, err + } + raw := strings.TrimSpace(string(b)) + parts := strings.Split(raw, " ") + switch parts[0] { + case "Darwin": + env = pbClipMode + case "Linux": + if strings.Contains(raw, "microsoft-standard-WSL2") { + env = wslMode + } else { + if strings.TrimSpace(os.Getenv("WAYLAND_DISPLAY")) == "" { + if strings.TrimSpace(os.Getenv("DISPLAY")) == "" { + return Commands{}, errors.New("unable to detect linux clipboard mode") + } + env = xClipMode + } else { + env = waylandClipMode + } + } + default: + return Commands{}, errors.New("unable to detect clipboard mode") + } + } + switch env { + case pbClipMode: + return Commands{Copy: []string{"pbcopy"}, Paste: []string{"pbpaste"}}, nil + case xClipMode: + return Commands{Copy: []string{"xclip"}, Paste: []string{"xclip", "-o"}}, nil + case waylandClipMode: + return Commands{Copy: []string{"wl-copy"}, Paste: []string{"wl-paste"}}, nil + case wslMode: + return Commands{Copy: []string{"clip.exe"}, Paste: []string{"powershell.exe", "-command", "Get-Clipboard"}}, nil + default: + return Commands{}, errors.New("clipboard is unavailable") + } +} + +// CopyToClipboard will copy to clipboard, if non-empty will clear later. +func (c Commands) CopyToClipboard(value, executable string) { + var args []string + if len(c.Copy) > 1 { + args = c.Copy[1:] + } + pipeTo(c.Copy[0], value, true, args...) + if value != "" { + fmt.Printf("clipboard will clear in %d seconds\n", MaxTime) + pipeTo(filepath.Join(filepath.Dir(executable), "lb"), value, false, "clear") + } +} + +func pipeTo(command, value string, wait bool, args ...string) { + cmd := exec.Command(command, args...) + stdin, err := cmd.StdinPipe() + if err != nil { + internal.Die("unable to get stdin pipe", err) + } + + go func() { + defer stdin.Close() + if _, err := stdin.Write([]byte(value)); err != nil { + fmt.Printf("failed writing to stdin: %v\n", err) + } + }() + var ran error + if wait { + ran = cmd.Run() + } else { + ran = cmd.Start() + } + if ran != nil { + internal.Die("failed to run command", ran) + } +} diff --git a/internal/clipboard/clip_test.go b/internal/clipboard/clip_test.go @@ -0,0 +1,27 @@ +package clipboard + +import ( + "os" + "testing" +) + +func TestNoClipboard(t *testing.T) { + os.Setenv("LOCKBOX_CLIPMODE", "off") + _, err := NewCommands() + if err == nil || err.Error() != "clipboard is unavailable" { + t.Errorf("invalid error: %v", err) + } +} + +func TestClipboardInstances(t *testing.T) { + 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 { + t.Error("invalid command retrieved") + } + } +}