protondrive: tidy small review findings

Log lines no longer cut a name inside a UTF-8 sequence, the "superseded
upload" error says the file's state rather than claiming a revision is
active, a test-only block decrypter moves to the tests, a one-line alias
of encryptPassphrase goes, the upload godoc is rewrapped and the fake's
server struct is gofmt clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-11-12 14:46:52 +01:00
1 parent 30cfcac416
commit d3aee2af19
7 files changed
+43 -32

No files matched your search

-21
View File
@@ -559,13 +559,6 @@ func s2kSpecifier(op *packet.OpaquePacket) ([]byte, error) {
return rest[i:], nil
}
// reencryptPassphrase returns the passphrase of keys encrypted to
// newParentKR, with the same session key, and a new detached signature
// by signerKR, for a move.
func reencryptPassphrase(keys *nodeKeys, newParentKR, signerKR *crypto.KeyRing, now time.Time) (encPassphrase, passphraseSig string, err error) {
return encryptPassphrase(keys, newParentKR, signerKR, now)
}
// encryptName returns name encrypted to parentKR and signed by
// signerKR, without AEAD, with the session key sk, or a new one if sk
// is nil.
@@ -795,20 +788,6 @@ func encryptBlockTo(enc io.Writer, plain io.Reader, sk *crypto.SessionKey, nodeK
return encSignature, nil
}
// decryptBlock returns the encrypted block enc (SEIPDv1 or v2)
// decrypted with the content session key sk.
func decryptBlock(enc []byte, sk *crypto.SessionKey) ([]byte, error) {
r, err := blockDecrypter(bytes.NewReader(enc), sk)
if err != nil {
return nil, err
}
plain, err := io.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("decrypt block: %w", err)
}
return plain, nil
}
// blockDecrypter returns a reader of the encrypted block enc (SEIPDv1
// or v2) decrypted with the content session key sk.
//
+1 -1
View File
@@ -356,7 +356,7 @@ func TestReencryptPassphrase(t *testing.T) {
parent, newParent, signer, newSigner := newTestKeyRing(t, now), newTestKeyRing(t, now), newTestKeyRing(t, now), newTestKeyRing(t, now)
armoredKey, encPassphrase, _, keys := testNodeKeys(t, parent, signer, true, now)
enc, sig, err := reencryptPassphrase(keys, newParent, newSigner, now)
enc, sig, err := encryptPassphrase(keys, newParent, newSigner, now)
require.NoError(t, err)
requireNonAEAD(t, enc)
assert.NotEqual(t, encPassphrase, enc)
+8 -2
View File
@@ -11,6 +11,7 @@ import (
"strings"
"sync"
"time"
"unicode/utf8"
"github.com/ProtonMail/gopenpgp/v3/constants"
"github.com/ProtonMail/gopenpgp/v3/crypto"
@@ -623,7 +624,11 @@ func truncateName(name string) string {
if len(name) <= maxLen {
return name
}
return name[:maxLen] + "..."
cut := maxLen
for cut > 0 && !utf8.RuneStart(name[cut]) {
cut--
}
return name[:cut] + "..."
}
// reportOnce calls log unless a problem of kind with node id has
@@ -1267,7 +1272,8 @@ func (c *client) encryptForNewParent(ctx context.Context, op string, n *node, ne
return nil, err
}
passphraseSig := ""
out.passphrase, passphraseSig, err = reencryptPassphrase(n.keys, newParent.keys.keyRing, signKR, now)
// The passphrase keeps its session key, as in the SDK.
out.passphrase, passphraseSig, err = encryptPassphrase(n.keys, newParent.keys.keyRing, signKR, now)
if err != nil {
return nil, err
}
@@ -13,6 +13,7 @@ import (
"sync"
"testing"
"time"
"unicode/utf8"
"github.com/rclone/rclone/backend/protondrive/api"
"github.com/rclone/rclone/backend/protondrive/protontest"
@@ -1306,3 +1307,10 @@ func TestCopyReadBackLag(t *testing.T) {
assert.Equal(t, "copy.txt", cp.Name)
assert.Equal(t, file.sha1(), cp.sha1())
}
func TestTruncateName(t *testing.T) {
assert.Equal(t, "short", truncateName("short"))
got := truncateName("a" + strings.Repeat("é", 40))
assert.True(t, utf8.ValidString(got), "%q", got)
assert.Equal(t, "a"+strings.Repeat("é", 31)+"...", got)
}
+4 -3
View File
@@ -102,9 +102,6 @@ type Server struct {
requests map[string]int // count per "METHOD pattern"
faults []*fault
clockSkew time.Duration
// driveRequirements is sent as x-pm-drive-requirements headers if
// not empty; see SetDriveRequirements.
driveRequirements []string
users map[string]*User // by username
sessions map[string]*session // by UID
srp map[string]*srpLogin // by SRPSession
@@ -121,6 +118,10 @@ type Server struct {
readLag int // reads of a node after a change which don't see it; see SetReadLag
readLagView LagView // what lagging reads of a changed node see
lagging map[string]*lagView // nodes whose reads lag, by ID
// driveRequirements is sent as x-pm-drive-requirements headers if
// not empty; see SetDriveRequirements.
driveRequirements []string
}
// New starts a fake server which is closed when the test ends.
@@ -1,9 +1,13 @@
package protondrive
import (
"bytes"
"context"
"fmt"
"io"
"testing"
"github.com/ProtonMail/gopenpgp/v3/crypto"
"github.com/rclone/rclone/backend/protondrive/protontest"
"github.com/stretchr/testify/require"
)
@@ -31,3 +35,17 @@ func newTestClientFor(t testing.TB, srv *protontest.Server, u *protontest.User,
t.Cleanup(c.close)
return c
}
// decryptBlock returns the encrypted block enc (SEIPDv1 or v2)
// decrypted with the content session key sk.
func decryptBlock(enc []byte, sk *crypto.SessionKey) ([]byte, error) {
r, err := blockDecrypter(bytes.NewReader(enc), sk)
if err != nil {
return nil, err
}
plain, err := io.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("decrypt block: %w", err)
}
return plain, nil
}
+4 -5
View File
@@ -103,10 +103,9 @@ type draft struct {
// and a failed commit whose revision the file read back doesn't show is
// errUploadOutcomeUnknown: the upload may have succeeded. A commit which
// succeeded but whose file has another revision by the time it is read
// back is errUploadSuperseded,
// and one the server still doesn't show after a few reads is
// errUploadUnconfirmed. The returned node is always the upload's own
// revision.
// back is errUploadSuperseded, and one the server still doesn't show
// after a few reads is errUploadUnconfirmed. The returned node is always
// the upload's own revision.
func (c *client) upload(ctx context.Context, r uploadRequest) (*node, error) {
what := fmt.Sprintf("upload %q", r.Name)
if r.Existing != nil {
@@ -443,7 +442,7 @@ func (c *client) uploadDraft(ctx context.Context, d *draft, r uploadRequest, sig
case commitErr == nil && err != nil:
return nil, true, fmt.Errorf("read the uploaded file: %w", err)
case commitErr == nil:
return nil, true, fmt.Errorf("%w (revision %s is active, not %s)", errUploadSuperseded, n.RevisionID, d.revisionID)
return nil, true, fmt.Errorf("%w (the file is in state %d with revision %q active, not %s)", errUploadSuperseded, n.State, n.RevisionID, d.revisionID)
case err != nil:
// Any draft left is replaced by the next upload of the name.
return nil, true, fmt.Errorf("commit: %w: %w (reading the file failed: %v)", errUploadOutcomeUnknown, commitErr, err)