github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/fs/config/config.go (about) 1 // Package config reads, writes and edits the config file and deals with command line flags 2 package config 3 4 import ( 5 "bufio" 6 "bytes" 7 "crypto/rand" 8 "crypto/sha256" 9 "encoding/base64" 10 "encoding/json" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "log" 15 mathrand "math/rand" 16 "os" 17 "path/filepath" 18 "regexp" 19 "runtime" 20 "sort" 21 "strconv" 22 "strings" 23 "time" 24 "unicode/utf8" 25 26 "github.com/Unknwon/goconfig" 27 homedir "github.com/mitchellh/go-homedir" 28 "github.com/ncw/rclone/fs" 29 "github.com/ncw/rclone/fs/accounting" 30 "github.com/ncw/rclone/fs/config/configmap" 31 "github.com/ncw/rclone/fs/config/configstruct" 32 "github.com/ncw/rclone/fs/config/obscure" 33 "github.com/ncw/rclone/fs/driveletter" 34 "github.com/ncw/rclone/fs/fshttp" 35 "github.com/ncw/rclone/fs/fspath" 36 "github.com/ncw/rclone/fs/rc" 37 "github.com/pkg/errors" 38 "golang.org/x/crypto/nacl/secretbox" 39 "golang.org/x/text/unicode/norm" 40 ) 41 42 const ( 43 configFileName = "rclone.conf" 44 hiddenConfigFileName = "." + configFileName 45 46 // ConfigToken is the key used to store the token under 47 ConfigToken = "token" 48 49 // ConfigClientID is the config key used to store the client id 50 ConfigClientID = "client_id" 51 52 // ConfigClientSecret is the config key used to store the client secret 53 ConfigClientSecret = "client_secret" 54 55 // ConfigAuthURL is the config key used to store the auth server endpoint 56 ConfigAuthURL = "auth_url" 57 58 // ConfigTokenURL is the config key used to store the token server endpoint 59 ConfigTokenURL = "token_url" 60 61 // ConfigAuthorize indicates that we just want "rclone authorize" 62 ConfigAuthorize = "config_authorize" 63 ) 64 65 // Global 66 var ( 67 // configFile is the global config data structure. Don't read it directly, use getConfigData() 68 configFile *goconfig.ConfigFile 69 70 // ConfigPath points to the config file 71 ConfigPath = makeConfigPath() 72 73 // CacheDir points to the cache directory. Users of this 74 // should make a subdirectory and use MkdirAll() to create it 75 // and any parents. 76 CacheDir = makeCacheDir() 77 78 // Key to use for password en/decryption. 79 // When nil, no encryption will be used for saving. 80 configKey []byte 81 82 // output of prompt for password 83 PasswordPromptOutput = os.Stderr 84 85 // If set to true, the configKey is obscured with obscure.Obscure and saved to a temp file when it is 86 // calculated from the password. The path of that temp file is then written to the environment variable 87 // `_RCLONE_CONFIG_KEY_FILE`. If `_RCLONE_CONFIG_KEY_FILE` is present, password prompt is skipped and `RCLONE_CONFIG_PASS` ignored. 88 // For security reasons, the temp file is deleted once the configKey is successfully loaded. 89 // This can be used to pass the configKey to a child process. 90 PassConfigKeyForDaemonization = false 91 ) 92 93 func init() { 94 // Set the function pointers up in fs 95 fs.ConfigFileGet = FileGetFlag 96 fs.ConfigFileSet = FileSet 97 } 98 99 func getConfigData() *goconfig.ConfigFile { 100 if configFile == nil { 101 LoadConfig() 102 } 103 return configFile 104 } 105 106 // Return the path to the configuration file 107 func makeConfigPath() string { 108 109 // Use rclone.conf from rclone executable directory if already existing 110 exe, err := os.Executable() 111 if err == nil { 112 exedir := filepath.Dir(exe) 113 cfgpath := filepath.Join(exedir, configFileName) 114 _, err := os.Stat(cfgpath) 115 if err == nil { 116 return cfgpath 117 } 118 } 119 120 // Find user's home directory 121 homeDir, err := homedir.Dir() 122 123 // Find user's configuration directory. 124 // Prefer XDG config path, with fallback to $HOME/.config. 125 // See XDG Base Directory specification 126 // https://specifications.freedesktop.org/basedir-spec/latest/), 127 xdgdir := os.Getenv("XDG_CONFIG_HOME") 128 var cfgdir string 129 if xdgdir != "" { 130 // User's configuration directory for rclone is $XDG_CONFIG_HOME/rclone 131 cfgdir = filepath.Join(xdgdir, "rclone") 132 } else if homeDir != "" { 133 // User's configuration directory for rclone is $HOME/.config/rclone 134 cfgdir = filepath.Join(homeDir, ".config", "rclone") 135 } 136 137 // Use rclone.conf from user's configuration directory if already existing 138 var cfgpath string 139 if cfgdir != "" { 140 cfgpath = filepath.Join(cfgdir, configFileName) 141 _, err := os.Stat(cfgpath) 142 if err == nil { 143 return cfgpath 144 } 145 } 146 147 // Use .rclone.conf from user's home directory if already existing 148 var homeconf string 149 if homeDir != "" { 150 homeconf = filepath.Join(homeDir, hiddenConfigFileName) 151 _, err := os.Stat(homeconf) 152 if err == nil { 153 return homeconf 154 } 155 } 156 157 // Check to see if user supplied a --config variable or environment 158 // variable. We can't use pflag for this because it isn't initialised 159 // yet so we search the command line manually. 160 _, configSupplied := os.LookupEnv("RCLONE_CONFIG") 161 if !configSupplied { 162 for _, item := range os.Args { 163 if item == "--config" || strings.HasPrefix(item, "--config=") { 164 configSupplied = true 165 break 166 } 167 } 168 } 169 170 // If user's configuration directory was found, then try to create it 171 // and assume rclone.conf can be written there. If user supplied config 172 // then skip creating the directory since it will not be used. 173 if cfgpath != "" { 174 // cfgpath != "" implies cfgdir != "" 175 if configSupplied { 176 return cfgpath 177 } 178 err := os.MkdirAll(cfgdir, os.ModePerm) 179 if err == nil { 180 return cfgpath 181 } 182 } 183 184 // Assume .rclone.conf can be written to user's home directory. 185 if homeconf != "" { 186 return homeconf 187 } 188 189 // Default to ./.rclone.conf (current working directory) if everything else fails. 190 if !configSupplied { 191 fs.Errorf(nil, "Couldn't find home directory or read HOME or XDG_CONFIG_HOME environment variables.") 192 fs.Errorf(nil, "Defaulting to storing config in current directory.") 193 fs.Errorf(nil, "Use --config flag to workaround.") 194 fs.Errorf(nil, "Error was: %v", err) 195 } 196 return hiddenConfigFileName 197 } 198 199 // LoadConfig loads the config file 200 func LoadConfig() { 201 // Load configuration file. 202 var err error 203 configFile, err = loadConfigFile() 204 if err == errorConfigFileNotFound { 205 fs.Logf(nil, "Config file %q not found - using defaults", ConfigPath) 206 configFile, _ = goconfig.LoadFromReader(&bytes.Buffer{}) 207 } else if err != nil { 208 log.Fatalf("Failed to load config file %q: %v", ConfigPath, err) 209 } else { 210 fs.Debugf(nil, "Using config file from %q", ConfigPath) 211 } 212 213 // Start the token bucket limiter 214 accounting.StartTokenBucket() 215 216 // Start the bandwidth update ticker 217 accounting.StartTokenTicker() 218 219 // Start the transactions per second limiter 220 fshttp.StartHTTPTokenBucket() 221 } 222 223 var errorConfigFileNotFound = errors.New("config file not found") 224 225 // loadConfigFile will load a config file, and 226 // automatically decrypt it. 227 func loadConfigFile() (*goconfig.ConfigFile, error) { 228 envpw := os.Getenv("RCLONE_CONFIG_PASS") 229 if len(configKey) == 0 && envpw != "" { 230 err := setConfigPassword(envpw) 231 if err != nil { 232 fs.Errorf(nil, "Using RCLONE_CONFIG_PASS returned: %v", err) 233 } else { 234 fs.Debugf(nil, "Using RCLONE_CONFIG_PASS password.") 235 } 236 } 237 238 b, err := ioutil.ReadFile(ConfigPath) 239 if err != nil { 240 if os.IsNotExist(err) { 241 return nil, errorConfigFileNotFound 242 } 243 return nil, err 244 } 245 // Find first non-empty line 246 r := bufio.NewReader(bytes.NewBuffer(b)) 247 for { 248 line, _, err := r.ReadLine() 249 if err != nil { 250 if err == io.EOF { 251 return goconfig.LoadFromReader(bytes.NewBuffer(b)) 252 } 253 return nil, err 254 } 255 l := strings.TrimSpace(string(line)) 256 if len(l) == 0 || strings.HasPrefix(l, ";") || strings.HasPrefix(l, "#") { 257 continue 258 } 259 // First non-empty or non-comment must be ENCRYPT_V0 260 if l == "RCLONE_ENCRYPT_V0:" { 261 break 262 } 263 if strings.HasPrefix(l, "RCLONE_ENCRYPT_V") { 264 return nil, errors.New("unsupported configuration encryption - update rclone for support") 265 } 266 return goconfig.LoadFromReader(bytes.NewBuffer(b)) 267 } 268 269 // Encrypted content is base64 encoded. 270 dec := base64.NewDecoder(base64.StdEncoding, r) 271 box, err := ioutil.ReadAll(dec) 272 if err != nil { 273 return nil, errors.Wrap(err, "failed to load base64 encoded data") 274 } 275 if len(box) < 24+secretbox.Overhead { 276 return nil, errors.New("Configuration data too short") 277 } 278 279 var out []byte 280 for { 281 if envKeyFile := os.Getenv("_RCLONE_CONFIG_KEY_FILE"); len(envKeyFile) > 0 { 282 fs.Debugf(nil, "attempting to obtain configKey from temp file %s", envKeyFile) 283 obscuredKey, err := ioutil.ReadFile(envKeyFile) 284 if err != nil { 285 errRemove := os.Remove(envKeyFile) 286 if errRemove != nil { 287 log.Fatalf("unable to read obscured config key and unable to delete the temp file: %v", err) 288 } 289 log.Fatalf("unable to read obscured config key: %v", err) 290 } 291 errRemove := os.Remove(envKeyFile) 292 if errRemove != nil { 293 log.Fatalf("unable to delete temp file with configKey: %v", err) 294 } 295 configKey = []byte(obscure.MustReveal(string(obscuredKey))) 296 fs.Debugf(nil, "using _RCLONE_CONFIG_KEY_FILE for configKey") 297 } else { 298 if len(configKey) == 0 { 299 if !fs.Config.AskPassword { 300 return nil, errors.New("unable to decrypt configuration and not allowed to ask for password - set RCLONE_CONFIG_PASS to your configuration password") 301 } 302 getConfigPassword("Enter configuration password:") 303 } 304 } 305 306 // Nonce is first 24 bytes of the ciphertext 307 var nonce [24]byte 308 copy(nonce[:], box[:24]) 309 var key [32]byte 310 copy(key[:], configKey[:32]) 311 312 // Attempt to decrypt 313 var ok bool 314 out, ok = secretbox.Open(nil, box[24:], &nonce, &key) 315 if ok { 316 break 317 } 318 319 // Retry 320 fs.Errorf(nil, "Couldn't decrypt configuration, most likely wrong password.") 321 configKey = nil 322 } 323 return goconfig.LoadFromReader(bytes.NewBuffer(out)) 324 } 325 326 // checkPassword normalises and validates the password 327 func checkPassword(password string) (string, error) { 328 if !utf8.ValidString(password) { 329 return "", errors.New("password contains invalid utf8 characters") 330 } 331 // Check for leading/trailing whitespace 332 trimmedPassword := strings.TrimSpace(password) 333 // Warn user if password has leading+trailing whitespace 334 if len(password) != len(trimmedPassword) { 335 _, _ = fmt.Fprintln(os.Stderr, "Your password contains leading/trailing whitespace - in previous versions of rclone this was stripped") 336 } 337 // Normalize to reduce weird variations. 338 password = norm.NFKC.String(password) 339 if len(password) == 0 || len(trimmedPassword) == 0 { 340 return "", errors.New("no characters in password") 341 } 342 return password, nil 343 } 344 345 // GetPassword asks the user for a password with the prompt given. 346 func GetPassword(prompt string) string { 347 _, _ = fmt.Fprintln(PasswordPromptOutput, prompt) 348 for { 349 _, _ = fmt.Fprint(PasswordPromptOutput, "password:") 350 password := ReadPassword() 351 password, err := checkPassword(password) 352 if err == nil { 353 return password 354 } 355 _, _ = fmt.Fprintf(os.Stderr, "Bad password: %v\n", err) 356 } 357 } 358 359 // ChangePassword will query the user twice for the named password. If 360 // the same password is entered it is returned. 361 func ChangePassword(name string) string { 362 for { 363 a := GetPassword(fmt.Sprintf("Enter %s password:", name)) 364 b := GetPassword(fmt.Sprintf("Confirm %s password:", name)) 365 if a == b { 366 return a 367 } 368 fmt.Println("Passwords do not match!") 369 } 370 } 371 372 // getConfigPassword will query the user for a password the 373 // first time it is required. 374 func getConfigPassword(q string) { 375 if len(configKey) != 0 { 376 return 377 } 378 for { 379 password := GetPassword(q) 380 err := setConfigPassword(password) 381 if err == nil { 382 return 383 } 384 _, _ = fmt.Fprintln(os.Stderr, "Error:", err) 385 } 386 } 387 388 // setConfigPassword will set the configKey to the hash of 389 // the password. If the length of the password is 390 // zero after trimming+normalization, an error is returned. 391 func setConfigPassword(password string) error { 392 password, err := checkPassword(password) 393 if err != nil { 394 return err 395 } 396 // Create SHA256 has of the password 397 sha := sha256.New() 398 _, err = sha.Write([]byte("[" + password + "][rclone-config]")) 399 if err != nil { 400 return err 401 } 402 configKey = sha.Sum(nil) 403 if PassConfigKeyForDaemonization { 404 tempFile, err := ioutil.TempFile("", "rclone") 405 if err != nil { 406 log.Fatalf("cannot create temp file to store configKey: %v", err) 407 } 408 _, err = tempFile.WriteString(obscure.MustObscure(string(configKey))) 409 if err != nil { 410 errRemove := os.Remove(tempFile.Name()) 411 if errRemove != nil { 412 log.Fatalf("error writing configKey to temp file and also error deleting it: %v", err) 413 } 414 log.Fatalf("error writing configKey to temp file: %v", err) 415 } 416 err = tempFile.Close() 417 if err != nil { 418 errRemove := os.Remove(tempFile.Name()) 419 if errRemove != nil { 420 log.Fatalf("error closing temp file with configKey and also error deleting it: %v", err) 421 } 422 log.Fatalf("error closing temp file with configKey: %v", err) 423 } 424 fs.Debugf(nil, "saving configKey to temp file") 425 err = os.Setenv("_RCLONE_CONFIG_KEY_FILE", tempFile.Name()) 426 if err != nil { 427 errRemove := os.Remove(tempFile.Name()) 428 if errRemove != nil { 429 log.Fatalf("unable to set environment variable _RCLONE_CONFIG_KEY_FILE and unable to delete the temp file: %v", err) 430 } 431 log.Fatalf("unable to set environment variable _RCLONE_CONFIG_KEY_FILE: %v", err) 432 } 433 } 434 return nil 435 } 436 437 // changeConfigPassword will query the user twice 438 // for a password. If the same password is entered 439 // twice the key is updated. 440 func changeConfigPassword() { 441 err := setConfigPassword(ChangePassword("NEW configuration")) 442 if err != nil { 443 fmt.Printf("Failed to set config password: %v\n", err) 444 return 445 } 446 } 447 448 // saveConfig saves configuration file. 449 // if configKey has been set, the file will be encrypted. 450 func saveConfig() error { 451 dir, name := filepath.Split(ConfigPath) 452 err := os.MkdirAll(dir, os.ModePerm) 453 if err != nil { 454 return errors.Wrap(err, "failed to create config directory") 455 } 456 f, err := ioutil.TempFile(dir, name) 457 if err != nil { 458 return errors.Errorf("Failed to create temp file for new config: %v", err) 459 } 460 defer func() { 461 if err := os.Remove(f.Name()); err != nil && !os.IsNotExist(err) { 462 fs.Errorf(nil, "Failed to remove temp config file: %v", err) 463 } 464 }() 465 466 var buf bytes.Buffer 467 err = goconfig.SaveConfigData(getConfigData(), &buf) 468 if err != nil { 469 return errors.Errorf("Failed to save config file: %v", err) 470 } 471 472 if len(configKey) == 0 { 473 if _, err := buf.WriteTo(f); err != nil { 474 return errors.Errorf("Failed to write temp config file: %v", err) 475 } 476 } else { 477 _, _ = fmt.Fprintln(f, "# Encrypted rclone configuration File") 478 _, _ = fmt.Fprintln(f, "") 479 _, _ = fmt.Fprintln(f, "RCLONE_ENCRYPT_V0:") 480 481 // Generate new nonce and write it to the start of the ciphertext 482 var nonce [24]byte 483 n, _ := rand.Read(nonce[:]) 484 if n != 24 { 485 return errors.Errorf("nonce short read: %d", n) 486 } 487 enc := base64.NewEncoder(base64.StdEncoding, f) 488 _, err = enc.Write(nonce[:]) 489 if err != nil { 490 return errors.Errorf("Failed to write temp config file: %v", err) 491 } 492 493 var key [32]byte 494 copy(key[:], configKey[:32]) 495 496 b := secretbox.Seal(nil, buf.Bytes(), &nonce, &key) 497 _, err = enc.Write(b) 498 if err != nil { 499 return errors.Errorf("Failed to write temp config file: %v", err) 500 } 501 _ = enc.Close() 502 } 503 504 err = f.Close() 505 if err != nil { 506 return errors.Errorf("Failed to close config file: %v", err) 507 } 508 509 var fileMode os.FileMode = 0600 510 info, err := os.Stat(ConfigPath) 511 if err != nil { 512 fs.Debugf(nil, "Using default permissions for config file: %v", fileMode) 513 } else if info.Mode() != fileMode { 514 fs.Debugf(nil, "Keeping previous permissions for config file: %v", info.Mode()) 515 fileMode = info.Mode() 516 } 517 518 attemptCopyGroup(ConfigPath, f.Name()) 519 520 err = os.Chmod(f.Name(), fileMode) 521 if err != nil { 522 fs.Errorf(nil, "Failed to set permissions on config file: %v", err) 523 } 524 525 if err = os.Rename(ConfigPath, ConfigPath+".old"); err != nil && !os.IsNotExist(err) { 526 return errors.Errorf("Failed to move previous config to backup location: %v", err) 527 } 528 if err = os.Rename(f.Name(), ConfigPath); err != nil { 529 return errors.Errorf("Failed to move newly written config from %s to final location: %v", f.Name(), err) 530 } 531 if err := os.Remove(ConfigPath + ".old"); err != nil && !os.IsNotExist(err) { 532 fs.Errorf(nil, "Failed to remove backup config file: %v", err) 533 } 534 return nil 535 } 536 537 // SaveConfig calling function which saves configuration file. 538 // if saveConfig returns error trying again after sleep. 539 func SaveConfig() { 540 var err error 541 for i := 0; i < fs.Config.LowLevelRetries+1; i++ { 542 if err = saveConfig(); err == nil { 543 return 544 } 545 waitingTimeMs := mathrand.Intn(1000) 546 time.Sleep(time.Duration(waitingTimeMs) * time.Millisecond) 547 } 548 log.Fatalf("Failed to save config after %d tries: %v", fs.Config.LowLevelRetries, err) 549 550 return 551 } 552 553 // SetValueAndSave sets the key to the value and saves just that 554 // value in the config file. It loads the old config file in from 555 // disk first and overwrites the given value only. 556 func SetValueAndSave(name, key, value string) (err error) { 557 // Set the value in config in case we fail to reload it 558 getConfigData().SetValue(name, key, value) 559 // Reload the config file 560 reloadedConfigFile, err := loadConfigFile() 561 if err == errorConfigFileNotFound { 562 // Config file not written yet so ignore reload 563 return nil 564 } else if err != nil { 565 return err 566 } 567 _, err = reloadedConfigFile.GetSection(name) 568 if err != nil { 569 // Section doesn't exist yet so ignore reload 570 return err 571 } 572 // Update the config file with the reloaded version 573 configFile = reloadedConfigFile 574 // Set the value in the reloaded version 575 reloadedConfigFile.SetValue(name, key, value) 576 // Save it again 577 SaveConfig() 578 return nil 579 } 580 581 // FileGetFresh reads the config key under section return the value or 582 // an error if the config file was not found or that value couldn't be 583 // read. 584 func FileGetFresh(section, key string) (value string, err error) { 585 reloadedConfigFile, err := loadConfigFile() 586 if err != nil { 587 return "", err 588 } 589 return reloadedConfigFile.GetValue(section, key) 590 } 591 592 // ShowRemotes shows an overview of the config file 593 func ShowRemotes() { 594 remotes := getConfigData().GetSectionList() 595 if len(remotes) == 0 { 596 return 597 } 598 sort.Strings(remotes) 599 fmt.Printf("%-20s %s\n", "Name", "Type") 600 fmt.Printf("%-20s %s\n", "====", "====") 601 for _, remote := range remotes { 602 fmt.Printf("%-20s %s\n", remote, FileGet(remote, "type")) 603 } 604 } 605 606 // ChooseRemote chooses a remote name 607 func ChooseRemote() string { 608 remotes := getConfigData().GetSectionList() 609 sort.Strings(remotes) 610 return Choose("remote", remotes, nil, false) 611 } 612 613 // ReadLine reads some input 614 var ReadLine = func() string { 615 buf := bufio.NewReader(os.Stdin) 616 line, err := buf.ReadString('\n') 617 if err != nil { 618 log.Fatalf("Failed to read line: %v", err) 619 } 620 return strings.TrimSpace(line) 621 } 622 623 // Command - choose one 624 func Command(commands []string) byte { 625 opts := []string{} 626 for _, text := range commands { 627 fmt.Printf("%c) %s\n", text[0], text[1:]) 628 opts = append(opts, text[:1]) 629 } 630 optString := strings.Join(opts, "") 631 optHelp := strings.Join(opts, "/") 632 for { 633 fmt.Printf("%s> ", optHelp) 634 result := strings.ToLower(ReadLine()) 635 if len(result) != 1 { 636 continue 637 } 638 i := strings.Index(optString, string(result[0])) 639 if i >= 0 { 640 return result[0] 641 } 642 } 643 } 644 645 // Confirm asks the user for Yes or No and returns true or false 646 // 647 // If AutoConfirm is set, it will return true 648 func Confirm() bool { 649 return Command([]string{"yYes", "nNo"}) == 'y' 650 } 651 652 // ConfirmWithConfig asks the user for Yes or No and returns true or 653 // false. 654 // 655 // If AutoConfirm is set, it will look up the value in m and return 656 // that, but if it isn't set then it will return the Default value 657 // passed in 658 func ConfirmWithConfig(m configmap.Getter, configName string, Default bool) bool { 659 if fs.Config.AutoConfirm { 660 configString, ok := m.Get(configName) 661 if ok { 662 configValue, err := strconv.ParseBool(configString) 663 if err != nil { 664 fs.Errorf(nil, "Failed to parse config parameter %s=%q as boolean - using default %v: %v", configName, configString, Default, err) 665 } else { 666 Default = configValue 667 } 668 } 669 answer := "No" 670 if Default { 671 answer = "Yes" 672 } 673 fmt.Printf("Auto confirm is set: answering %s, override by setting config parameter %s=%v\n", answer, configName, !Default) 674 return Default 675 } 676 return Confirm() 677 } 678 679 // Choose one of the defaults or type a new string if newOk is set 680 func Choose(what string, defaults, help []string, newOk bool) string { 681 valueDescription := "an existing" 682 if newOk { 683 valueDescription = "your own" 684 } 685 fmt.Printf("Choose a number from below, or type in %s value\n", valueDescription) 686 for i, text := range defaults { 687 var lines []string 688 if help != nil { 689 parts := strings.Split(help[i], "\n") 690 lines = append(lines, parts...) 691 } 692 lines = append(lines, fmt.Sprintf("%q", text)) 693 pos := i + 1 694 if len(lines) == 1 { 695 fmt.Printf("%2d > %s\n", pos, text) 696 } else { 697 mid := (len(lines) - 1) / 2 698 for i, line := range lines { 699 var sep rune 700 switch i { 701 case 0: 702 sep = '/' 703 case len(lines) - 1: 704 sep = '\\' 705 default: 706 sep = '|' 707 } 708 number := " " 709 if i == mid { 710 number = fmt.Sprintf("%2d", pos) 711 } 712 fmt.Printf("%s %c %s\n", number, sep, line) 713 } 714 } 715 } 716 for { 717 fmt.Printf("%s> ", what) 718 result := ReadLine() 719 i, err := strconv.Atoi(result) 720 if err != nil { 721 if newOk { 722 return result 723 } 724 for _, v := range defaults { 725 if result == v { 726 return result 727 } 728 } 729 continue 730 } 731 if i >= 1 && i <= len(defaults) { 732 return defaults[i-1] 733 } 734 } 735 } 736 737 // ChooseNumber asks the user to enter a number between min and max 738 // inclusive prompting them with what. 739 func ChooseNumber(what string, min, max int) int { 740 for { 741 fmt.Printf("%s> ", what) 742 result := ReadLine() 743 i, err := strconv.Atoi(result) 744 if err != nil { 745 fmt.Printf("Bad number: %v\n", err) 746 continue 747 } 748 if i < min || i > max { 749 fmt.Printf("Out of range - %d to %d inclusive\n", min, max) 750 continue 751 } 752 return i 753 } 754 } 755 756 // ShowRemote shows the contents of the remote 757 func ShowRemote(name string) { 758 fmt.Printf("--------------------\n") 759 fmt.Printf("[%s]\n", name) 760 fs := MustFindByName(name) 761 for _, key := range getConfigData().GetKeyList(name) { 762 isPassword := false 763 for _, option := range fs.Options { 764 if option.Name == key && option.IsPassword { 765 isPassword = true 766 break 767 } 768 } 769 value := FileGet(name, key) 770 if isPassword && value != "" { 771 fmt.Printf("%s = *** ENCRYPTED ***\n", key) 772 } else { 773 fmt.Printf("%s = %s\n", key, value) 774 } 775 } 776 fmt.Printf("--------------------\n") 777 } 778 779 // OkRemote prints the contents of the remote and ask if it is OK 780 func OkRemote(name string) bool { 781 ShowRemote(name) 782 switch i := Command([]string{"yYes this is OK", "eEdit this remote", "dDelete this remote"}); i { 783 case 'y': 784 return true 785 case 'e': 786 return false 787 case 'd': 788 getConfigData().DeleteSection(name) 789 return true 790 default: 791 fs.Errorf(nil, "Bad choice %c", i) 792 } 793 return false 794 } 795 796 // MustFindByName finds the RegInfo for the remote name passed in or 797 // exits with a fatal error. 798 func MustFindByName(name string) *fs.RegInfo { 799 fsType := FileGet(name, "type") 800 if fsType == "" { 801 log.Fatalf("Couldn't find type of fs for %q", name) 802 } 803 return fs.MustFind(fsType) 804 } 805 806 // RemoteConfig runs the config helper for the remote if needed 807 func RemoteConfig(name string) { 808 fmt.Printf("Remote config\n") 809 f := MustFindByName(name) 810 if f.Config != nil { 811 m := fs.ConfigMap(f, name) 812 f.Config(name, m) 813 } 814 } 815 816 // matchProvider returns true if provider matches the providerConfig string. 817 // 818 // The providerConfig string can either be a list of providers to 819 // match, or if it starts with "!" it will be a list of providers not 820 // to match. 821 // 822 // If either providerConfig or provider is blank then it will return true 823 func matchProvider(providerConfig, provider string) bool { 824 if providerConfig == "" || provider == "" { 825 return true 826 } 827 negate := false 828 if strings.HasPrefix(providerConfig, "!") { 829 providerConfig = providerConfig[1:] 830 negate = true 831 } 832 providers := strings.Split(providerConfig, ",") 833 matched := false 834 for _, p := range providers { 835 if p == provider { 836 matched = true 837 break 838 } 839 } 840 if negate { 841 return !matched 842 } 843 return matched 844 } 845 846 // ChooseOption asks the user to choose an option 847 func ChooseOption(o *fs.Option, name string) string { 848 var subProvider = getConfigData().MustValue(name, fs.ConfigProvider, "") 849 fmt.Println(o.Help) 850 if o.IsPassword { 851 actions := []string{"yYes type in my own password", "gGenerate random password"} 852 if !o.Required { 853 actions = append(actions, "nNo leave this optional password blank") 854 } 855 var password string 856 switch i := Command(actions); i { 857 case 'y': 858 password = ChangePassword("the") 859 case 'g': 860 for { 861 fmt.Printf("Password strength in bits.\n64 is just about memorable\n128 is secure\n1024 is the maximum\n") 862 bits := ChooseNumber("Bits", 64, 1024) 863 bytes := bits / 8 864 if bits%8 != 0 { 865 bytes++ 866 } 867 var pw = make([]byte, bytes) 868 n, _ := rand.Read(pw) 869 if n != bytes { 870 log.Fatalf("password short read: %d", n) 871 } 872 password = base64.RawURLEncoding.EncodeToString(pw) 873 fmt.Printf("Your password is: %s\n", password) 874 fmt.Printf("Use this password? Please note that an obscured version of this \npassword (and not the " + 875 "password itself) will be stored under your \nconfiguration file, so keep this generated password " + 876 "in a safe place.\n") 877 if Confirm() { 878 break 879 } 880 } 881 case 'n': 882 return "" 883 default: 884 fs.Errorf(nil, "Bad choice %c", i) 885 } 886 return obscure.MustObscure(password) 887 } 888 what := fmt.Sprintf("%T value", o.Default) 889 switch o.Default.(type) { 890 case bool: 891 what = "boolean value (true or false)" 892 case fs.SizeSuffix: 893 what = "size with suffix k,M,G,T" 894 case fs.Duration: 895 what = "duration s,m,h,d,w,M,y" 896 case int, int8, int16, int32, int64: 897 what = "signed integer" 898 case uint, byte, uint16, uint32, uint64: 899 what = "unsigned integer" 900 } 901 var in string 902 for { 903 fmt.Printf("Enter a %s. Press Enter for the default (%q).\n", what, fmt.Sprint(o.Default)) 904 if len(o.Examples) > 0 { 905 var values []string 906 var help []string 907 for _, example := range o.Examples { 908 if matchProvider(example.Provider, subProvider) { 909 values = append(values, example.Value) 910 help = append(help, example.Help) 911 } 912 } 913 in = Choose(o.Name, values, help, true) 914 } else { 915 fmt.Printf("%s> ", o.Name) 916 in = ReadLine() 917 } 918 if in == "" { 919 if o.Required && fmt.Sprint(o.Default) == "" { 920 fmt.Printf("This value is required and it has no default.\n") 921 continue 922 } 923 break 924 } 925 newIn, err := configstruct.StringToInterface(o.Default, in) 926 if err != nil { 927 fmt.Printf("Failed to parse %q: %v\n", in, err) 928 continue 929 } 930 in = fmt.Sprint(newIn) // canonicalise 931 break 932 } 933 return in 934 } 935 936 // Suppress the confirm prompts and return a function to undo that 937 func suppressConfirm() func() { 938 old := fs.Config.AutoConfirm 939 fs.Config.AutoConfirm = true 940 return func() { 941 fs.Config.AutoConfirm = old 942 } 943 } 944 945 // UpdateRemote adds the keyValues passed in to the remote of name. 946 // keyValues should be key, value pairs. 947 func UpdateRemote(name string, keyValues rc.Params) error { 948 defer suppressConfirm()() 949 950 // Work out which options need to be obscured 951 needsObscure := map[string]struct{}{} 952 if fsType := FileGet(name, "type"); fsType != "" { 953 if ri, err := fs.Find(fsType); err != nil { 954 fs.Debugf(nil, "Couldn't find fs for type %q", fsType) 955 } else { 956 for _, opt := range ri.Options { 957 if opt.IsPassword { 958 needsObscure[opt.Name] = struct{}{} 959 } 960 } 961 } 962 } else { 963 fs.Debugf(nil, "UpdateRemote: Couldn't find fs type") 964 } 965 966 // Set the config 967 for k, v := range keyValues { 968 vStr := fmt.Sprint(v) 969 // Obscure parameter if necessary 970 if _, ok := needsObscure[k]; ok { 971 _, err := obscure.Reveal(vStr) 972 if err != nil { 973 // If error => not already obscured, so obscure it 974 vStr, err = obscure.Obscure(vStr) 975 if err != nil { 976 return errors.Wrap(err, "UpdateRemote: obscure failed") 977 } 978 } 979 } 980 getConfigData().SetValue(name, k, vStr) 981 } 982 RemoteConfig(name) 983 SaveConfig() 984 return nil 985 } 986 987 // CreateRemote creates a new remote with name, provider and a list of 988 // parameters which are key, value pairs. If update is set then it 989 // adds the new keys rather than replacing all of them. 990 func CreateRemote(name string, provider string, keyValues rc.Params) error { 991 // Delete the old config if it exists 992 getConfigData().DeleteSection(name) 993 // Set the type 994 getConfigData().SetValue(name, "type", provider) 995 // Set the remaining values 996 return UpdateRemote(name, keyValues) 997 } 998 999 // PasswordRemote adds the keyValues passed in to the remote of name. 1000 // keyValues should be key, value pairs. 1001 func PasswordRemote(name string, keyValues rc.Params) error { 1002 defer suppressConfirm()() 1003 for k, v := range keyValues { 1004 keyValues[k] = obscure.MustObscure(fmt.Sprint(v)) 1005 } 1006 return UpdateRemote(name, keyValues) 1007 } 1008 1009 // JSONListProviders prints all the providers and options in JSON format 1010 func JSONListProviders() error { 1011 b, err := json.MarshalIndent(fs.Registry, "", " ") 1012 if err != nil { 1013 return errors.Wrap(err, "failed to marshal examples") 1014 } 1015 _, err = os.Stdout.Write(b) 1016 if err != nil { 1017 return errors.Wrap(err, "failed to write providers list") 1018 } 1019 return nil 1020 } 1021 1022 // fsOption returns an Option describing the possible remotes 1023 func fsOption() *fs.Option { 1024 o := &fs.Option{ 1025 Name: "Storage", 1026 Help: "Type of storage to configure.", 1027 Default: "", 1028 } 1029 for _, item := range fs.Registry { 1030 example := fs.OptionExample{ 1031 Value: item.Name, 1032 Help: item.Description, 1033 } 1034 o.Examples = append(o.Examples, example) 1035 } 1036 o.Examples.Sort() 1037 return o 1038 } 1039 1040 // NewRemoteName asks the user for a name for a remote 1041 func NewRemoteName() (name string) { 1042 for { 1043 fmt.Printf("name> ") 1044 name = ReadLine() 1045 parts := fspath.Matcher.FindStringSubmatch(name + ":") 1046 switch { 1047 case name == "": 1048 fmt.Printf("Can't use empty name.\n") 1049 case driveletter.IsDriveLetter(name): 1050 fmt.Printf("Can't use %q as it can be confused with a drive letter.\n", name) 1051 case parts == nil: 1052 fmt.Printf("Can't use %q as it has invalid characters in it.\n", name) 1053 default: 1054 return name 1055 } 1056 } 1057 } 1058 1059 // editOptions edits the options. If new is true then it just allows 1060 // entry and doesn't show any old values. 1061 func editOptions(ri *fs.RegInfo, name string, isNew bool) { 1062 fmt.Printf("** See help for %s backend at: https://rclone.org/%s/ **\n\n", ri.Name, ri.FileName()) 1063 hasAdvanced := false 1064 for _, advanced := range []bool{false, true} { 1065 if advanced { 1066 if !hasAdvanced { 1067 break 1068 } 1069 fmt.Printf("Edit advanced config? (y/n)\n") 1070 if !Confirm() { 1071 break 1072 } 1073 } 1074 for _, option := range ri.Options { 1075 hasAdvanced = hasAdvanced || option.Advanced 1076 if option.Advanced != advanced { 1077 continue 1078 } 1079 subProvider := getConfigData().MustValue(name, fs.ConfigProvider, "") 1080 if matchProvider(option.Provider, subProvider) { 1081 if !isNew { 1082 fmt.Printf("Value %q = %q\n", option.Name, FileGet(name, option.Name)) 1083 fmt.Printf("Edit? (y/n)>\n") 1084 if !Confirm() { 1085 continue 1086 } 1087 } 1088 if option.Hide&fs.OptionHideConfigurator == 0 { 1089 FileSet(name, option.Name, ChooseOption(&option, name)) 1090 } 1091 } 1092 } 1093 } 1094 } 1095 1096 // NewRemote make a new remote from its name 1097 func NewRemote(name string) { 1098 var ( 1099 newType string 1100 ri *fs.RegInfo 1101 err error 1102 ) 1103 1104 // Set the type first 1105 for { 1106 newType = ChooseOption(fsOption(), name) 1107 ri, err = fs.Find(newType) 1108 if err != nil { 1109 fmt.Printf("Bad remote %q: %v\n", newType, err) 1110 continue 1111 } 1112 break 1113 } 1114 getConfigData().SetValue(name, "type", newType) 1115 1116 editOptions(ri, name, true) 1117 RemoteConfig(name) 1118 if OkRemote(name) { 1119 SaveConfig() 1120 return 1121 } 1122 EditRemote(ri, name) 1123 } 1124 1125 // EditRemote gets the user to edit a remote 1126 func EditRemote(ri *fs.RegInfo, name string) { 1127 ShowRemote(name) 1128 fmt.Printf("Edit remote\n") 1129 for { 1130 editOptions(ri, name, false) 1131 if OkRemote(name) { 1132 break 1133 } 1134 } 1135 SaveConfig() 1136 RemoteConfig(name) 1137 } 1138 1139 // DeleteRemote gets the user to delete a remote 1140 func DeleteRemote(name string) { 1141 getConfigData().DeleteSection(name) 1142 SaveConfig() 1143 } 1144 1145 // copyRemote asks the user for a new remote name and copies name into 1146 // it. Returns the new name. 1147 func copyRemote(name string) string { 1148 newName := NewRemoteName() 1149 // Copy the keys 1150 for _, key := range getConfigData().GetKeyList(name) { 1151 value := getConfigData().MustValue(name, key, "") 1152 getConfigData().SetValue(newName, key, value) 1153 } 1154 return newName 1155 } 1156 1157 // RenameRemote renames a config section 1158 func RenameRemote(name string) { 1159 fmt.Printf("Enter new name for %q remote.\n", name) 1160 newName := copyRemote(name) 1161 if name != newName { 1162 getConfigData().DeleteSection(name) 1163 SaveConfig() 1164 } 1165 } 1166 1167 // CopyRemote copies a config section 1168 func CopyRemote(name string) { 1169 fmt.Printf("Enter name for copy of %q remote.\n", name) 1170 copyRemote(name) 1171 SaveConfig() 1172 } 1173 1174 // ShowConfigLocation prints the location of the config file in use 1175 func ShowConfigLocation() { 1176 if _, err := os.Stat(ConfigPath); os.IsNotExist(err) { 1177 fmt.Println("Configuration file doesn't exist, but rclone will use this path:") 1178 } else { 1179 fmt.Println("Configuration file is stored at:") 1180 } 1181 fmt.Printf("%s\n", ConfigPath) 1182 } 1183 1184 // ShowConfig prints the (unencrypted) config options 1185 func ShowConfig() { 1186 var buf bytes.Buffer 1187 if err := goconfig.SaveConfigData(getConfigData(), &buf); err != nil { 1188 log.Fatalf("Failed to serialize config: %v", err) 1189 } 1190 str := buf.String() 1191 if str == "" { 1192 str = "; empty config\n" 1193 } 1194 fmt.Printf("%s", str) 1195 } 1196 1197 // EditConfig edits the config file interactively 1198 func EditConfig() { 1199 for { 1200 haveRemotes := len(getConfigData().GetSectionList()) != 0 1201 what := []string{"eEdit existing remote", "nNew remote", "dDelete remote", "rRename remote", "cCopy remote", "sSet configuration password", "qQuit config"} 1202 if haveRemotes { 1203 fmt.Printf("Current remotes:\n\n") 1204 ShowRemotes() 1205 fmt.Printf("\n") 1206 } else { 1207 fmt.Printf("No remotes found - make a new one\n") 1208 // take 2nd item and last 2 items of menu list 1209 what = append(what[1:2], what[len(what)-2:]...) 1210 } 1211 switch i := Command(what); i { 1212 case 'e': 1213 name := ChooseRemote() 1214 fs := MustFindByName(name) 1215 EditRemote(fs, name) 1216 case 'n': 1217 NewRemote(NewRemoteName()) 1218 case 'd': 1219 name := ChooseRemote() 1220 DeleteRemote(name) 1221 case 'r': 1222 RenameRemote(ChooseRemote()) 1223 case 'c': 1224 CopyRemote(ChooseRemote()) 1225 case 's': 1226 SetPassword() 1227 case 'q': 1228 return 1229 1230 } 1231 } 1232 } 1233 1234 // SetPassword will allow the user to modify the current 1235 // configuration encryption settings. 1236 func SetPassword() { 1237 for { 1238 if len(configKey) > 0 { 1239 fmt.Println("Your configuration is encrypted.") 1240 what := []string{"cChange Password", "uUnencrypt configuration", "qQuit to main menu"} 1241 switch i := Command(what); i { 1242 case 'c': 1243 changeConfigPassword() 1244 SaveConfig() 1245 fmt.Println("Password changed") 1246 continue 1247 case 'u': 1248 configKey = nil 1249 SaveConfig() 1250 continue 1251 case 'q': 1252 return 1253 } 1254 1255 } else { 1256 fmt.Println("Your configuration is not encrypted.") 1257 fmt.Println("If you add a password, you will protect your login information to cloud services.") 1258 what := []string{"aAdd Password", "qQuit to main menu"} 1259 switch i := Command(what); i { 1260 case 'a': 1261 changeConfigPassword() 1262 SaveConfig() 1263 fmt.Println("Password set") 1264 continue 1265 case 'q': 1266 return 1267 } 1268 } 1269 } 1270 } 1271 1272 // Authorize is for remote authorization of headless machines. 1273 // 1274 // It expects 1 or 3 arguments 1275 // 1276 // rclone authorize "fs name" 1277 // rclone authorize "fs name" "client id" "client secret" 1278 func Authorize(args []string) { 1279 defer suppressConfirm()() 1280 switch len(args) { 1281 case 1, 3: 1282 default: 1283 log.Fatalf("Invalid number of arguments: %d", len(args)) 1284 } 1285 newType := args[0] 1286 f := fs.MustFind(newType) 1287 if f.Config == nil { 1288 log.Fatalf("Can't authorize fs %q", newType) 1289 } 1290 // Name used for temporary fs 1291 name := "**temp-fs**" 1292 1293 // Make sure we delete it 1294 defer DeleteRemote(name) 1295 1296 // Indicate that we are running rclone authorize 1297 getConfigData().SetValue(name, ConfigAuthorize, "true") 1298 if len(args) == 3 { 1299 getConfigData().SetValue(name, ConfigClientID, args[1]) 1300 getConfigData().SetValue(name, ConfigClientSecret, args[2]) 1301 } 1302 m := fs.ConfigMap(f, name) 1303 f.Config(name, m) 1304 } 1305 1306 // FileGetFlag gets the config key under section returning the 1307 // the value and true if found and or ("", false) otherwise 1308 func FileGetFlag(section, key string) (string, bool) { 1309 newValue, err := getConfigData().GetValue(section, key) 1310 return newValue, err == nil 1311 } 1312 1313 // FileGet gets the config key under section returning the 1314 // default or empty string if not set. 1315 // 1316 // It looks up defaults in the environment if they are present 1317 func FileGet(section, key string, defaultVal ...string) string { 1318 envKey := fs.ConfigToEnv(section, key) 1319 newValue, found := os.LookupEnv(envKey) 1320 if found { 1321 defaultVal = []string{newValue} 1322 } 1323 return getConfigData().MustValue(section, key, defaultVal...) 1324 } 1325 1326 // FileSet sets the key in section to value. It doesn't save 1327 // the config file. 1328 func FileSet(section, key, value string) { 1329 if value != "" { 1330 getConfigData().SetValue(section, key, value) 1331 } else { 1332 FileDeleteKey(section, key) 1333 } 1334 } 1335 1336 // FileDeleteKey deletes the config key in the config file. 1337 // It returns true if the key was deleted, 1338 // or returns false if the section or key didn't exist. 1339 func FileDeleteKey(section, key string) bool { 1340 return getConfigData().DeleteKey(section, key) 1341 } 1342 1343 var matchEnv = regexp.MustCompile(`^RCLONE_CONFIG_(.*?)_TYPE=.*$`) 1344 1345 // FileRefresh ensures the latest configFile is loaded from disk 1346 func FileRefresh() error { 1347 reloadedConfigFile, err := loadConfigFile() 1348 if err != nil { 1349 return err 1350 } 1351 configFile = reloadedConfigFile 1352 return nil 1353 } 1354 1355 // FileSections returns the sections in the config file 1356 // including any defined by environment variables. 1357 func FileSections() []string { 1358 sections := getConfigData().GetSectionList() 1359 for _, item := range os.Environ() { 1360 matches := matchEnv.FindStringSubmatch(item) 1361 if len(matches) == 2 { 1362 sections = append(sections, strings.ToLower(matches[1])) 1363 } 1364 } 1365 return sections 1366 } 1367 1368 // DumpRcRemote dumps the config for a single remote 1369 func DumpRcRemote(name string) (dump rc.Params) { 1370 params := rc.Params{} 1371 for _, key := range getConfigData().GetKeyList(name) { 1372 params[key] = FileGet(name, key) 1373 } 1374 return params 1375 } 1376 1377 // DumpRcBlob dumps all the config as an unstructured blob suitable 1378 // for the rc 1379 func DumpRcBlob() (dump rc.Params) { 1380 dump = rc.Params{} 1381 for _, name := range getConfigData().GetSectionList() { 1382 dump[name] = DumpRcRemote(name) 1383 } 1384 return dump 1385 } 1386 1387 // Dump dumps all the config as a JSON file 1388 func Dump() error { 1389 dump := DumpRcBlob() 1390 b, err := json.MarshalIndent(dump, "", " ") 1391 if err != nil { 1392 return errors.Wrap(err, "failed to marshal config dump") 1393 } 1394 _, err = os.Stdout.Write(b) 1395 if err != nil { 1396 return errors.Wrap(err, "failed to write config dump") 1397 } 1398 return nil 1399 } 1400 1401 // makeCacheDir returns a directory to use for caching. 1402 // 1403 // Code borrowed from go stdlib until it is made public 1404 func makeCacheDir() (dir string) { 1405 // Compute default location. 1406 switch runtime.GOOS { 1407 case "windows": 1408 dir = os.Getenv("LocalAppData") 1409 1410 case "darwin": 1411 dir = os.Getenv("HOME") 1412 if dir != "" { 1413 dir += "/Library/Caches" 1414 } 1415 1416 case "plan9": 1417 dir = os.Getenv("home") 1418 if dir != "" { 1419 // Plan 9 has no established per-user cache directory, 1420 // but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix. 1421 dir += "/lib/cache" 1422 } 1423 1424 default: // Unix 1425 // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html 1426 dir = os.Getenv("XDG_CACHE_HOME") 1427 if dir == "" { 1428 dir = os.Getenv("HOME") 1429 if dir != "" { 1430 dir += "/.cache" 1431 } 1432 } 1433 } 1434 1435 // if no dir found then use TempDir - we will have a cachedir! 1436 if dir == "" { 1437 dir = os.TempDir() 1438 } 1439 return filepath.Join(dir, "rclone") 1440 }