Skip to content

Commit f738370

Browse files
dominikschulzsudoforge
authored andcommitted
[feat] Replace clipboard library to support wl-copy args (gopasspw#3123)
* [feat] Replace clipboard library to support wl-copy args This change should allow us to protect sensitive content from being captured in some clipboard managers on KDE. Fixes gopasspw#2611 Signed-off-by: Dominik Schulz <[email protected]> * [chore] Update clipboard dep Signed-off-by: Dominik Schulz <[email protected]> * [fix] Update clipboard Signed-off-by: Dominik Schulz <[email protected]> --------- Signed-off-by: Dominik Schulz <[email protected]>
1 parent 7752ad1 commit f738370

File tree

12 files changed

+43
-125
lines changed

12 files changed

+43
-125
lines changed

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
module github.com/gopasspw/gopass
22

3-
go 1.24.0
3+
go 1.24.1
44

55
require (
66
filippo.io/age v1.2.1-0.20240618131852-7eedd929a6cf
77
github.com/ProtonMail/go-crypto v1.2.0
8-
github.com/atotto/clipboard v0.1.4
98
github.com/blang/semver/v4 v4.0.0
109
github.com/caspr-io/yamlpath v0.0.0-20200722075116-502e8d113a9b
1110
github.com/cenkalti/backoff/v4 v4.3.0
@@ -16,6 +15,7 @@ require (
1615
github.com/gokyle/twofactor v1.0.1
1716
github.com/google/go-cmp v0.7.0
1817
github.com/google/go-github/v61 v61.0.0
18+
github.com/gopasspw/clipboard v0.0.0-20250418184741-a9895c5a47ee
1919
github.com/gopasspw/gopass-hibp v1.15.15
2020
github.com/hashicorp/golang-lru/v2 v2.0.7
2121
github.com/jsimonetti/pwscheme v0.0.0-20220922140336-67a4d090f150
@@ -52,6 +52,7 @@ require (
5252
al.essio.dev/pkg/shellescape v1.6.0 // indirect
5353
codeberg.org/tslocum/cbind v0.1.6 // indirect
5454
filippo.io/edwards25519 v1.1.0 // indirect
55+
github.com/atotto/clipboard v0.1.4 // indirect
5556
github.com/boombuler/barcode v1.0.2 // indirect
5657
github.com/cloudflare/circl v1.6.1 // indirect
5758
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
7171
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
7272
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
7373
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
74+
github.com/gopasspw/clipboard v0.0.0-20250417190150-d64f7d604636 h1:IqhPR3G2C1cdMgKKHYwaASJuh9meJDy6Abes44nYxTQ=
75+
github.com/gopasspw/clipboard v0.0.0-20250417190150-d64f7d604636/go.mod h1:b2ka158TfIu6UEYbnuYGjztg9dNwAIwCBL3qNoKH8qE=
76+
github.com/gopasspw/clipboard v0.0.0-20250418164705-c6bd724b45e0 h1:xCvVD0/DfFzYybu1t/dkLwXWwGPQdrfHvQSRtFJKhC8=
77+
github.com/gopasspw/clipboard v0.0.0-20250418164705-c6bd724b45e0/go.mod h1:i0cShr7JEbOXZ/iKM5RyfBLbu1FPzouO8BTCJy0uHy8=
78+
github.com/gopasspw/clipboard v0.0.0-20250418174641-ec5f8eb4a01b h1:wMbrBbxjh/cZeqXGTGhYs4L65tP6YBKvIgDTo9RIv94=
79+
github.com/gopasspw/clipboard v0.0.0-20250418174641-ec5f8eb4a01b/go.mod h1:i0cShr7JEbOXZ/iKM5RyfBLbu1FPzouO8BTCJy0uHy8=
80+
github.com/gopasspw/clipboard v0.0.0-20250418184741-a9895c5a47ee h1:I1bYhCNc3Qbd/sbjFPFZfeKmNvC+wIuFhwzCDmnBaX8=
81+
github.com/gopasspw/clipboard v0.0.0-20250418184741-a9895c5a47ee/go.mod h1:i0cShr7JEbOXZ/iKM5RyfBLbu1FPzouO8BTCJy0uHy8=
7482
github.com/gopasspw/gopass-hibp v1.15.15 h1:zmLhxXKu3fLa7qAexKw4EWVfKGgFzJ1j5ra9nzNnd1Y=
7583
github.com/gopasspw/gopass-hibp v1.15.15/go.mod h1:7xE84pJnO6x3i+u38NeUAvYlJVYPTUNL3Y5XJHSAwaY=
7684
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=

internal/action/create_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"os"
66
"testing"
77

8-
aclip "github.com/atotto/clipboard"
8+
"github.com/gopasspw/clipboard"
99
"github.com/gopasspw/gopass/internal/config"
1010
"github.com/gopasspw/gopass/internal/out"
1111
"github.com/gopasspw/gopass/pkg/ctxutil"
@@ -16,7 +16,7 @@ import (
1616
func TestCreate(t *testing.T) {
1717
u := gptest.NewUnitTester(t)
1818

19-
aclip.Unsupported = true
19+
clipboard.ForceUnsupported = true
2020

2121
ctx := config.NewContextInMemory()
2222
ctx = ctxutil.WithAlwaysYes(ctx, true)

internal/action/show_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"os"
77
"testing"
88

9-
"github.com/atotto/clipboard"
109
"github.com/fatih/color"
10+
"github.com/gopasspw/clipboard"
1111
"github.com/gopasspw/gopass/internal/config"
1212
"github.com/gopasspw/gopass/internal/out"
1313
"github.com/gopasspw/gopass/pkg/ctxutil"
@@ -224,11 +224,11 @@ func TestShowMulti(t *testing.T) {
224224

225225
func TestShowAutoClip(t *testing.T) {
226226
// make sure we consistently get the unsupported error message
227-
ov := clipboard.Unsupported
227+
ov := clipboard.ForceUnsupported
228228
defer func() {
229-
clipboard.Unsupported = ov
229+
clipboard.ForceUnsupported = ov
230230
}()
231-
clipboard.Unsupported = true
231+
clipboard.ForceUnsupported = true
232232

233233
u := gptest.NewUnitTester(t)
234234

main_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"runtime"
99
"testing"
1010

11-
"github.com/atotto/clipboard"
1211
"github.com/blang/semver/v4"
1312
"github.com/fatih/color"
13+
"github.com/gopasspw/clipboard"
1414
"github.com/gopasspw/gopass/internal/action"
1515
"github.com/gopasspw/gopass/internal/backend"
1616
"github.com/gopasspw/gopass/internal/backend/crypto/gpg"
@@ -118,7 +118,7 @@ func TestGetCommands(t *testing.T) {
118118
cfg := config.NewInMemory()
119119
require.NoError(t, cfg.SetPath(u.StoreDir("")))
120120

121-
clipboard.Unsupported = true
121+
clipboard.ForceUnsupported = true
122122

123123
ctx := config.NewContextInMemory()
124124
ctx = ctxutil.WithAlwaysYes(ctx, true)

pkg/clipboard/clipboard.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77
"os"
88
"os/exec"
99

10-
"github.com/atotto/clipboard"
1110
"github.com/fatih/color"
11+
"github.com/gopasspw/clipboard"
1212
"github.com/gopasspw/gopass/internal/notify"
1313
"github.com/gopasspw/gopass/internal/out"
1414
"github.com/gopasspw/gopass/pkg/debug"
@@ -17,7 +17,7 @@ import (
1717
var (
1818
// Helpers can be overridden at compile time, e.g. go build \
1919
// -ldflags=='-X github.com/gopasspw/gopass/pkg/clipboard.Helpers=termux-api'.
20-
Helpers = "xsel or xclip"
20+
Helpers = "xsel, xclip or wl-clipboard"
2121
// ErrNotSupported is returned when the clipboard is not accessible.
2222
ErrNotSupported = fmt.Errorf("WARNING: No clipboard available. "+
2323
"Install %s, provide $GOPASS_CLIPBOARD_COPY_CMD and $GOPASS_CLIPBOARD_CLEAR_CMD or use -f to print to console", Helpers)
@@ -35,7 +35,7 @@ func CopyTo(ctx context.Context, name string, content []byte, timeout int) error
3535

3636
return fmt.Errorf("failed to call clipboard copy command: %w", err)
3737
}
38-
} else if clipboard.Unsupported {
38+
} else if clipboard.IsUnsupported() {
3939
out.Errorf(ctx, "%s", ErrNotSupported)
4040
_ = notify.Notify(ctx, "gopass - clipboard", ErrNotSupported.Error())
4141

@@ -67,7 +67,15 @@ func CopyTo(ctx context.Context, name string, content []byte, timeout int) error
6767
return nil
6868
}
6969

70-
func callCommand(ctx context.Context, cmd string, parameter string, stdinValue []byte) error {
70+
func copyToClipboard(ctx context.Context, content []byte) error {
71+
if err := clipboard.WriteAll(ctx, content); err != nil {
72+
return fmt.Errorf("failed to write to clipboard: %w", err)
73+
}
74+
75+
return nil
76+
}
77+
78+
func callCommand(_ context.Context, cmd string, parameter string, stdinValue []byte) error {
7179
clipboardProcess := exec.Command(cmd, parameter)
7280
stdin, err := clipboardProcess.StdinPipe()
7381

pkg/clipboard/clipboard_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
"testing"
1111
"time"
1212

13-
"github.com/atotto/clipboard"
13+
"github.com/gopasspw/clipboard"
1414
"github.com/gopasspw/gopass/internal/config"
1515
"github.com/gopasspw/gopass/internal/out"
1616
"github.com/mitchellh/go-ps"
@@ -36,7 +36,7 @@ func TestUnsupportedCopyToClipboard(t *testing.T) {
3636
ctx, cancel := context.WithCancel(config.NewContextInMemory())
3737
defer cancel()
3838

39-
clipboard.Unsupported = true
39+
clipboard.ForceUnsupported = true
4040

4141
buf := &bytes.Buffer{}
4242
out.Stderr = buf
@@ -53,7 +53,7 @@ func TestClearClipboard(t *testing.T) {
5353
}
5454

5555
func BenchmarkWalkProc(b *testing.B) {
56-
for i := 0; i < b.N; i++ { //nolint:intrange // b.N is evaluated at each iteration.
56+
for b.Loop() {
5757
_ = filepath.Walk("/proc", func(path string, info os.FileInfo, err error) error {
5858
if err != nil {
5959
return nil
@@ -76,7 +76,7 @@ func BenchmarkWalkProc(b *testing.B) {
7676
}
7777

7878
func BenchmarkListProc(b *testing.B) {
79-
for i := 0; i < b.N; i++ { //nolint:intrange // b.N is evaluated at each iteration.
79+
for b.Loop() {
8080
procs, err := ps.Processes()
8181
if err != nil {
8282
b.Fatalf("err: %s", err)

pkg/clipboard/copy_darwin.go

Lines changed: 0 additions & 80 deletions
This file was deleted.

pkg/clipboard/copy_others.go

Lines changed: 0 additions & 19 deletions
This file was deleted.

pkg/clipboard/unclip.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"fmt"
66
"os"
77

8-
"github.com/atotto/clipboard"
8+
"github.com/gopasspw/clipboard"
99
"github.com/gopasspw/gopass/internal/notify"
1010
"github.com/gopasspw/gopass/internal/pwschemes/argon2id"
1111
"github.com/gopasspw/gopass/pkg/debug"
@@ -26,11 +26,11 @@ func Clear(ctx context.Context, name string, checksum string, force bool) error
2626
return nil
2727
}
2828

29-
if clipboard.Unsupported {
29+
if clipboard.IsUnsupported() {
3030
return ErrNotSupported
3131
}
3232

33-
cur, err := clipboard.ReadAll()
33+
cur, err := clipboard.ReadAllString(ctx)
3434
if err != nil {
3535
return fmt.Errorf("failed to read clipboard: %w", err)
3636
}
@@ -46,7 +46,7 @@ func Clear(ctx context.Context, name string, checksum string, force bool) error
4646
return nil
4747
}
4848

49-
if err := clipboard.WriteAll(""); err != nil {
49+
if err := clipboard.WriteAllString(ctx, ""); err != nil {
5050
_ = notify.Notify(ctx, "gopass - clipboard", "Failed to clear clipboard")
5151

5252
return fmt.Errorf("failed to write clipboard: %w", err)

0 commit comments

Comments
 (0)