mirror of
https://github.com/rclone/rclone
synced 2024-11-05 01:42:31 +01:00
Before this change, undecryptable file names would be skipped very quietly (there was a log warning, but only at DEBUG level), failing to alert users of a potentially serious issue that needs attention. After this change, the log level is raised to NOTICE by default and a new --crypt-strict-names flag allows raising an error, for users who may prefer not to proceed if such an issue is detected. See https://forum.rclone.org/t/skipping-undecryptable-file-name-should-be-an-error/27115 https://github.com/rclone/rclone/issues/5787
This commit is contained in:
parent
f5f86786b2
commit
4c6d2c5410
@ -130,6 +130,16 @@ trying to recover an encrypted file with errors and it is desired to
|
|||||||
recover as much of the file as possible.`,
|
recover as much of the file as possible.`,
|
||||||
Default: false,
|
Default: false,
|
||||||
Advanced: true,
|
Advanced: true,
|
||||||
|
}, {
|
||||||
|
Name: "strict_names",
|
||||||
|
Help: `If set, this will raise an error when crypt comes across a filename that can't be decrypted.
|
||||||
|
|
||||||
|
(By default, rclone will just log a NOTICE and continue as normal.)
|
||||||
|
This can happen if encrypted and unencrypted files are stored in the same
|
||||||
|
directory (which is not recommended.) It may also indicate a more serious
|
||||||
|
problem that should be investigated.`,
|
||||||
|
Default: false,
|
||||||
|
Advanced: true,
|
||||||
}, {
|
}, {
|
||||||
Name: "filename_encoding",
|
Name: "filename_encoding",
|
||||||
Help: `How to encode the encrypted filename to text string.
|
Help: `How to encode the encrypted filename to text string.
|
||||||
@ -299,6 +309,7 @@ type Options struct {
|
|||||||
PassBadBlocks bool `config:"pass_bad_blocks"`
|
PassBadBlocks bool `config:"pass_bad_blocks"`
|
||||||
FilenameEncoding string `config:"filename_encoding"`
|
FilenameEncoding string `config:"filename_encoding"`
|
||||||
Suffix string `config:"suffix"`
|
Suffix string `config:"suffix"`
|
||||||
|
StrictNames bool `config:"strict_names"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fs represents a wrapped fs.Fs
|
// Fs represents a wrapped fs.Fs
|
||||||
@ -333,45 +344,64 @@ func (f *Fs) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt an object file name to entries.
|
// Encrypt an object file name to entries.
|
||||||
func (f *Fs) add(entries *fs.DirEntries, obj fs.Object) {
|
func (f *Fs) add(entries *fs.DirEntries, obj fs.Object) error {
|
||||||
remote := obj.Remote()
|
remote := obj.Remote()
|
||||||
decryptedRemote, err := f.cipher.DecryptFileName(remote)
|
decryptedRemote, err := f.cipher.DecryptFileName(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Debugf(remote, "Skipping undecryptable file name: %v", err)
|
if f.opt.StrictNames {
|
||||||
return
|
return fmt.Errorf("%s: undecryptable file name detected: %v", remote, err)
|
||||||
|
}
|
||||||
|
fs.Logf(remote, "Skipping undecryptable file name: %v", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if f.opt.ShowMapping {
|
if f.opt.ShowMapping {
|
||||||
fs.Logf(decryptedRemote, "Encrypts to %q", remote)
|
fs.Logf(decryptedRemote, "Encrypts to %q", remote)
|
||||||
}
|
}
|
||||||
*entries = append(*entries, f.newObject(obj))
|
*entries = append(*entries, f.newObject(obj))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt a directory file name to entries.
|
// Encrypt a directory file name to entries.
|
||||||
func (f *Fs) addDir(ctx context.Context, entries *fs.DirEntries, dir fs.Directory) {
|
func (f *Fs) addDir(ctx context.Context, entries *fs.DirEntries, dir fs.Directory) error {
|
||||||
remote := dir.Remote()
|
remote := dir.Remote()
|
||||||
decryptedRemote, err := f.cipher.DecryptDirName(remote)
|
decryptedRemote, err := f.cipher.DecryptDirName(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Debugf(remote, "Skipping undecryptable dir name: %v", err)
|
if f.opt.StrictNames {
|
||||||
return
|
return fmt.Errorf("%s: undecryptable dir name detected: %v", remote, err)
|
||||||
|
}
|
||||||
|
fs.Logf(remote, "Skipping undecryptable dir name: %v", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if f.opt.ShowMapping {
|
if f.opt.ShowMapping {
|
||||||
fs.Logf(decryptedRemote, "Encrypts to %q", remote)
|
fs.Logf(decryptedRemote, "Encrypts to %q", remote)
|
||||||
}
|
}
|
||||||
*entries = append(*entries, f.newDir(ctx, dir))
|
*entries = append(*entries, f.newDir(ctx, dir))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt some directory entries. This alters entries returning it as newEntries.
|
// Encrypt some directory entries. This alters entries returning it as newEntries.
|
||||||
func (f *Fs) encryptEntries(ctx context.Context, entries fs.DirEntries) (newEntries fs.DirEntries, err error) {
|
func (f *Fs) encryptEntries(ctx context.Context, entries fs.DirEntries) (newEntries fs.DirEntries, err error) {
|
||||||
newEntries = entries[:0] // in place filter
|
newEntries = entries[:0] // in place filter
|
||||||
|
errors := 0
|
||||||
|
var firsterr error
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
switch x := entry.(type) {
|
switch x := entry.(type) {
|
||||||
case fs.Object:
|
case fs.Object:
|
||||||
f.add(&newEntries, x)
|
err = f.add(&newEntries, x)
|
||||||
case fs.Directory:
|
case fs.Directory:
|
||||||
f.addDir(ctx, &newEntries, x)
|
err = f.addDir(ctx, &newEntries, x)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown object type %T", entry)
|
return nil, fmt.Errorf("unknown object type %T", entry)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
errors++
|
||||||
|
if firsterr == nil {
|
||||||
|
firsterr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if firsterr != nil {
|
||||||
|
return nil, fmt.Errorf("there were %v undecryptable name errors. first error: %v", errors, firsterr)
|
||||||
}
|
}
|
||||||
return newEntries, nil
|
return newEntries, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user