github.com/artpar/rclone@v1.67.3/backend/crypt/crypt.go (about) 1 // Package crypt provides wrappers for Fs and Object which implement encryption 2 package crypt 3 4 import ( 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "path" 10 "strings" 11 "time" 12 13 "github.com/artpar/rclone/fs" 14 "github.com/artpar/rclone/fs/accounting" 15 "github.com/artpar/rclone/fs/cache" 16 "github.com/artpar/rclone/fs/config/configmap" 17 "github.com/artpar/rclone/fs/config/configstruct" 18 "github.com/artpar/rclone/fs/config/obscure" 19 "github.com/artpar/rclone/fs/fspath" 20 "github.com/artpar/rclone/fs/hash" 21 ) 22 23 // Globals 24 // Register with Fs 25 func init() { 26 fs.Register(&fs.RegInfo{ 27 Name: "crypt", 28 Description: "Encrypt/Decrypt a remote", 29 NewFs: NewFs, 30 CommandHelp: commandHelp, 31 MetadataInfo: &fs.MetadataInfo{ 32 Help: `Any metadata supported by the underlying remote is read and written.`, 33 }, 34 Options: []fs.Option{{ 35 Name: "remote", 36 Help: "Remote to encrypt/decrypt.\n\nNormally should contain a ':' and a path, e.g. \"myremote:path/to/dir\",\n\"myremote:bucket\" or maybe \"myremote:\" (not recommended).", 37 Required: true, 38 }, { 39 Name: "filename_encryption", 40 Help: "How to encrypt the filenames.", 41 Default: "standard", 42 Examples: []fs.OptionExample{ 43 { 44 Value: "standard", 45 Help: "Encrypt the filenames.\nSee the docs for the details.", 46 }, { 47 Value: "obfuscate", 48 Help: "Very simple filename obfuscation.", 49 }, { 50 Value: "off", 51 Help: "Don't encrypt the file names.\nAdds a \".bin\", or \"suffix\" extension only.", 52 }, 53 }, 54 }, { 55 Name: "directory_name_encryption", 56 Help: `Option to either encrypt directory names or leave them intact. 57 58 NB If filename_encryption is "off" then this option will do nothing.`, 59 Default: true, 60 Examples: []fs.OptionExample{ 61 { 62 Value: "true", 63 Help: "Encrypt directory names.", 64 }, 65 { 66 Value: "false", 67 Help: "Don't encrypt directory names, leave them intact.", 68 }, 69 }, 70 }, { 71 Name: "password", 72 Help: "Password or pass phrase for encryption.", 73 IsPassword: true, 74 Required: true, 75 }, { 76 Name: "password2", 77 Help: "Password or pass phrase for salt.\n\nOptional but recommended.\nShould be different to the previous password.", 78 IsPassword: true, 79 }, { 80 Name: "server_side_across_configs", 81 Default: false, 82 Help: `Deprecated: use --server-side-across-configs instead. 83 84 Allow server-side operations (e.g. copy) to work across different crypt configs. 85 86 Normally this option is not what you want, but if you have two crypts 87 pointing to the same backend you can use it. 88 89 This can be used, for example, to change file name encryption type 90 without re-uploading all the data. Just make two crypt backends 91 pointing to two different directories with the single changed 92 parameter and use rclone move to move the files between the crypt 93 remotes.`, 94 Advanced: true, 95 }, { 96 Name: "show_mapping", 97 Help: `For all files listed show how the names encrypt. 98 99 If this flag is set then for each file that the remote is asked to 100 list, it will log (at level INFO) a line stating the decrypted file 101 name and the encrypted file name. 102 103 This is so you can work out which encrypted names are which decrypted 104 names just in case you need to do something with the encrypted file 105 names, or for debugging purposes.`, 106 Default: false, 107 Hide: fs.OptionHideConfigurator, 108 Advanced: true, 109 }, { 110 Name: "no_data_encryption", 111 Help: "Option to either encrypt file data or leave it unencrypted.", 112 Default: false, 113 Advanced: true, 114 Examples: []fs.OptionExample{ 115 { 116 Value: "true", 117 Help: "Don't encrypt file data, leave it unencrypted.", 118 }, 119 { 120 Value: "false", 121 Help: "Encrypt file data.", 122 }, 123 }, 124 }, { 125 Name: "pass_bad_blocks", 126 Help: `If set this will pass bad blocks through as all 0. 127 128 This should not be set in normal operation, it should only be set if 129 trying to recover an encrypted file with errors and it is desired to 130 recover as much of the file as possible.`, 131 Default: false, 132 Advanced: true, 133 }, { 134 Name: "strict_names", 135 Help: `If set, this will raise an error when crypt comes across a filename that can't be decrypted. 136 137 (By default, rclone will just log a NOTICE and continue as normal.) 138 This can happen if encrypted and unencrypted files are stored in the same 139 directory (which is not recommended.) It may also indicate a more serious 140 problem that should be investigated.`, 141 Default: false, 142 Advanced: true, 143 }, { 144 Name: "filename_encoding", 145 Help: `How to encode the encrypted filename to text string. 146 147 This option could help with shortening the encrypted filename. The 148 suitable option would depend on the way your remote count the filename 149 length and if it's case sensitive.`, 150 Default: "base32", 151 Examples: []fs.OptionExample{ 152 { 153 Value: "base32", 154 Help: "Encode using base32. Suitable for all remote.", 155 }, 156 { 157 Value: "base64", 158 Help: "Encode using base64. Suitable for case sensitive remote.", 159 }, 160 { 161 Value: "base32768", 162 Help: "Encode using base32768. Suitable if your remote counts UTF-16 or\nUnicode codepoint instead of UTF-8 byte length. (Eg. Onedrive, Dropbox)", 163 }, 164 }, 165 Advanced: true, 166 }, { 167 Name: "suffix", 168 Help: `If this is set it will override the default suffix of ".bin". 169 170 Setting suffix to "none" will result in an empty suffix. This may be useful 171 when the path length is critical.`, 172 Default: ".bin", 173 Advanced: true, 174 }}, 175 }) 176 } 177 178 // newCipherForConfig constructs a Cipher for the given config name 179 func newCipherForConfig(opt *Options) (*Cipher, error) { 180 mode, err := NewNameEncryptionMode(opt.FilenameEncryption) 181 if err != nil { 182 return nil, err 183 } 184 if opt.Password == "" { 185 return nil, errors.New("password not set in config file") 186 } 187 password, err := obscure.Reveal(opt.Password) 188 if err != nil { 189 return nil, fmt.Errorf("failed to decrypt password: %w", err) 190 } 191 var salt string 192 if opt.Password2 != "" { 193 salt, err = obscure.Reveal(opt.Password2) 194 if err != nil { 195 return nil, fmt.Errorf("failed to decrypt password2: %w", err) 196 } 197 } 198 enc, err := NewNameEncoding(opt.FilenameEncoding) 199 if err != nil { 200 return nil, err 201 } 202 cipher, err := newCipher(mode, password, salt, opt.DirectoryNameEncryption, enc) 203 if err != nil { 204 return nil, fmt.Errorf("failed to make cipher: %w", err) 205 } 206 cipher.setEncryptedSuffix(opt.Suffix) 207 cipher.setPassBadBlocks(opt.PassBadBlocks) 208 return cipher, nil 209 } 210 211 // NewCipher constructs a Cipher for the given config 212 func NewCipher(m configmap.Mapper) (*Cipher, error) { 213 // Parse config into Options struct 214 opt := new(Options) 215 err := configstruct.Set(m, opt) 216 if err != nil { 217 return nil, err 218 } 219 return newCipherForConfig(opt) 220 } 221 222 // NewFs constructs an Fs from the path, container:path 223 func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs, error) { 224 // Parse config into Options struct 225 opt := new(Options) 226 err := configstruct.Set(m, opt) 227 if err != nil { 228 return nil, err 229 } 230 cipher, err := newCipherForConfig(opt) 231 if err != nil { 232 return nil, err 233 } 234 remote := opt.Remote 235 if strings.HasPrefix(remote, name+":") { 236 return nil, errors.New("can't point crypt remote at itself - check the value of the remote setting") 237 } 238 // Make sure to remove trailing . referring to the current dir 239 if path.Base(rpath) == "." { 240 rpath = strings.TrimSuffix(rpath, ".") 241 } 242 // Look for a file first 243 var wrappedFs fs.Fs 244 if rpath == "" { 245 wrappedFs, err = cache.Get(ctx, remote) 246 } else { 247 remotePath := fspath.JoinRootPath(remote, cipher.EncryptFileName(rpath)) 248 wrappedFs, err = cache.Get(ctx, remotePath) 249 // if that didn't produce a file, look for a directory 250 if err != fs.ErrorIsFile { 251 remotePath = fspath.JoinRootPath(remote, cipher.EncryptDirName(rpath)) 252 wrappedFs, err = cache.Get(ctx, remotePath) 253 } 254 } 255 if err != fs.ErrorIsFile && err != nil { 256 return nil, fmt.Errorf("failed to make remote %q to wrap: %w", remote, err) 257 } 258 f := &Fs{ 259 Fs: wrappedFs, 260 name: name, 261 root: rpath, 262 opt: *opt, 263 cipher: cipher, 264 } 265 cache.PinUntilFinalized(f.Fs, f) 266 // Correct root if definitely pointing to a file 267 if err == fs.ErrorIsFile { 268 f.root = path.Dir(f.root) 269 if f.root == "." || f.root == "/" { 270 f.root = "" 271 } 272 } 273 // the features here are ones we could support, and they are 274 // ANDed with the ones from wrappedFs 275 f.features = (&fs.Features{ 276 CaseInsensitive: !cipher.dirNameEncrypt || cipher.NameEncryptionMode() == NameEncryptionOff, 277 DuplicateFiles: true, 278 ReadMimeType: false, // MimeTypes not supported with crypt 279 WriteMimeType: false, 280 BucketBased: true, 281 CanHaveEmptyDirectories: true, 282 SetTier: true, 283 GetTier: true, 284 ServerSideAcrossConfigs: opt.ServerSideAcrossConfigs, 285 ReadMetadata: true, 286 WriteMetadata: true, 287 UserMetadata: true, 288 ReadDirMetadata: true, 289 WriteDirMetadata: true, 290 WriteDirSetModTime: true, 291 UserDirMetadata: true, 292 DirModTimeUpdatesOnWrite: true, 293 PartialUploads: true, 294 }).Fill(ctx, f).Mask(ctx, wrappedFs).WrapsFs(f, wrappedFs) 295 296 return f, err 297 } 298 299 // Options defines the configuration for this backend 300 type Options struct { 301 Remote string `config:"remote"` 302 FilenameEncryption string `config:"filename_encryption"` 303 DirectoryNameEncryption bool `config:"directory_name_encryption"` 304 NoDataEncryption bool `config:"no_data_encryption"` 305 Password string `config:"password"` 306 Password2 string `config:"password2"` 307 ServerSideAcrossConfigs bool `config:"server_side_across_configs"` 308 ShowMapping bool `config:"show_mapping"` 309 PassBadBlocks bool `config:"pass_bad_blocks"` 310 FilenameEncoding string `config:"filename_encoding"` 311 Suffix string `config:"suffix"` 312 StrictNames bool `config:"strict_names"` 313 } 314 315 // Fs represents a wrapped fs.Fs 316 type Fs struct { 317 fs.Fs 318 wrapper fs.Fs 319 name string 320 root string 321 opt Options 322 features *fs.Features // optional features 323 cipher *Cipher 324 } 325 326 // Name of the remote (as passed into NewFs) 327 func (f *Fs) Name() string { 328 return f.name 329 } 330 331 // Root of the remote (as passed into NewFs) 332 func (f *Fs) Root() string { 333 return f.root 334 } 335 336 // Features returns the optional features of this Fs 337 func (f *Fs) Features() *fs.Features { 338 return f.features 339 } 340 341 // String returns a description of the FS 342 func (f *Fs) String() string { 343 return fmt.Sprintf("Encrypted drive '%s:%s'", f.name, f.root) 344 } 345 346 // Encrypt an object file name to entries. 347 func (f *Fs) add(entries *fs.DirEntries, obj fs.Object) error { 348 remote := obj.Remote() 349 decryptedRemote, err := f.cipher.DecryptFileName(remote) 350 if err != nil { 351 if f.opt.StrictNames { 352 return fmt.Errorf("%s: undecryptable file name detected: %v", remote, err) 353 } 354 fs.Logf(remote, "Skipping undecryptable file name: %v", err) 355 return nil 356 } 357 if f.opt.ShowMapping { 358 fs.Logf(decryptedRemote, "Encrypts to %q", remote) 359 } 360 *entries = append(*entries, f.newObject(obj)) 361 return nil 362 } 363 364 // Encrypt a directory file name to entries. 365 func (f *Fs) addDir(ctx context.Context, entries *fs.DirEntries, dir fs.Directory) error { 366 remote := dir.Remote() 367 decryptedRemote, err := f.cipher.DecryptDirName(remote) 368 if err != nil { 369 if f.opt.StrictNames { 370 return fmt.Errorf("%s: undecryptable dir name detected: %v", remote, err) 371 } 372 fs.Logf(remote, "Skipping undecryptable dir name: %v", err) 373 return nil 374 } 375 if f.opt.ShowMapping { 376 fs.Logf(decryptedRemote, "Encrypts to %q", remote) 377 } 378 *entries = append(*entries, f.newDir(ctx, dir)) 379 return nil 380 } 381 382 // Encrypt some directory entries. This alters entries returning it as newEntries. 383 func (f *Fs) encryptEntries(ctx context.Context, entries fs.DirEntries) (newEntries fs.DirEntries, err error) { 384 newEntries = entries[:0] // in place filter 385 errors := 0 386 var firsterr error 387 for _, entry := range entries { 388 switch x := entry.(type) { 389 case fs.Object: 390 err = f.add(&newEntries, x) 391 case fs.Directory: 392 err = f.addDir(ctx, &newEntries, x) 393 default: 394 return nil, fmt.Errorf("unknown object type %T", entry) 395 } 396 if err != nil { 397 errors++ 398 if firsterr == nil { 399 firsterr = err 400 } 401 } 402 } 403 if firsterr != nil { 404 return nil, fmt.Errorf("there were %v undecryptable name errors. first error: %v", errors, firsterr) 405 } 406 return newEntries, nil 407 } 408 409 // List the objects and directories in dir into entries. The 410 // entries can be returned in any order but should be for a 411 // complete directory. 412 // 413 // dir should be "" to list the root, and should not have 414 // trailing slashes. 415 // 416 // This should return ErrDirNotFound if the directory isn't 417 // found. 418 func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) { 419 entries, err = f.Fs.List(ctx, f.cipher.EncryptDirName(dir)) 420 if err != nil { 421 return nil, err 422 } 423 return f.encryptEntries(ctx, entries) 424 } 425 426 // ListR lists the objects and directories of the Fs starting 427 // from dir recursively into out. 428 // 429 // dir should be "" to start from the root, and should not 430 // have trailing slashes. 431 // 432 // This should return ErrDirNotFound if the directory isn't 433 // found. 434 // 435 // It should call callback for each tranche of entries read. 436 // These need not be returned in any particular order. If 437 // callback returns an error then the listing will stop 438 // immediately. 439 // 440 // Don't implement this unless you have a more efficient way 441 // of listing recursively that doing a directory traversal. 442 func (f *Fs) ListR(ctx context.Context, dir string, callback fs.ListRCallback) (err error) { 443 return f.Fs.Features().ListR(ctx, f.cipher.EncryptDirName(dir), func(entries fs.DirEntries) error { 444 newEntries, err := f.encryptEntries(ctx, entries) 445 if err != nil { 446 return err 447 } 448 return callback(newEntries) 449 }) 450 } 451 452 // NewObject finds the Object at remote. 453 func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) { 454 o, err := f.Fs.NewObject(ctx, f.cipher.EncryptFileName(remote)) 455 if err != nil { 456 return nil, err 457 } 458 return f.newObject(o), nil 459 } 460 461 type putFn func(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) 462 463 // put implements Put or PutStream 464 func (f *Fs) put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption, put putFn) (fs.Object, error) { 465 ci := fs.GetConfig(ctx) 466 467 if f.opt.NoDataEncryption { 468 o, err := put(ctx, in, f.newObjectInfo(src, nonce{}), options...) 469 if err == nil && o != nil { 470 o = f.newObject(o) 471 } 472 return o, err 473 } 474 475 // Encrypt the data into wrappedIn 476 wrappedIn, encrypter, err := f.cipher.encryptData(in) 477 if err != nil { 478 return nil, err 479 } 480 481 // Find a hash the destination supports to compute a hash of 482 // the encrypted data 483 ht := f.Fs.Hashes().GetOne() 484 if ci.IgnoreChecksum { 485 ht = hash.None 486 } 487 var hasher *hash.MultiHasher 488 if ht != hash.None { 489 hasher, err = hash.NewMultiHasherTypes(hash.NewHashSet(ht)) 490 if err != nil { 491 return nil, err 492 } 493 // unwrap the accounting 494 var wrap accounting.WrapFn 495 wrappedIn, wrap = accounting.UnWrap(wrappedIn) 496 // add the hasher 497 wrappedIn = io.TeeReader(wrappedIn, hasher) 498 // wrap the accounting back on 499 wrappedIn = wrap(wrappedIn) 500 } 501 502 // Transfer the data 503 o, err := put(ctx, wrappedIn, f.newObjectInfo(src, encrypter.nonce), options...) 504 if err != nil { 505 return nil, err 506 } 507 508 // Check the hashes of the encrypted data if we were comparing them 509 if ht != hash.None && hasher != nil { 510 srcHash := hasher.Sums()[ht] 511 var dstHash string 512 dstHash, err = o.Hash(ctx, ht) 513 if err != nil { 514 return nil, fmt.Errorf("failed to read destination hash: %w", err) 515 } 516 if srcHash != "" && dstHash != "" { 517 if srcHash != dstHash { 518 // remove object 519 err = o.Remove(ctx) 520 if err != nil { 521 fs.Errorf(o, "Failed to remove corrupted object: %v", err) 522 } 523 return nil, fmt.Errorf("corrupted on transfer: %v encrypted hashes differ src(%s) %q vs dst(%s) %q", ht, f.Fs, srcHash, o.Fs(), dstHash) 524 } 525 fs.Debugf(src, "%v = %s OK", ht, srcHash) 526 } 527 } 528 529 return f.newObject(o), nil 530 } 531 532 // Put in to the remote path with the modTime given of the given size 533 // 534 // May create the object even if it returns an error - if so 535 // will return the object and the error, otherwise will return 536 // nil and the error 537 func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 538 return f.put(ctx, in, src, options, f.Fs.Put) 539 } 540 541 // PutStream uploads to the remote path with the modTime given of indeterminate size 542 func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 543 return f.put(ctx, in, src, options, f.Fs.Features().PutStream) 544 } 545 546 // Hashes returns the supported hash sets. 547 func (f *Fs) Hashes() hash.Set { 548 return hash.Set(hash.None) 549 } 550 551 // Mkdir makes the directory (container, bucket) 552 // 553 // Shouldn't return an error if it already exists 554 func (f *Fs) Mkdir(ctx context.Context, dir string) error { 555 return f.Fs.Mkdir(ctx, f.cipher.EncryptDirName(dir)) 556 } 557 558 // MkdirMetadata makes the root directory of the Fs object 559 func (f *Fs) MkdirMetadata(ctx context.Context, dir string, metadata fs.Metadata) (fs.Directory, error) { 560 do := f.Fs.Features().MkdirMetadata 561 if do == nil { 562 return nil, fs.ErrorNotImplemented 563 } 564 newDir, err := do(ctx, f.cipher.EncryptDirName(dir), metadata) 565 if err != nil { 566 return nil, err 567 } 568 var entries = make(fs.DirEntries, 0, 1) 569 err = f.addDir(ctx, &entries, newDir) 570 if err != nil { 571 return nil, err 572 } 573 newDir, ok := entries[0].(fs.Directory) 574 if !ok { 575 return nil, fmt.Errorf("internal error: expecting %T to be fs.Directory", entries[0]) 576 } 577 return newDir, nil 578 } 579 580 // DirSetModTime sets the directory modtime for dir 581 func (f *Fs) DirSetModTime(ctx context.Context, dir string, modTime time.Time) error { 582 do := f.Fs.Features().DirSetModTime 583 if do == nil { 584 return fs.ErrorNotImplemented 585 } 586 return do(ctx, f.cipher.EncryptDirName(dir), modTime) 587 } 588 589 // Rmdir removes the directory (container, bucket) if empty 590 // 591 // Return an error if it doesn't exist or isn't empty 592 func (f *Fs) Rmdir(ctx context.Context, dir string) error { 593 return f.Fs.Rmdir(ctx, f.cipher.EncryptDirName(dir)) 594 } 595 596 // Purge all files in the directory specified 597 // 598 // Implement this if you have a way of deleting all the files 599 // quicker than just running Remove() on the result of List() 600 // 601 // Return an error if it doesn't exist 602 func (f *Fs) Purge(ctx context.Context, dir string) error { 603 do := f.Fs.Features().Purge 604 if do == nil { 605 return fs.ErrorCantPurge 606 } 607 return do(ctx, f.cipher.EncryptDirName(dir)) 608 } 609 610 // Copy src to this remote using server-side copy operations. 611 // 612 // This is stored with the remote path given. 613 // 614 // It returns the destination Object and a possible error. 615 // 616 // Will only be called if src.Fs().Name() == f.Name() 617 // 618 // If it isn't possible then return fs.ErrorCantCopy 619 func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { 620 do := f.Fs.Features().Copy 621 if do == nil { 622 return nil, fs.ErrorCantCopy 623 } 624 o, ok := src.(*Object) 625 if !ok { 626 return nil, fs.ErrorCantCopy 627 } 628 oResult, err := do(ctx, o.Object, f.cipher.EncryptFileName(remote)) 629 if err != nil { 630 return nil, err 631 } 632 return f.newObject(oResult), nil 633 } 634 635 // Move src to this remote using server-side move operations. 636 // 637 // This is stored with the remote path given. 638 // 639 // It returns the destination Object and a possible error. 640 // 641 // Will only be called if src.Fs().Name() == f.Name() 642 // 643 // If it isn't possible then return fs.ErrorCantMove 644 func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { 645 do := f.Fs.Features().Move 646 if do == nil { 647 return nil, fs.ErrorCantMove 648 } 649 o, ok := src.(*Object) 650 if !ok { 651 return nil, fs.ErrorCantMove 652 } 653 oResult, err := do(ctx, o.Object, f.cipher.EncryptFileName(remote)) 654 if err != nil { 655 return nil, err 656 } 657 return f.newObject(oResult), nil 658 } 659 660 // DirMove moves src, srcRemote to this remote at dstRemote 661 // using server-side move operations. 662 // 663 // Will only be called if src.Fs().Name() == f.Name() 664 // 665 // If it isn't possible then return fs.ErrorCantDirMove 666 // 667 // If destination exists then return fs.ErrorDirExists 668 func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) error { 669 do := f.Fs.Features().DirMove 670 if do == nil { 671 return fs.ErrorCantDirMove 672 } 673 srcFs, ok := src.(*Fs) 674 if !ok { 675 fs.Debugf(srcFs, "Can't move directory - not same remote type") 676 return fs.ErrorCantDirMove 677 } 678 return do(ctx, srcFs.Fs, f.cipher.EncryptDirName(srcRemote), f.cipher.EncryptDirName(dstRemote)) 679 } 680 681 // PutUnchecked uploads the object 682 // 683 // This will create a duplicate if we upload a new file without 684 // checking to see if there is one already - use Put() for that. 685 func (f *Fs) PutUnchecked(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 686 do := f.Fs.Features().PutUnchecked 687 if do == nil { 688 return nil, errors.New("can't PutUnchecked") 689 } 690 wrappedIn, encrypter, err := f.cipher.encryptData(in) 691 if err != nil { 692 return nil, err 693 } 694 o, err := do(ctx, wrappedIn, f.newObjectInfo(src, encrypter.nonce)) 695 if err != nil { 696 return nil, err 697 } 698 return f.newObject(o), nil 699 } 700 701 // CleanUp the trash in the Fs 702 // 703 // Implement this if you have a way of emptying the trash or 704 // otherwise cleaning up old versions of files. 705 func (f *Fs) CleanUp(ctx context.Context) error { 706 do := f.Fs.Features().CleanUp 707 if do == nil { 708 return errors.New("not supported by underlying remote") 709 } 710 return do(ctx) 711 } 712 713 // About gets quota information from the Fs 714 func (f *Fs) About(ctx context.Context) (*fs.Usage, error) { 715 do := f.Fs.Features().About 716 if do == nil { 717 return nil, errors.New("not supported by underlying remote") 718 } 719 return do(ctx) 720 } 721 722 // UnWrap returns the Fs that this Fs is wrapping 723 func (f *Fs) UnWrap() fs.Fs { 724 return f.Fs 725 } 726 727 // WrapFs returns the Fs that is wrapping this Fs 728 func (f *Fs) WrapFs() fs.Fs { 729 return f.wrapper 730 } 731 732 // SetWrapper sets the Fs that is wrapping this Fs 733 func (f *Fs) SetWrapper(wrapper fs.Fs) { 734 f.wrapper = wrapper 735 } 736 737 // EncryptFileName returns an encrypted file name 738 func (f *Fs) EncryptFileName(fileName string) string { 739 return f.cipher.EncryptFileName(fileName) 740 } 741 742 // DecryptFileName returns a decrypted file name 743 func (f *Fs) DecryptFileName(encryptedFileName string) (string, error) { 744 return f.cipher.DecryptFileName(encryptedFileName) 745 } 746 747 // computeHashWithNonce takes the nonce and encrypts the contents of 748 // src with it, and calculates the hash given by HashType on the fly 749 // 750 // Note that we break lots of encapsulation in this function. 751 func (f *Fs) computeHashWithNonce(ctx context.Context, nonce nonce, src fs.Object, hashType hash.Type) (hashStr string, err error) { 752 // Open the src for input 753 in, err := src.Open(ctx) 754 if err != nil { 755 return "", fmt.Errorf("failed to open src: %w", err) 756 } 757 defer fs.CheckClose(in, &err) 758 759 // Now encrypt the src with the nonce 760 out, err := f.cipher.newEncrypter(in, &nonce) 761 if err != nil { 762 return "", fmt.Errorf("failed to make encrypter: %w", err) 763 } 764 765 // pipe into hash 766 m, err := hash.NewMultiHasherTypes(hash.NewHashSet(hashType)) 767 if err != nil { 768 return "", fmt.Errorf("failed to make hasher: %w", err) 769 } 770 _, err = io.Copy(m, out) 771 if err != nil { 772 return "", fmt.Errorf("failed to hash data: %w", err) 773 } 774 775 return m.Sums()[hashType], nil 776 } 777 778 // ComputeHash takes the nonce from o, and encrypts the contents of 779 // src with it, and calculates the hash given by HashType on the fly 780 // 781 // Note that we break lots of encapsulation in this function. 782 func (f *Fs) ComputeHash(ctx context.Context, o *Object, src fs.Object, hashType hash.Type) (hashStr string, err error) { 783 if f.opt.NoDataEncryption { 784 return src.Hash(ctx, hashType) 785 } 786 787 // Read the nonce - opening the file is sufficient to read the nonce in 788 // use a limited read so we only read the header 789 in, err := o.Object.Open(ctx, &fs.RangeOption{Start: 0, End: int64(fileHeaderSize) - 1}) 790 if err != nil { 791 return "", fmt.Errorf("failed to open object to read nonce: %w", err) 792 } 793 d, err := f.cipher.newDecrypter(in) 794 if err != nil { 795 _ = in.Close() 796 return "", fmt.Errorf("failed to open object to read nonce: %w", err) 797 } 798 nonce := d.nonce 799 // fs.Debugf(o, "Read nonce % 2x", nonce) 800 801 // Check nonce isn't all zeros 802 isZero := true 803 for i := range nonce { 804 if nonce[i] != 0 { 805 isZero = false 806 } 807 } 808 if isZero { 809 fs.Errorf(o, "empty nonce read") 810 } 811 812 // Close d (and hence in) once we have read the nonce 813 err = d.Close() 814 if err != nil { 815 return "", fmt.Errorf("failed to close nonce read: %w", err) 816 } 817 818 return f.computeHashWithNonce(ctx, nonce, src, hashType) 819 } 820 821 // MergeDirs merges the contents of all the directories passed 822 // in into the first one and rmdirs the other directories. 823 func (f *Fs) MergeDirs(ctx context.Context, dirs []fs.Directory) error { 824 do := f.Fs.Features().MergeDirs 825 if do == nil { 826 return errors.New("MergeDirs not supported") 827 } 828 out := make([]fs.Directory, len(dirs)) 829 for i, dir := range dirs { 830 out[i] = fs.NewDirWrapper(f.cipher.EncryptDirName(dir.Remote()), dir) 831 } 832 return do(ctx, out) 833 } 834 835 // DirCacheFlush resets the directory cache - used in testing 836 // as an optional interface 837 func (f *Fs) DirCacheFlush() { 838 do := f.Fs.Features().DirCacheFlush 839 if do != nil { 840 do() 841 } 842 } 843 844 // PublicLink generates a public link to the remote path (usually readable by anyone) 845 func (f *Fs) PublicLink(ctx context.Context, remote string, expire fs.Duration, unlink bool) (string, error) { 846 do := f.Fs.Features().PublicLink 847 if do == nil { 848 return "", errors.New("PublicLink not supported") 849 } 850 o, err := f.NewObject(ctx, remote) 851 if err != nil { 852 // assume it is a directory 853 return do(ctx, f.cipher.EncryptDirName(remote), expire, unlink) 854 } 855 return do(ctx, o.(*Object).Object.Remote(), expire, unlink) 856 } 857 858 // ChangeNotify calls the passed function with a path 859 // that has had changes. If the implementation 860 // uses polling, it should adhere to the given interval. 861 func (f *Fs) ChangeNotify(ctx context.Context, notifyFunc func(string, fs.EntryType), pollIntervalChan <-chan time.Duration) { 862 do := f.Fs.Features().ChangeNotify 863 if do == nil { 864 return 865 } 866 wrappedNotifyFunc := func(path string, entryType fs.EntryType) { 867 // fs.Debugf(f, "ChangeNotify: path %q entryType %d", path, entryType) 868 var ( 869 err error 870 decrypted string 871 ) 872 switch entryType { 873 case fs.EntryDirectory: 874 decrypted, err = f.cipher.DecryptDirName(path) 875 case fs.EntryObject: 876 decrypted, err = f.cipher.DecryptFileName(path) 877 default: 878 fs.Errorf(path, "crypt ChangeNotify: ignoring unknown EntryType %d", entryType) 879 return 880 } 881 if err != nil { 882 fs.Logf(f, "ChangeNotify was unable to decrypt %q: %s", path, err) 883 return 884 } 885 notifyFunc(decrypted, entryType) 886 } 887 do(ctx, wrappedNotifyFunc, pollIntervalChan) 888 } 889 890 var commandHelp = []fs.CommandHelp{ 891 { 892 Name: "encode", 893 Short: "Encode the given filename(s)", 894 Long: `This encodes the filenames given as arguments returning a list of 895 strings of the encoded results. 896 897 Usage Example: 898 899 rclone backend encode crypt: file1 [file2...] 900 rclone rc backend/command command=encode fs=crypt: file1 [file2...] 901 `, 902 }, 903 { 904 Name: "decode", 905 Short: "Decode the given filename(s)", 906 Long: `This decodes the filenames given as arguments returning a list of 907 strings of the decoded results. It will return an error if any of the 908 inputs are invalid. 909 910 Usage Example: 911 912 rclone backend decode crypt: encryptedfile1 [encryptedfile2...] 913 rclone rc backend/command command=decode fs=crypt: encryptedfile1 [encryptedfile2...] 914 `, 915 }, 916 } 917 918 // Command the backend to run a named command 919 // 920 // The command run is name 921 // args may be used to read arguments from 922 // opts may be used to read optional arguments from 923 // 924 // The result should be capable of being JSON encoded 925 // If it is a string or a []string it will be shown to the user 926 // otherwise it will be JSON encoded and shown to the user like that 927 func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[string]string) (out interface{}, err error) { 928 switch name { 929 case "decode": 930 out := make([]string, 0, len(arg)) 931 for _, encryptedFileName := range arg { 932 fileName, err := f.DecryptFileName(encryptedFileName) 933 if err != nil { 934 return out, fmt.Errorf("failed to decrypt: %s: %w", encryptedFileName, err) 935 } 936 out = append(out, fileName) 937 } 938 return out, nil 939 case "encode": 940 out := make([]string, 0, len(arg)) 941 for _, fileName := range arg { 942 encryptedFileName := f.EncryptFileName(fileName) 943 out = append(out, encryptedFileName) 944 } 945 return out, nil 946 default: 947 return nil, fs.ErrorCommandNotFound 948 } 949 } 950 951 // Object describes a wrapped for being read from the Fs 952 // 953 // This decrypts the remote name and decrypts the data 954 type Object struct { 955 fs.Object 956 f *Fs 957 } 958 959 func (f *Fs) newObject(o fs.Object) *Object { 960 return &Object{ 961 Object: o, 962 f: f, 963 } 964 } 965 966 // Fs returns read only access to the Fs that this object is part of 967 func (o *Object) Fs() fs.Info { 968 return o.f 969 } 970 971 // Return a string version 972 func (o *Object) String() string { 973 if o == nil { 974 return "<nil>" 975 } 976 return o.Remote() 977 } 978 979 // Remote returns the remote path 980 func (o *Object) Remote() string { 981 remote := o.Object.Remote() 982 decryptedName, err := o.f.cipher.DecryptFileName(remote) 983 if err != nil { 984 fs.Debugf(remote, "Undecryptable file name: %v", err) 985 return remote 986 } 987 return decryptedName 988 } 989 990 // Size returns the size of the file 991 func (o *Object) Size() int64 { 992 size := o.Object.Size() 993 if !o.f.opt.NoDataEncryption { 994 var err error 995 size, err = o.f.cipher.DecryptedSize(size) 996 if err != nil { 997 fs.Debugf(o, "Bad size for decrypt: %v", err) 998 } 999 } 1000 return size 1001 } 1002 1003 // Hash returns the selected checksum of the file 1004 // If no checksum is available it returns "" 1005 func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) { 1006 return "", hash.ErrUnsupported 1007 } 1008 1009 // UnWrap returns the wrapped Object 1010 func (o *Object) UnWrap() fs.Object { 1011 return o.Object 1012 } 1013 1014 // Open opens the file for read. Call Close() on the returned io.ReadCloser 1015 func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (rc io.ReadCloser, err error) { 1016 if o.f.opt.NoDataEncryption { 1017 return o.Object.Open(ctx, options...) 1018 } 1019 1020 var openOptions []fs.OpenOption 1021 var offset, limit int64 = 0, -1 1022 for _, option := range options { 1023 switch x := option.(type) { 1024 case *fs.SeekOption: 1025 offset = x.Offset 1026 case *fs.RangeOption: 1027 offset, limit = x.Decode(o.Size()) 1028 default: 1029 // pass on Options to underlying open if appropriate 1030 openOptions = append(openOptions, option) 1031 } 1032 } 1033 rc, err = o.f.cipher.DecryptDataSeek(ctx, func(ctx context.Context, underlyingOffset, underlyingLimit int64) (io.ReadCloser, error) { 1034 if underlyingOffset == 0 && underlyingLimit < 0 { 1035 // Open with no seek 1036 return o.Object.Open(ctx, openOptions...) 1037 } 1038 // Open stream with a range of underlyingOffset, underlyingLimit 1039 end := int64(-1) 1040 if underlyingLimit >= 0 { 1041 end = underlyingOffset + underlyingLimit - 1 1042 if end >= o.Object.Size() { 1043 end = -1 1044 } 1045 } 1046 newOpenOptions := append(openOptions, &fs.RangeOption{Start: underlyingOffset, End: end}) 1047 return o.Object.Open(ctx, newOpenOptions...) 1048 }, offset, limit) 1049 if err != nil { 1050 return nil, err 1051 } 1052 return rc, nil 1053 } 1054 1055 // Update in to the object with the modTime given of the given size 1056 func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error { 1057 update := func(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 1058 return o.Object, o.Object.Update(ctx, in, src, options...) 1059 } 1060 _, err := o.f.put(ctx, in, src, options, update) 1061 return err 1062 } 1063 1064 // newDir returns a dir with the Name decrypted 1065 func (f *Fs) newDir(ctx context.Context, dir fs.Directory) fs.Directory { 1066 remote := dir.Remote() 1067 decryptedRemote, err := f.cipher.DecryptDirName(remote) 1068 if err != nil { 1069 fs.Debugf(remote, "Undecryptable dir name: %v", err) 1070 } else { 1071 remote = decryptedRemote 1072 } 1073 newDir := fs.NewDirWrapper(remote, dir) 1074 return newDir 1075 } 1076 1077 // UserInfo returns info about the connected user 1078 func (f *Fs) UserInfo(ctx context.Context) (map[string]string, error) { 1079 do := f.Fs.Features().UserInfo 1080 if do == nil { 1081 return nil, fs.ErrorNotImplemented 1082 } 1083 return do(ctx) 1084 } 1085 1086 // Disconnect the current user 1087 func (f *Fs) Disconnect(ctx context.Context) error { 1088 do := f.Fs.Features().Disconnect 1089 if do == nil { 1090 return fs.ErrorNotImplemented 1091 } 1092 return do(ctx) 1093 } 1094 1095 // Shutdown the backend, closing any background tasks and any 1096 // cached connections. 1097 func (f *Fs) Shutdown(ctx context.Context) error { 1098 do := f.Fs.Features().Shutdown 1099 if do == nil { 1100 return nil 1101 } 1102 return do(ctx) 1103 } 1104 1105 // ObjectInfo describes a wrapped fs.ObjectInfo for being the source 1106 // 1107 // This encrypts the remote name and adjusts the size 1108 type ObjectInfo struct { 1109 fs.ObjectInfo 1110 f *Fs 1111 nonce nonce 1112 } 1113 1114 func (f *Fs) newObjectInfo(src fs.ObjectInfo, nonce nonce) *ObjectInfo { 1115 return &ObjectInfo{ 1116 ObjectInfo: src, 1117 f: f, 1118 nonce: nonce, 1119 } 1120 } 1121 1122 // Fs returns read only access to the Fs that this object is part of 1123 func (o *ObjectInfo) Fs() fs.Info { 1124 return o.f 1125 } 1126 1127 // Remote returns the remote path 1128 func (o *ObjectInfo) Remote() string { 1129 return o.f.cipher.EncryptFileName(o.ObjectInfo.Remote()) 1130 } 1131 1132 // Size returns the size of the file 1133 func (o *ObjectInfo) Size() int64 { 1134 size := o.ObjectInfo.Size() 1135 if size < 0 { 1136 return size 1137 } 1138 if o.f.opt.NoDataEncryption { 1139 return size 1140 } 1141 return o.f.cipher.EncryptedSize(size) 1142 } 1143 1144 // Hash returns the selected checksum of the file 1145 // If no checksum is available it returns "" 1146 func (o *ObjectInfo) Hash(ctx context.Context, hash hash.Type) (string, error) { 1147 var srcObj fs.Object 1148 var ok bool 1149 // Get the underlying object if there is one 1150 if srcObj, ok = o.ObjectInfo.(fs.Object); ok { 1151 // Prefer direct interface assertion 1152 } else if do, ok := o.ObjectInfo.(*fs.OverrideRemote); ok { 1153 // Unwrap if it is an operations.OverrideRemote 1154 srcObj = do.UnWrap() 1155 } else { 1156 // Otherwise don't unwrap any further 1157 return "", nil 1158 } 1159 // if this is wrapping a local object then we work out the hash 1160 if srcObj.Fs().Features().IsLocal { 1161 // Read the data and encrypt it to calculate the hash 1162 fs.Debugf(o, "Computing %v hash of encrypted source", hash) 1163 return o.f.computeHashWithNonce(ctx, o.nonce, srcObj, hash) 1164 } 1165 return "", nil 1166 } 1167 1168 // GetTier returns storage tier or class of the Object 1169 func (o *ObjectInfo) GetTier() string { 1170 do, ok := o.ObjectInfo.(fs.GetTierer) 1171 if !ok { 1172 return "" 1173 } 1174 return do.GetTier() 1175 } 1176 1177 // ID returns the ID of the Object if known, or "" if not 1178 func (o *ObjectInfo) ID() string { 1179 do, ok := o.ObjectInfo.(fs.IDer) 1180 if !ok { 1181 return "" 1182 } 1183 return do.ID() 1184 } 1185 1186 // Metadata returns metadata for an object 1187 // 1188 // It should return nil if there is no Metadata 1189 func (o *ObjectInfo) Metadata(ctx context.Context) (fs.Metadata, error) { 1190 do, ok := o.ObjectInfo.(fs.Metadataer) 1191 if !ok { 1192 return nil, nil 1193 } 1194 return do.Metadata(ctx) 1195 } 1196 1197 // MimeType returns the content type of the Object if 1198 // known, or "" if not 1199 // 1200 // This is deliberately unsupported so we don't leak mime type info by 1201 // default. 1202 func (o *ObjectInfo) MimeType(ctx context.Context) string { 1203 return "" 1204 } 1205 1206 // UnWrap returns the Object that this Object is wrapping or 1207 // nil if it isn't wrapping anything 1208 func (o *ObjectInfo) UnWrap() fs.Object { 1209 return fs.UnWrapObjectInfo(o.ObjectInfo) 1210 } 1211 1212 // ID returns the ID of the Object if known, or "" if not 1213 func (o *Object) ID() string { 1214 do, ok := o.Object.(fs.IDer) 1215 if !ok { 1216 return "" 1217 } 1218 return do.ID() 1219 } 1220 1221 // SetTier performs changing storage tier of the Object if 1222 // multiple storage classes supported 1223 func (o *Object) SetTier(tier string) error { 1224 do, ok := o.Object.(fs.SetTierer) 1225 if !ok { 1226 return errors.New("crypt: underlying remote does not support SetTier") 1227 } 1228 return do.SetTier(tier) 1229 } 1230 1231 // GetTier returns storage tier or class of the Object 1232 func (o *Object) GetTier() string { 1233 do, ok := o.Object.(fs.GetTierer) 1234 if !ok { 1235 return "" 1236 } 1237 return do.GetTier() 1238 } 1239 1240 // Metadata returns metadata for an object 1241 // 1242 // It should return nil if there is no Metadata 1243 func (o *Object) Metadata(ctx context.Context) (fs.Metadata, error) { 1244 do, ok := o.Object.(fs.Metadataer) 1245 if !ok { 1246 return nil, nil 1247 } 1248 return do.Metadata(ctx) 1249 } 1250 1251 // MimeType returns the content type of the Object if 1252 // known, or "" if not 1253 // 1254 // This is deliberately unsupported so we don't leak mime type info by 1255 // default. 1256 func (o *Object) MimeType(ctx context.Context) string { 1257 return "" 1258 } 1259 1260 // Check the interfaces are satisfied 1261 var ( 1262 _ fs.Fs = (*Fs)(nil) 1263 _ fs.Purger = (*Fs)(nil) 1264 _ fs.Copier = (*Fs)(nil) 1265 _ fs.Mover = (*Fs)(nil) 1266 _ fs.DirMover = (*Fs)(nil) 1267 _ fs.Commander = (*Fs)(nil) 1268 _ fs.PutUncheckeder = (*Fs)(nil) 1269 _ fs.PutStreamer = (*Fs)(nil) 1270 _ fs.CleanUpper = (*Fs)(nil) 1271 _ fs.UnWrapper = (*Fs)(nil) 1272 _ fs.ListRer = (*Fs)(nil) 1273 _ fs.Abouter = (*Fs)(nil) 1274 _ fs.Wrapper = (*Fs)(nil) 1275 _ fs.MergeDirser = (*Fs)(nil) 1276 _ fs.DirSetModTimer = (*Fs)(nil) 1277 _ fs.MkdirMetadataer = (*Fs)(nil) 1278 _ fs.DirCacheFlusher = (*Fs)(nil) 1279 _ fs.ChangeNotifier = (*Fs)(nil) 1280 _ fs.PublicLinker = (*Fs)(nil) 1281 _ fs.UserInfoer = (*Fs)(nil) 1282 _ fs.Disconnecter = (*Fs)(nil) 1283 _ fs.Shutdowner = (*Fs)(nil) 1284 _ fs.FullObjectInfo = (*ObjectInfo)(nil) 1285 _ fs.FullObject = (*Object)(nil) 1286 )