Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly handle new multiline secrets #2625

Merged
merged 4 commits into from Jul 30, 2023

Conversation

dominikschulz
Copy link
Member

This commit fixes as small issue in how multi-line secrets are handled. Before they were always written in to the secret body completly ignoring the first line that contains the password. Now we do respect that correctly. To implement that properly we need to have some additional code to satisfy the io.Writer assumptions around the AKV secret type.

Also this fixes some non-hermetic tests that showed up during testing of this change.

Fixes #2614

This commit fixes as small issue in how multi-line secrets are handled.
Before they were always written in to the secret body completly ignoring
the first line that contains the password. Now we do respect that
correctly. To implement that properly we need to have some additional
code to satisfy the io.Writer assumptions around the AKV secret type.

Also this fixes some non-hermetic tests that showed up during testing of
this change.

Fixes gopasspw#2614

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
@dominikschulz dominikschulz added the bug Defects label Jul 30, 2023
@dominikschulz dominikschulz added this to the 1.15.6 milestone Jul 30, 2023
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
Copy link
Member

@AnomalRoil AnomalRoil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised we need such a "complex" solution, I would have expected removing the newline in NewAKV would already solve the multi-line issue, but I guess you tried it and it had side effects.

Just a few comments around the Write returns, since usually we'd return the number of bytes actually written.

func (p *pwWriter) Write(buf []byte) (int, error) {
n := len(buf)
if p.written || p.a == nil {
return n, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return n, nil
return 0, nil

Since no writes are done in that case, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this did raise some questions with me that I didn't have a good answer for and I ditched the MultiWriter approach for a pass-through wirter. I think that's easier to reason about.

_, err = p.Write([]byte("baz\n"))
assert.NoError(t, err)

assert.Equal(t, "foobar", a.Password())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the test also test the content of Body?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's more comprehensive.

pkg/gopass/secrets/akv.go Outdated Show resolved Hide resolved

// If the body is empty before writing we must threat the first line
// of the newly written content as the password or multi-line insert
// and similar operations will fail. For regular command line usage
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you mean by "and similar operations will fail"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like insert from STDIN. That should be affected here as well. Updated the comment.

p.a.password = p.buf.String()
p.written = true

return n, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be

Suggested change
return n, nil
return i, nil

Since it only writes the pw?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment above. I think the approach was not great.

@dominikschulz
Copy link
Member Author

dominikschulz commented Jul 30, 2023

I did try the simpler approach first, indeed. It had side-effects for some of our tests. Unfortunately. I'll address the other comments later.

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
@dominikschulz dominikschulz merged commit 9666b0a into gopasspw:master Jul 30, 2023
8 checks passed
@dominikschulz dominikschulz deleted the fix/issue-2614 branch July 30, 2023 16:57
Copy link
Member

@AnomalRoil AnomalRoil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a little comment about the logs.

I'm not sure we needed the extra writer implementation since we do the Write call on the whole buffer anyway and not in a way we could stream with a reader/writer but lgtm

@@ -185,6 +185,7 @@ func (s *Action) insertGetSecret(ctx context.Context, name, pw string) (gopass.S

// insertYAML will overwrite existing keys.
func (s *Action) insertYAML(ctx context.Context, name, key string, content []byte, kvps map[string]string) error {
debug.Log("insertYAML: %s - %s -> %s", name, key, content)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this will leak OTP codes in the debug logs, I think.
We should not be logging any of otp, topt, hotp and otpauth keys, as well as any key that satisfies action.isUnsafeKey I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these should be safeString types, so they shouldn't leak I think?

But if they do we can remove these.

@@ -436,6 +436,7 @@ func (s *Action) generateReplaceExisting(ctx context.Context, name, key, passwor

func setMetadata(sec gopass.Secret, kvps map[string]string) {
for k, v := range kvps {
debug.Log("setting %s to %s", k, v)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as other comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Defects
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Copying empty secret when multiline is inserted
2 participants