github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/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 "fmt" 7 "io" 8 "path" 9 "strings" 10 "time" 11 12 "github.com/pkg/errors" 13 "github.com/rclone/rclone/fs" 14 "github.com/rclone/rclone/fs/accounting" 15 "github.com/rclone/rclone/fs/config/configmap" 16 "github.com/rclone/rclone/fs/config/configstruct" 17 "github.com/rclone/rclone/fs/config/obscure" 18 "github.com/rclone/rclone/fs/fspath" 19 "github.com/rclone/rclone/fs/hash" 20 ) 21 22 // Globals 23 // Register with Fs 24 func init() { 25 fs.Register(&fs.RegInfo{ 26 Name: "crypt", 27 Description: "Encrypt/Decrypt a remote", 28 NewFs: NewFs, 29 CommandHelp: commandHelp, 30 Options: []fs.Option{{ 31 Name: "remote", 32 Help: "Remote to encrypt/decrypt.\nNormally should contain a ':' and a path, eg \"myremote:path/to/dir\",\n\"myremote:bucket\" or maybe \"myremote:\" (not recommended).", 33 Required: true, 34 }, { 35 Name: "filename_encryption", 36 Help: "How to encrypt the filenames.", 37 Default: "standard", 38 Examples: []fs.OptionExample{ 39 { 40 Value: "standard", 41 Help: "Encrypt the filenames see the docs for the details.", 42 }, { 43 Value: "obfuscate", 44 Help: "Very simple filename obfuscation.", 45 }, { 46 Value: "off", 47 Help: "Don't encrypt the file names. Adds a \".bin\" extension only.", 48 }, 49 }, 50 }, { 51 Name: "directory_name_encryption", 52 Help: `Option to either encrypt directory names or leave them intact. 53 54 NB If filename_encryption is "off" then this option will do nothing.`, 55 Default: true, 56 Examples: []fs.OptionExample{ 57 { 58 Value: "true", 59 Help: "Encrypt directory names.", 60 }, 61 { 62 Value: "false", 63 Help: "Don't encrypt directory names, leave them intact.", 64 }, 65 }, 66 }, { 67 Name: "password", 68 Help: "Password or pass phrase for encryption.", 69 IsPassword: true, 70 Required: true, 71 }, { 72 Name: "password2", 73 Help: "Password or pass phrase for salt. Optional but recommended.\nShould be different to the previous password.", 74 IsPassword: true, 75 }, { 76 Name: "show_mapping", 77 Help: `For all files listed show how the names encrypt. 78 79 If this flag is set then for each file that the remote is asked to 80 list, it will log (at level INFO) a line stating the decrypted file 81 name and the encrypted file name. 82 83 This is so you can work out which encrypted names are which decrypted 84 names just in case you need to do something with the encrypted file 85 names, or for debugging purposes.`, 86 Default: false, 87 Hide: fs.OptionHideConfigurator, 88 Advanced: true, 89 }}, 90 }) 91 } 92 93 // newCipherForConfig constructs a Cipher for the given config name 94 func newCipherForConfig(opt *Options) (*Cipher, error) { 95 mode, err := NewNameEncryptionMode(opt.FilenameEncryption) 96 if err != nil { 97 return nil, err 98 } 99 if opt.Password == "" { 100 return nil, errors.New("password not set in config file") 101 } 102 password, err := obscure.Reveal(opt.Password) 103 if err != nil { 104 return nil, errors.Wrap(err, "failed to decrypt password") 105 } 106 var salt string 107 if opt.Password2 != "" { 108 salt, err = obscure.Reveal(opt.Password2) 109 if err != nil { 110 return nil, errors.Wrap(err, "failed to decrypt password2") 111 } 112 } 113 cipher, err := newCipher(mode, password, salt, opt.DirectoryNameEncryption) 114 if err != nil { 115 return nil, errors.Wrap(err, "failed to make cipher") 116 } 117 return cipher, nil 118 } 119 120 // NewCipher constructs a Cipher for the given config 121 func NewCipher(m configmap.Mapper) (*Cipher, error) { 122 // Parse config into Options struct 123 opt := new(Options) 124 err := configstruct.Set(m, opt) 125 if err != nil { 126 return nil, err 127 } 128 return newCipherForConfig(opt) 129 } 130 131 // NewFs constructs an Fs from the path, container:path 132 func NewFs(name, rpath string, m configmap.Mapper) (fs.Fs, error) { 133 // Parse config into Options struct 134 opt := new(Options) 135 err := configstruct.Set(m, opt) 136 if err != nil { 137 return nil, err 138 } 139 cipher, err := newCipherForConfig(opt) 140 if err != nil { 141 return nil, err 142 } 143 remote := opt.Remote 144 if strings.HasPrefix(remote, name+":") { 145 return nil, errors.New("can't point crypt remote at itself - check the value of the remote setting") 146 } 147 wInfo, wName, wPath, wConfig, err := fs.ConfigFs(remote) 148 if err != nil { 149 return nil, errors.Wrapf(err, "failed to parse remote %q to wrap", remote) 150 } 151 // Make sure to remove trailing . reffering to the current dir 152 if path.Base(rpath) == "." { 153 rpath = strings.TrimSuffix(rpath, ".") 154 } 155 // Look for a file first 156 remotePath := fspath.JoinRootPath(wPath, cipher.EncryptFileName(rpath)) 157 wrappedFs, err := wInfo.NewFs(wName, remotePath, wConfig) 158 // if that didn't produce a file, look for a directory 159 if err != fs.ErrorIsFile { 160 remotePath = fspath.JoinRootPath(wPath, cipher.EncryptDirName(rpath)) 161 wrappedFs, err = wInfo.NewFs(wName, remotePath, wConfig) 162 } 163 if err != fs.ErrorIsFile && err != nil { 164 return nil, errors.Wrapf(err, "failed to make remote %s:%q to wrap", wName, remotePath) 165 } 166 f := &Fs{ 167 Fs: wrappedFs, 168 name: name, 169 root: rpath, 170 opt: *opt, 171 cipher: cipher, 172 } 173 // the features here are ones we could support, and they are 174 // ANDed with the ones from wrappedFs 175 f.features = (&fs.Features{ 176 CaseInsensitive: cipher.NameEncryptionMode() == NameEncryptionOff, 177 DuplicateFiles: true, 178 ReadMimeType: false, // MimeTypes not supported with crypt 179 WriteMimeType: false, 180 BucketBased: true, 181 CanHaveEmptyDirectories: true, 182 SetTier: true, 183 GetTier: true, 184 }).Fill(f).Mask(wrappedFs).WrapsFs(f, wrappedFs) 185 186 return f, err 187 } 188 189 // Options defines the configuration for this backend 190 type Options struct { 191 Remote string `config:"remote"` 192 FilenameEncryption string `config:"filename_encryption"` 193 DirectoryNameEncryption bool `config:"directory_name_encryption"` 194 Password string `config:"password"` 195 Password2 string `config:"password2"` 196 ShowMapping bool `config:"show_mapping"` 197 } 198 199 // Fs represents a wrapped fs.Fs 200 type Fs struct { 201 fs.Fs 202 wrapper fs.Fs 203 name string 204 root string 205 opt Options 206 features *fs.Features // optional features 207 cipher *Cipher 208 } 209 210 // Name of the remote (as passed into NewFs) 211 func (f *Fs) Name() string { 212 return f.name 213 } 214 215 // Root of the remote (as passed into NewFs) 216 func (f *Fs) Root() string { 217 return f.root 218 } 219 220 // Features returns the optional features of this Fs 221 func (f *Fs) Features() *fs.Features { 222 return f.features 223 } 224 225 // String returns a description of the FS 226 func (f *Fs) String() string { 227 return fmt.Sprintf("Encrypted drive '%s:%s'", f.name, f.root) 228 } 229 230 // Encrypt an object file name to entries. 231 func (f *Fs) add(entries *fs.DirEntries, obj fs.Object) { 232 remote := obj.Remote() 233 decryptedRemote, err := f.cipher.DecryptFileName(remote) 234 if err != nil { 235 fs.Debugf(remote, "Skipping undecryptable file name: %v", err) 236 return 237 } 238 if f.opt.ShowMapping { 239 fs.Logf(decryptedRemote, "Encrypts to %q", remote) 240 } 241 *entries = append(*entries, f.newObject(obj)) 242 } 243 244 // Encrypt a directory file name to entries. 245 func (f *Fs) addDir(ctx context.Context, entries *fs.DirEntries, dir fs.Directory) { 246 remote := dir.Remote() 247 decryptedRemote, err := f.cipher.DecryptDirName(remote) 248 if err != nil { 249 fs.Debugf(remote, "Skipping undecryptable dir name: %v", err) 250 return 251 } 252 if f.opt.ShowMapping { 253 fs.Logf(decryptedRemote, "Encrypts to %q", remote) 254 } 255 *entries = append(*entries, f.newDir(ctx, dir)) 256 } 257 258 // Encrypt some directory entries. This alters entries returning it as newEntries. 259 func (f *Fs) encryptEntries(ctx context.Context, entries fs.DirEntries) (newEntries fs.DirEntries, err error) { 260 newEntries = entries[:0] // in place filter 261 for _, entry := range entries { 262 switch x := entry.(type) { 263 case fs.Object: 264 f.add(&newEntries, x) 265 case fs.Directory: 266 f.addDir(ctx, &newEntries, x) 267 default: 268 return nil, errors.Errorf("Unknown object type %T", entry) 269 } 270 } 271 return newEntries, nil 272 } 273 274 // List the objects and directories in dir into entries. The 275 // entries can be returned in any order but should be for a 276 // complete directory. 277 // 278 // dir should be "" to list the root, and should not have 279 // trailing slashes. 280 // 281 // This should return ErrDirNotFound if the directory isn't 282 // found. 283 func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) { 284 entries, err = f.Fs.List(ctx, f.cipher.EncryptDirName(dir)) 285 if err != nil { 286 return nil, err 287 } 288 return f.encryptEntries(ctx, entries) 289 } 290 291 // ListR lists the objects and directories of the Fs starting 292 // from dir recursively into out. 293 // 294 // dir should be "" to start from the root, and should not 295 // have trailing slashes. 296 // 297 // This should return ErrDirNotFound if the directory isn't 298 // found. 299 // 300 // It should call callback for each tranche of entries read. 301 // These need not be returned in any particular order. If 302 // callback returns an error then the listing will stop 303 // immediately. 304 // 305 // Don't implement this unless you have a more efficient way 306 // of listing recursively that doing a directory traversal. 307 func (f *Fs) ListR(ctx context.Context, dir string, callback fs.ListRCallback) (err error) { 308 return f.Fs.Features().ListR(ctx, f.cipher.EncryptDirName(dir), func(entries fs.DirEntries) error { 309 newEntries, err := f.encryptEntries(ctx, entries) 310 if err != nil { 311 return err 312 } 313 return callback(newEntries) 314 }) 315 } 316 317 // NewObject finds the Object at remote. 318 func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) { 319 o, err := f.Fs.NewObject(ctx, f.cipher.EncryptFileName(remote)) 320 if err != nil { 321 return nil, err 322 } 323 return f.newObject(o), nil 324 } 325 326 type putFn func(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) 327 328 // put implements Put or PutStream 329 func (f *Fs) put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options []fs.OpenOption, put putFn) (fs.Object, error) { 330 // Encrypt the data into wrappedIn 331 wrappedIn, encrypter, err := f.cipher.encryptData(in) 332 if err != nil { 333 return nil, err 334 } 335 336 // Find a hash the destination supports to compute a hash of 337 // the encrypted data 338 ht := f.Fs.Hashes().GetOne() 339 var hasher *hash.MultiHasher 340 if ht != hash.None { 341 hasher, err = hash.NewMultiHasherTypes(hash.NewHashSet(ht)) 342 if err != nil { 343 return nil, err 344 } 345 // unwrap the accounting 346 var wrap accounting.WrapFn 347 wrappedIn, wrap = accounting.UnWrap(wrappedIn) 348 // add the hasher 349 wrappedIn = io.TeeReader(wrappedIn, hasher) 350 // wrap the accounting back on 351 wrappedIn = wrap(wrappedIn) 352 } 353 354 // Transfer the data 355 o, err := put(ctx, wrappedIn, f.newObjectInfo(src, encrypter.nonce), options...) 356 if err != nil { 357 return nil, err 358 } 359 360 // Check the hashes of the encrypted data if we were comparing them 361 if ht != hash.None && hasher != nil { 362 srcHash := hasher.Sums()[ht] 363 var dstHash string 364 dstHash, err = o.Hash(ctx, ht) 365 if err != nil { 366 return nil, errors.Wrap(err, "failed to read destination hash") 367 } 368 if srcHash != "" && dstHash != "" && srcHash != dstHash { 369 // remove object 370 err = o.Remove(ctx) 371 if err != nil { 372 fs.Errorf(o, "Failed to remove corrupted object: %v", err) 373 } 374 return nil, errors.Errorf("corrupted on transfer: %v crypted hash differ %q vs %q", ht, srcHash, dstHash) 375 } 376 } 377 378 return f.newObject(o), nil 379 } 380 381 // Put in to the remote path with the modTime given of the given size 382 // 383 // May create the object even if it returns an error - if so 384 // will return the object and the error, otherwise will return 385 // nil and the error 386 func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 387 return f.put(ctx, in, src, options, f.Fs.Put) 388 } 389 390 // PutStream uploads to the remote path with the modTime given of indeterminate size 391 func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 392 return f.put(ctx, in, src, options, f.Fs.Features().PutStream) 393 } 394 395 // Hashes returns the supported hash sets. 396 func (f *Fs) Hashes() hash.Set { 397 return hash.Set(hash.None) 398 } 399 400 // Mkdir makes the directory (container, bucket) 401 // 402 // Shouldn't return an error if it already exists 403 func (f *Fs) Mkdir(ctx context.Context, dir string) error { 404 return f.Fs.Mkdir(ctx, f.cipher.EncryptDirName(dir)) 405 } 406 407 // Rmdir removes the directory (container, bucket) if empty 408 // 409 // Return an error if it doesn't exist or isn't empty 410 func (f *Fs) Rmdir(ctx context.Context, dir string) error { 411 return f.Fs.Rmdir(ctx, f.cipher.EncryptDirName(dir)) 412 } 413 414 // Purge all files in the root and the root directory 415 // 416 // Implement this if you have a way of deleting all the files 417 // quicker than just running Remove() on the result of List() 418 // 419 // Return an error if it doesn't exist 420 func (f *Fs) Purge(ctx context.Context) error { 421 do := f.Fs.Features().Purge 422 if do == nil { 423 return fs.ErrorCantPurge 424 } 425 return do(ctx) 426 } 427 428 // Copy src to this remote using server side copy operations. 429 // 430 // This is stored with the remote path given 431 // 432 // It returns the destination Object and a possible error 433 // 434 // Will only be called if src.Fs().Name() == f.Name() 435 // 436 // If it isn't possible then return fs.ErrorCantCopy 437 func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { 438 do := f.Fs.Features().Copy 439 if do == nil { 440 return nil, fs.ErrorCantCopy 441 } 442 o, ok := src.(*Object) 443 if !ok { 444 return nil, fs.ErrorCantCopy 445 } 446 oResult, err := do(ctx, o.Object, f.cipher.EncryptFileName(remote)) 447 if err != nil { 448 return nil, err 449 } 450 return f.newObject(oResult), nil 451 } 452 453 // Move src to this remote using server side move operations. 454 // 455 // This is stored with the remote path given 456 // 457 // It returns the destination Object and a possible error 458 // 459 // Will only be called if src.Fs().Name() == f.Name() 460 // 461 // If it isn't possible then return fs.ErrorCantMove 462 func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { 463 do := f.Fs.Features().Move 464 if do == nil { 465 return nil, fs.ErrorCantMove 466 } 467 o, ok := src.(*Object) 468 if !ok { 469 return nil, fs.ErrorCantMove 470 } 471 oResult, err := do(ctx, o.Object, f.cipher.EncryptFileName(remote)) 472 if err != nil { 473 return nil, err 474 } 475 return f.newObject(oResult), nil 476 } 477 478 // DirMove moves src, srcRemote to this remote at dstRemote 479 // using server side move operations. 480 // 481 // Will only be called if src.Fs().Name() == f.Name() 482 // 483 // If it isn't possible then return fs.ErrorCantDirMove 484 // 485 // If destination exists then return fs.ErrorDirExists 486 func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) error { 487 do := f.Fs.Features().DirMove 488 if do == nil { 489 return fs.ErrorCantDirMove 490 } 491 srcFs, ok := src.(*Fs) 492 if !ok { 493 fs.Debugf(srcFs, "Can't move directory - not same remote type") 494 return fs.ErrorCantDirMove 495 } 496 return do(ctx, srcFs.Fs, f.cipher.EncryptDirName(srcRemote), f.cipher.EncryptDirName(dstRemote)) 497 } 498 499 // PutUnchecked uploads the object 500 // 501 // This will create a duplicate if we upload a new file without 502 // checking to see if there is one already - use Put() for that. 503 func (f *Fs) PutUnchecked(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 504 do := f.Fs.Features().PutUnchecked 505 if do == nil { 506 return nil, errors.New("can't PutUnchecked") 507 } 508 wrappedIn, encrypter, err := f.cipher.encryptData(in) 509 if err != nil { 510 return nil, err 511 } 512 o, err := do(ctx, wrappedIn, f.newObjectInfo(src, encrypter.nonce)) 513 if err != nil { 514 return nil, err 515 } 516 return f.newObject(o), nil 517 } 518 519 // CleanUp the trash in the Fs 520 // 521 // Implement this if you have a way of emptying the trash or 522 // otherwise cleaning up old versions of files. 523 func (f *Fs) CleanUp(ctx context.Context) error { 524 do := f.Fs.Features().CleanUp 525 if do == nil { 526 return errors.New("can't CleanUp") 527 } 528 return do(ctx) 529 } 530 531 // About gets quota information from the Fs 532 func (f *Fs) About(ctx context.Context) (*fs.Usage, error) { 533 do := f.Fs.Features().About 534 if do == nil { 535 return nil, errors.New("About not supported") 536 } 537 return do(ctx) 538 } 539 540 // UnWrap returns the Fs that this Fs is wrapping 541 func (f *Fs) UnWrap() fs.Fs { 542 return f.Fs 543 } 544 545 // WrapFs returns the Fs that is wrapping this Fs 546 func (f *Fs) WrapFs() fs.Fs { 547 return f.wrapper 548 } 549 550 // SetWrapper sets the Fs that is wrapping this Fs 551 func (f *Fs) SetWrapper(wrapper fs.Fs) { 552 f.wrapper = wrapper 553 } 554 555 // EncryptFileName returns an encrypted file name 556 func (f *Fs) EncryptFileName(fileName string) string { 557 return f.cipher.EncryptFileName(fileName) 558 } 559 560 // DecryptFileName returns a decrypted file name 561 func (f *Fs) DecryptFileName(encryptedFileName string) (string, error) { 562 return f.cipher.DecryptFileName(encryptedFileName) 563 } 564 565 // computeHashWithNonce takes the nonce and encrypts the contents of 566 // src with it, and calculates the hash given by HashType on the fly 567 // 568 // Note that we break lots of encapsulation in this function. 569 func (f *Fs) computeHashWithNonce(ctx context.Context, nonce nonce, src fs.Object, hashType hash.Type) (hashStr string, err error) { 570 // Open the src for input 571 in, err := src.Open(ctx) 572 if err != nil { 573 return "", errors.Wrap(err, "failed to open src") 574 } 575 defer fs.CheckClose(in, &err) 576 577 // Now encrypt the src with the nonce 578 out, err := f.cipher.newEncrypter(in, &nonce) 579 if err != nil { 580 return "", errors.Wrap(err, "failed to make encrypter") 581 } 582 583 // pipe into hash 584 m, err := hash.NewMultiHasherTypes(hash.NewHashSet(hashType)) 585 if err != nil { 586 return "", errors.Wrap(err, "failed to make hasher") 587 } 588 _, err = io.Copy(m, out) 589 if err != nil { 590 return "", errors.Wrap(err, "failed to hash data") 591 } 592 593 return m.Sums()[hashType], nil 594 } 595 596 // ComputeHash takes the nonce from o, and encrypts the contents of 597 // src with it, and calculates the hash given by HashType on the fly 598 // 599 // Note that we break lots of encapsulation in this function. 600 func (f *Fs) ComputeHash(ctx context.Context, o *Object, src fs.Object, hashType hash.Type) (hashStr string, err error) { 601 // Read the nonce - opening the file is sufficient to read the nonce in 602 // use a limited read so we only read the header 603 in, err := o.Object.Open(ctx, &fs.RangeOption{Start: 0, End: int64(fileHeaderSize) - 1}) 604 if err != nil { 605 return "", errors.Wrap(err, "failed to open object to read nonce") 606 } 607 d, err := f.cipher.newDecrypter(in) 608 if err != nil { 609 _ = in.Close() 610 return "", errors.Wrap(err, "failed to open object to read nonce") 611 } 612 nonce := d.nonce 613 // fs.Debugf(o, "Read nonce % 2x", nonce) 614 615 // Check nonce isn't all zeros 616 isZero := true 617 for i := range nonce { 618 if nonce[i] != 0 { 619 isZero = false 620 } 621 } 622 if isZero { 623 fs.Errorf(o, "empty nonce read") 624 } 625 626 // Close d (and hence in) once we have read the nonce 627 err = d.Close() 628 if err != nil { 629 return "", errors.Wrap(err, "failed to close nonce read") 630 } 631 632 return f.computeHashWithNonce(ctx, nonce, src, hashType) 633 } 634 635 // MergeDirs merges the contents of all the directories passed 636 // in into the first one and rmdirs the other directories. 637 func (f *Fs) MergeDirs(ctx context.Context, dirs []fs.Directory) error { 638 do := f.Fs.Features().MergeDirs 639 if do == nil { 640 return errors.New("MergeDirs not supported") 641 } 642 out := make([]fs.Directory, len(dirs)) 643 for i, dir := range dirs { 644 out[i] = fs.NewDirCopy(ctx, dir).SetRemote(f.cipher.EncryptDirName(dir.Remote())) 645 } 646 return do(ctx, out) 647 } 648 649 // DirCacheFlush resets the directory cache - used in testing 650 // as an optional interface 651 func (f *Fs) DirCacheFlush() { 652 do := f.Fs.Features().DirCacheFlush 653 if do != nil { 654 do() 655 } 656 } 657 658 // PublicLink generates a public link to the remote path (usually readable by anyone) 659 func (f *Fs) PublicLink(ctx context.Context, remote string) (string, error) { 660 do := f.Fs.Features().PublicLink 661 if do == nil { 662 return "", errors.New("PublicLink not supported") 663 } 664 o, err := f.NewObject(ctx, remote) 665 if err != nil { 666 // assume it is a directory 667 return do(ctx, f.cipher.EncryptDirName(remote)) 668 } 669 return do(ctx, o.(*Object).Object.Remote()) 670 } 671 672 // ChangeNotify calls the passed function with a path 673 // that has had changes. If the implementation 674 // uses polling, it should adhere to the given interval. 675 func (f *Fs) ChangeNotify(ctx context.Context, notifyFunc func(string, fs.EntryType), pollIntervalChan <-chan time.Duration) { 676 do := f.Fs.Features().ChangeNotify 677 if do == nil { 678 return 679 } 680 wrappedNotifyFunc := func(path string, entryType fs.EntryType) { 681 // fs.Debugf(f, "ChangeNotify: path %q entryType %d", path, entryType) 682 var ( 683 err error 684 decrypted string 685 ) 686 switch entryType { 687 case fs.EntryDirectory: 688 decrypted, err = f.cipher.DecryptDirName(path) 689 case fs.EntryObject: 690 decrypted, err = f.cipher.DecryptFileName(path) 691 default: 692 fs.Errorf(path, "crypt ChangeNotify: ignoring unknown EntryType %d", entryType) 693 return 694 } 695 if err != nil { 696 fs.Logf(f, "ChangeNotify was unable to decrypt %q: %s", path, err) 697 return 698 } 699 notifyFunc(decrypted, entryType) 700 } 701 do(ctx, wrappedNotifyFunc, pollIntervalChan) 702 } 703 704 var commandHelp = []fs.CommandHelp{ 705 { 706 Name: "encode", 707 Short: "Encode the given filename(s)", 708 Long: `This encodes the filenames given as arguments returning a list of 709 strings of the encoded results. 710 711 Usage Example: 712 713 rclone backend encode crypt: file1 [file2...] 714 rclone rc backend/command command=encode fs=crypt: file1 [file2...] 715 `, 716 }, 717 { 718 Name: "decode", 719 Short: "Decode the given filename(s)", 720 Long: `This decodes the filenames given as arguments returning a list of 721 strings of the decoded results. It will return an error if any of the 722 inputs are invalid. 723 724 Usage Example: 725 726 rclone backend decode crypt: encryptedfile1 [encryptedfile2...] 727 rclone rc backend/command command=decode fs=crypt: encryptedfile1 [encryptedfile2...] 728 `, 729 }, 730 } 731 732 // Command the backend to run a named command 733 // 734 // The command run is name 735 // args may be used to read arguments from 736 // opts may be used to read optional arguments from 737 // 738 // The result should be capable of being JSON encoded 739 // If it is a string or a []string it will be shown to the user 740 // otherwise it will be JSON encoded and shown to the user like that 741 func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[string]string) (out interface{}, err error) { 742 switch name { 743 case "decode": 744 out := make([]string, 0, len(arg)) 745 for _, encryptedFileName := range arg { 746 fileName, err := f.DecryptFileName(encryptedFileName) 747 if err != nil { 748 return out, errors.Wrap(err, fmt.Sprintf("Failed to decrypt : %s", encryptedFileName)) 749 } 750 out = append(out, fileName) 751 } 752 return out, nil 753 case "encode": 754 out := make([]string, 0, len(arg)) 755 for _, fileName := range arg { 756 encryptedFileName := f.EncryptFileName(fileName) 757 out = append(out, encryptedFileName) 758 } 759 return out, nil 760 default: 761 return nil, fs.ErrorCommandNotFound 762 } 763 } 764 765 // Object describes a wrapped for being read from the Fs 766 // 767 // This decrypts the remote name and decrypts the data 768 type Object struct { 769 fs.Object 770 f *Fs 771 } 772 773 func (f *Fs) newObject(o fs.Object) *Object { 774 return &Object{ 775 Object: o, 776 f: f, 777 } 778 } 779 780 // Fs returns read only access to the Fs that this object is part of 781 func (o *Object) Fs() fs.Info { 782 return o.f 783 } 784 785 // Return a string version 786 func (o *Object) String() string { 787 if o == nil { 788 return "<nil>" 789 } 790 return o.Remote() 791 } 792 793 // Remote returns the remote path 794 func (o *Object) Remote() string { 795 remote := o.Object.Remote() 796 decryptedName, err := o.f.cipher.DecryptFileName(remote) 797 if err != nil { 798 fs.Debugf(remote, "Undecryptable file name: %v", err) 799 return remote 800 } 801 return decryptedName 802 } 803 804 // Size returns the size of the file 805 func (o *Object) Size() int64 { 806 size, err := o.f.cipher.DecryptedSize(o.Object.Size()) 807 if err != nil { 808 fs.Debugf(o, "Bad size for decrypt: %v", err) 809 } 810 return size 811 } 812 813 // Hash returns the selected checksum of the file 814 // If no checksum is available it returns "" 815 func (o *Object) Hash(ctx context.Context, ht hash.Type) (string, error) { 816 return "", hash.ErrUnsupported 817 } 818 819 // UnWrap returns the wrapped Object 820 func (o *Object) UnWrap() fs.Object { 821 return o.Object 822 } 823 824 // Open opens the file for read. Call Close() on the returned io.ReadCloser 825 func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (rc io.ReadCloser, err error) { 826 var openOptions []fs.OpenOption 827 var offset, limit int64 = 0, -1 828 for _, option := range options { 829 switch x := option.(type) { 830 case *fs.SeekOption: 831 offset = x.Offset 832 case *fs.RangeOption: 833 offset, limit = x.Decode(o.Size()) 834 default: 835 // pass on Options to underlying open if appropriate 836 openOptions = append(openOptions, option) 837 } 838 } 839 rc, err = o.f.cipher.DecryptDataSeek(ctx, func(ctx context.Context, underlyingOffset, underlyingLimit int64) (io.ReadCloser, error) { 840 if underlyingOffset == 0 && underlyingLimit < 0 { 841 // Open with no seek 842 return o.Object.Open(ctx, openOptions...) 843 } 844 // Open stream with a range of underlyingOffset, underlyingLimit 845 end := int64(-1) 846 if underlyingLimit >= 0 { 847 end = underlyingOffset + underlyingLimit - 1 848 if end >= o.Object.Size() { 849 end = -1 850 } 851 } 852 newOpenOptions := append(openOptions, &fs.RangeOption{Start: underlyingOffset, End: end}) 853 return o.Object.Open(ctx, newOpenOptions...) 854 }, offset, limit) 855 if err != nil { 856 return nil, err 857 } 858 return rc, nil 859 } 860 861 // Update in to the object with the modTime given of the given size 862 func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error { 863 update := func(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) { 864 return o.Object, o.Object.Update(ctx, in, src, options...) 865 } 866 _, err := o.f.put(ctx, in, src, options, update) 867 return err 868 } 869 870 // newDir returns a dir with the Name decrypted 871 func (f *Fs) newDir(ctx context.Context, dir fs.Directory) fs.Directory { 872 newDir := fs.NewDirCopy(ctx, dir) 873 remote := dir.Remote() 874 decryptedRemote, err := f.cipher.DecryptDirName(remote) 875 if err != nil { 876 fs.Debugf(remote, "Undecryptable dir name: %v", err) 877 } else { 878 newDir.SetRemote(decryptedRemote) 879 } 880 return newDir 881 } 882 883 // UserInfo returns info about the connected user 884 func (f *Fs) UserInfo(ctx context.Context) (map[string]string, error) { 885 do := f.Fs.Features().UserInfo 886 if do == nil { 887 return nil, fs.ErrorNotImplemented 888 } 889 return do(ctx) 890 } 891 892 // Disconnect the current user 893 func (f *Fs) Disconnect(ctx context.Context) error { 894 do := f.Fs.Features().Disconnect 895 if do == nil { 896 return fs.ErrorNotImplemented 897 } 898 return do(ctx) 899 } 900 901 // ObjectInfo describes a wrapped fs.ObjectInfo for being the source 902 // 903 // This encrypts the remote name and adjusts the size 904 type ObjectInfo struct { 905 fs.ObjectInfo 906 f *Fs 907 nonce nonce 908 } 909 910 func (f *Fs) newObjectInfo(src fs.ObjectInfo, nonce nonce) *ObjectInfo { 911 return &ObjectInfo{ 912 ObjectInfo: src, 913 f: f, 914 nonce: nonce, 915 } 916 } 917 918 // Fs returns read only access to the Fs that this object is part of 919 func (o *ObjectInfo) Fs() fs.Info { 920 return o.f 921 } 922 923 // Remote returns the remote path 924 func (o *ObjectInfo) Remote() string { 925 return o.f.cipher.EncryptFileName(o.ObjectInfo.Remote()) 926 } 927 928 // Size returns the size of the file 929 func (o *ObjectInfo) Size() int64 { 930 size := o.ObjectInfo.Size() 931 if size < 0 { 932 return size 933 } 934 return o.f.cipher.EncryptedSize(size) 935 } 936 937 // Hash returns the selected checksum of the file 938 // If no checksum is available it returns "" 939 func (o *ObjectInfo) Hash(ctx context.Context, hash hash.Type) (string, error) { 940 var srcObj fs.Object 941 var ok bool 942 // Get the underlying object if there is one 943 if srcObj, ok = o.ObjectInfo.(fs.Object); ok { 944 // Prefer direct interface assertion 945 } else if do, ok := o.ObjectInfo.(fs.ObjectUnWrapper); ok { 946 // Otherwise likely is an operations.OverrideRemote 947 srcObj = do.UnWrap() 948 } else { 949 return "", nil 950 } 951 // if this is wrapping a local object then we work out the hash 952 if srcObj.Fs().Features().IsLocal { 953 // Read the data and encrypt it to calculate the hash 954 fs.Debugf(o, "Computing %v hash of encrypted source", hash) 955 return o.f.computeHashWithNonce(ctx, o.nonce, srcObj, hash) 956 } 957 return "", nil 958 } 959 960 // ID returns the ID of the Object if known, or "" if not 961 func (o *Object) ID() string { 962 do, ok := o.Object.(fs.IDer) 963 if !ok { 964 return "" 965 } 966 return do.ID() 967 } 968 969 // SetTier performs changing storage tier of the Object if 970 // multiple storage classes supported 971 func (o *Object) SetTier(tier string) error { 972 do, ok := o.Object.(fs.SetTierer) 973 if !ok { 974 return errors.New("crypt: underlying remote does not support SetTier") 975 } 976 return do.SetTier(tier) 977 } 978 979 // GetTier returns storage tier or class of the Object 980 func (o *Object) GetTier() string { 981 do, ok := o.Object.(fs.GetTierer) 982 if !ok { 983 return "" 984 } 985 return do.GetTier() 986 } 987 988 // Check the interfaces are satisfied 989 var ( 990 _ fs.Fs = (*Fs)(nil) 991 _ fs.Purger = (*Fs)(nil) 992 _ fs.Copier = (*Fs)(nil) 993 _ fs.Mover = (*Fs)(nil) 994 _ fs.DirMover = (*Fs)(nil) 995 _ fs.Commander = (*Fs)(nil) 996 _ fs.PutUncheckeder = (*Fs)(nil) 997 _ fs.PutStreamer = (*Fs)(nil) 998 _ fs.CleanUpper = (*Fs)(nil) 999 _ fs.UnWrapper = (*Fs)(nil) 1000 _ fs.ListRer = (*Fs)(nil) 1001 _ fs.Abouter = (*Fs)(nil) 1002 _ fs.Wrapper = (*Fs)(nil) 1003 _ fs.MergeDirser = (*Fs)(nil) 1004 _ fs.DirCacheFlusher = (*Fs)(nil) 1005 _ fs.ChangeNotifier = (*Fs)(nil) 1006 _ fs.PublicLinker = (*Fs)(nil) 1007 _ fs.UserInfoer = (*Fs)(nil) 1008 _ fs.Disconnecter = (*Fs)(nil) 1009 _ fs.ObjectInfo = (*ObjectInfo)(nil) 1010 _ fs.Object = (*Object)(nil) 1011 _ fs.ObjectUnWrapper = (*Object)(nil) 1012 _ fs.IDer = (*Object)(nil) 1013 _ fs.SetTierer = (*Object)(nil) 1014 _ fs.GetTierer = (*Object)(nil) 1015 )