Skip to content
This repository was archived by the owner on Feb 16, 2023. It is now read-only.

Commit cfef938

Browse files
Merge pull request #382 from secrethub/fix/clipboard-test
Fix tests using WriteClipboardAutoClear
2 parents 4038bc8 + 192fd0b commit cfef938

8 files changed

Lines changed: 97 additions & 100 deletions

File tree

internals/secrethub/clear_clipboard.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111
"golang.org/x/crypto/bcrypt"
1212
)
1313

14-
// defaultClearClipboardAfter defines the default TTL for data written to the clipboard.
15-
const defaultClearClipboardAfter = 45 * time.Second
14+
// clearClipboardAfter defines the TTL for data written to the clipboard.
15+
const clearClipboardAfter = 45 * time.Second
1616

1717
// ClearClipboardCommand is a command to clear the contents of the clipboard after some time passed.
1818
type ClearClipboardCommand struct {
@@ -62,21 +62,29 @@ func (cmd *ClearClipboardCommand) Run() error {
6262
return nil
6363
}
6464

65-
// WriteClipboardAutoClear writes data to the clipboard and clears it after the timeout.
66-
func WriteClipboardAutoClear(data []byte, timeout time.Duration, clipper clip.Clipper) error {
65+
type ClipboardWriter interface {
66+
Write(data []byte) error
67+
}
68+
69+
type ClipboardWriterAutoClear struct {
70+
clipper clip.Clipper
71+
}
72+
73+
// Write writes data to the clipboard and clears it after the timeout.
74+
func (clipWriter *ClipboardWriterAutoClear) Write(data []byte) error {
6775
hash, err := bcrypt.GenerateFromPassword(data, bcrypt.DefaultCost)
6876
if err != nil {
6977
return err
7078
}
7179

72-
err = clipper.WriteAll(data)
80+
err = clipWriter.clipper.WriteAll(data)
7381
if err != nil {
7482
return err
7583
}
7684

7785
err = cloneproc.Spawn(
7886
"clipboard-clear", hex.EncodeToString(hash),
79-
"--timeout", timeout.String())
87+
"--timeout", clearClipboardAfter.String())
8088

8189
return err
8290
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package secrethub
2+
3+
import "bytes"
4+
5+
type FakeClipboardWriter struct {
6+
Buffer bytes.Buffer
7+
}
8+
9+
func (clipWriter *FakeClipboardWriter) Write(data []byte) error {
10+
_, err := clipWriter.Buffer.Write(data)
11+
return err
12+
}

internals/secrethub/generate.go

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"os"
66
"strconv"
77
"strings"
8-
"time"
98

109
"github.com/secrethub/secrethub-cli/internals/cli"
1110
"github.com/secrethub/secrethub-cli/internals/cli/clip"
@@ -35,28 +34,28 @@ const defaultLength = 22
3534

3635
// GenerateSecretCommand generates a new secret and writes to the output path.
3736
type GenerateSecretCommand struct {
38-
symbolsFlag bool
39-
generator randchar.Generator
40-
io ui.IO
41-
lengthFlag intValue
42-
firstArg cli.StringValue
43-
secondArg cli.StringValue
44-
lengthArg intValue
45-
charsetFlag charsetValue
46-
mins minRuleValue
47-
copyToClipboard bool
48-
clearClipboardAfter time.Duration
49-
clipper clip.Clipper
50-
newClient newClientFunc
37+
symbolsFlag bool
38+
generator randchar.Generator
39+
io ui.IO
40+
lengthFlag intValue
41+
firstArg cli.StringValue
42+
secondArg cli.StringValue
43+
lengthArg intValue
44+
charsetFlag charsetValue
45+
mins minRuleValue
46+
copyToClipboard bool
47+
newClient newClientFunc
48+
clipWriter ClipboardWriter
5149
}
5250

5351
// NewGenerateSecretCommand creates a new GenerateSecretCommand.
5452
func NewGenerateSecretCommand(io ui.IO, newClient newClientFunc) *GenerateSecretCommand {
5553
return &GenerateSecretCommand{
56-
io: io,
57-
newClient: newClient,
58-
clearClipboardAfter: defaultClearClipboardAfter,
59-
clipper: clip.NewClipboard(),
54+
io: io,
55+
newClient: newClient,
56+
clipWriter: &ClipboardWriterAutoClear{
57+
clipper: clip.NewClipboard(),
58+
},
6059
}
6160
}
6261

@@ -66,7 +65,7 @@ func (cmd *GenerateSecretCommand) Register(r cli.Registerer) {
6665
clause.Flags().VarP(&cmd.lengthFlag, "length", "l", "The length of the generated secret.")
6766
clause.Cmd.Flag("length").DefValue = strconv.Itoa(defaultLength)
6867
clause.Flags().Var(&cmd.mins, "min", "<charset>:<n> Ensure that the resulting password contains at least n characters from the given character set. Note that adding constraints reduces the strength of the secret. When possible, avoid any constraints.")
69-
clause.Flags().BoolVarP(&cmd.copyToClipboard, "clip", "c", false, "Copy the generated value to the clipboard. The clipboard is automatically cleared after "+units.HumanDuration(cmd.clearClipboardAfter)+".")
68+
clause.Flags().BoolVarP(&cmd.copyToClipboard, "clip", "c", false, "Copy the generated value to the clipboard. The clipboard is automatically cleared after "+units.HumanDuration(clearClipboardAfter)+".")
7069
_ = cmd.charsetFlag.Set("alphanumeric")
7170
clause.Flags().Var(&cmd.charsetFlag, "charset", "Define the set of characters to randomly generate a password from. Options are all, alphanumeric, numeric, lowercase, uppercase, letters, symbols and human-readable. Multiple character sets can be combined by supplying them in a comma separated list.")
7271
clause.Cmd.Flag("charset").DefValue = "alphanumeric"
@@ -147,15 +146,15 @@ func (cmd *GenerateSecretCommand) run() error {
147146
fmt.Fprintf(cmd.io.Output(), "A randomly generated secret has been written to %s:%d.\n", path, version.Version)
148147

149148
if cmd.copyToClipboard {
150-
err = WriteClipboardAutoClear(data, cmd.clearClipboardAfter, cmd.clipper)
149+
err = cmd.clipWriter.Write(data)
151150
if err != nil {
152151
return err
153152
}
154153

155154
fmt.Fprintf(
156155
cmd.io.Output(),
157156
"The generated value has been copied to the clipboard. It will be cleared after %s.\n",
158-
units.HumanDuration(cmd.clearClipboardAfter),
157+
units.HumanDuration(clearClipboardAfter),
159158
)
160159
}
161160

internals/secrethub/generate_test.go

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

77
"github.com/secrethub/secrethub-cli/internals/cli"
8-
"github.com/secrethub/secrethub-cli/internals/cli/clip/fakeclip"
98
"github.com/secrethub/secrethub-cli/internals/cli/ui/fakeui"
109

1110
"github.com/secrethub/secrethub-go/internals/api"
@@ -42,7 +41,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
4241
Err: nil,
4342
},
4443
firstArg: cli.StringValue{Value: testPath},
45-
clipper: fakeclip.New(),
4644
},
4745
writeFunc: func(path string, data []byte) (*api.SecretVersion, error) {
4846
return &api.SecretVersion{Version: 1}, nil
@@ -60,7 +58,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
6058
},
6159
firstArg: cli.StringValue{Value: testPath},
6260
copyToClipboard: true,
63-
clipper: fakeclip.New(),
6461
},
6562
writeFunc: func(path string, data []byte) (*api.SecretVersion, error) {
6663
return &api.SecretVersion{Version: 1}, nil
@@ -69,7 +66,7 @@ func TestGenerateSecretCommand_run(t *testing.T) {
6966
data: testData,
7067
expectedClip: testData,
7168
expectedOut: "A randomly generated secret has been written to namespace/repo/secret:1.\n" +
72-
"The generated value has been copied to the clipboard. It will be cleared after Less than a second.\n",
69+
"The generated value has been copied to the clipboard. It will be cleared after 45 seconds.\n",
7370
},
7471
"length flag": {
7572
cmd: GenerateSecretCommand{
@@ -79,7 +76,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
7976
},
8077
firstArg: cli.StringValue{Value: testPath},
8178
lengthFlag: newIntValue(24),
82-
clipper: fakeclip.New(),
8379
},
8480
writeFunc: func(path string, data []byte) (*api.SecretVersion, error) {
8581
return &api.SecretVersion{Version: 1}, nil
@@ -99,7 +95,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
9995
secondArg: cli.StringValue{Value: testPath},
10096
lengthFlag: newIntValue(24),
10197
lengthArg: newIntValue(24),
102-
clipper: fakeclip.New(),
10398
},
10499
expectedErr: ErrCannotUseLengthArgAndFlag,
105100
},
@@ -112,7 +107,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
112107
firstArg: cli.StringValue{Value: "rand"},
113108
secondArg: cli.StringValue{Value: testPath},
114109
lengthArg: newIntValue(23),
115-
clipper: fakeclip.New(),
116110
},
117111
writeFunc: func(path string, data []byte) (*api.SecretVersion, error) {
118112
return &api.SecretVersion{Version: 1}, nil
@@ -127,7 +121,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
127121
firstArg: cli.StringValue{Value: "rand"},
128122
secondArg: cli.StringValue{Value: testPath},
129123
lengthArg: newIntValue(0),
130-
clipper: fakeclip.New(),
131124
},
132125
expectedErr: ErrInvalidRandLength,
133126
expectedOut: "",
@@ -137,7 +130,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
137130
firstArg: cli.StringValue{Value: "rand"},
138131
secondArg: cli.StringValue{Value: testPath},
139132
lengthArg: newIntValue(-1),
140-
clipper: fakeclip.New(),
141133
},
142134
expectedErr: ErrInvalidRandLength,
143135
expectedOut: "",
@@ -147,7 +139,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
147139
cmd: GenerateSecretCommand{
148140
firstArg: cli.StringValue{Value: testPath},
149141
lengthArg: newIntValue(24),
150-
clipper: fakeclip.New(),
151142
},
152143
expectedErr: errors.New("unexpected 24"),
153144
},
@@ -156,7 +147,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
156147
cmd: GenerateSecretCommand{
157148
firstArg: cli.StringValue{Value: testPath},
158149
secondArg: cli.StringValue{Value: "namespace/repo/secret2"},
159-
clipper: fakeclip.New(),
160150
},
161151
expectedErr: errors.New("unexpected namespace/repo/secret2"),
162152
},
@@ -167,7 +157,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
167157
Err: testErr,
168158
},
169159
firstArg: cli.StringValue{Value: testPath},
170-
clipper: fakeclip.New(),
171160
},
172161
expectedErr: testErr,
173162
},
@@ -178,7 +167,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
178167
Err: nil,
179168
},
180169
firstArg: cli.StringValue{Value: testPath},
181-
clipper: fakeclip.New(),
182170
},
183171
newClientErr: testErr,
184172
expectedErr: testErr,
@@ -190,7 +178,6 @@ func TestGenerateSecretCommand_run(t *testing.T) {
190178
Err: nil,
191179
},
192180
firstArg: cli.StringValue{Value: testPath},
193-
clipper: fakeclip.New(),
194181
},
195182
writeFunc: func(path string, data []byte) (*api.SecretVersion, error) {
196183
return nil, testErr
@@ -210,6 +197,9 @@ func TestGenerateSecretCommand_run(t *testing.T) {
210197
testIO := fakeui.NewIO(t)
211198
tc.cmd.io = testIO
212199

200+
clipWriter := &FakeClipboardWriter{}
201+
tc.cmd.clipWriter = clipWriter
202+
213203
tc.cmd.newClient = func() (secrethub.ClientInterface, error) {
214204
return fakeclient.Client{
215205
SecretService: &fakeclient.SecretService{
@@ -224,14 +214,12 @@ func TestGenerateSecretCommand_run(t *testing.T) {
224214

225215
// Act
226216
err := tc.cmd.run()
227-
resClip, clipErr := tc.cmd.clipper.ReadAll()
228217

229218
// Assert
230-
assert.OK(t, clipErr)
231219
assert.Equal(t, err, tc.expectedErr)
232220
assert.Equal(t, argPath, tc.path)
233221
assert.Equal(t, argData, tc.data)
234-
assert.Equal(t, resClip, tc.expectedClip)
222+
assert.Equal(t, clipWriter.Buffer.Bytes(), tc.expectedClip)
235223
assert.Equal(t, testIO.Out.String(), tc.expectedOut)
236224
})
237225
}

internals/secrethub/inject.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"io/ioutil"
66
"os"
77
"path/filepath"
8-
"time"
98

109
"github.com/secrethub/secrethub-cli/internals/cli"
1110
"github.com/secrethub/secrethub-cli/internals/cli/clip"
@@ -31,8 +30,7 @@ type InjectCommand struct {
3130
force bool
3231
io ui.IO
3332
useClipboard bool
34-
clearClipboardAfter time.Duration
35-
clipper clip.Clipper
33+
clipWriter ClipboardWriter
3634
osEnv []string
3735
newClient newClientFunc
3836
templateVars map[string]string
@@ -43,13 +41,14 @@ type InjectCommand struct {
4341
// NewInjectCommand creates a new InjectCommand.
4442
func NewInjectCommand(io ui.IO, newClient newClientFunc) *InjectCommand {
4543
return &InjectCommand{
46-
clipper: clip.NewClipboard(),
47-
osEnv: os.Environ(),
48-
clearClipboardAfter: defaultClearClipboardAfter,
49-
io: io,
50-
newClient: newClient,
51-
templateVars: make(map[string]string),
52-
fileMode: filemode.New(0600),
44+
clipWriter: &ClipboardWriterAutoClear{
45+
clipper: clip.NewClipboard(),
46+
},
47+
osEnv: os.Environ(),
48+
io: io,
49+
newClient: newClient,
50+
templateVars: make(map[string]string),
51+
fileMode: filemode.New(0600),
5352
}
5453
}
5554

@@ -61,7 +60,7 @@ func (cmd *InjectCommand) Register(r cli.Registerer) {
6160
"clip", "c", false,
6261
fmt.Sprintf(
6362
"Copy the injected template to the clipboard instead of stdout. The clipboard is automatically cleared after %s.",
64-
units.HumanDuration(cmd.clearClipboardAfter),
63+
units.HumanDuration(clearClipboardAfter),
6564
))
6665
clause.Flags().StringVarP(&cmd.inFile, "in-file", "i", "", "The filename of a template file to inject.")
6766
clause.Flags().StringVarP(&cmd.outFile, "out-file", "o", "", "Write the injected template to a file instead of stdout.")
@@ -131,12 +130,12 @@ func (cmd *InjectCommand) Run() error {
131130

132131
out := []byte(injected)
133132
if cmd.useClipboard {
134-
err = WriteClipboardAutoClear(out, cmd.clearClipboardAfter, cmd.clipper)
133+
err = cmd.clipWriter.Write(out)
135134
if err != nil {
136135
return err
137136
}
138137

139-
_, err = fmt.Fprintf(cmd.io.Output(), "Copied injected template to clipboard. It will be cleared after %s.\n", units.HumanDuration(cmd.clearClipboardAfter))
138+
_, err = fmt.Fprintf(cmd.io.Output(), "Copied injected template to clipboard. It will be cleared after %s.\n", units.HumanDuration(clearClipboardAfter))
140139
if err != nil {
141140
return err
142141
}

0 commit comments

Comments
 (0)