github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/kbpagesconfig/cmd_upgrade.go (about) 1 // Copyright 2018 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "context" 9 "fmt" 10 "os" 11 "strings" 12 13 "github.com/keybase/client/go/kbfs/libpages/config" 14 "github.com/keybase/client/go/minterm" 15 "github.com/urfave/cli" 16 ) 17 18 func migrateUserToSHA256Hash(p prompter, username string, oldConfig config.Config) (sha256Hash string, err error) { 19 for { // loop until user ctrl-C the command 20 input, err := p.PromptPassword(fmt.Sprintf( 21 "enter the password for %s: ", username)) 22 if err != nil { 23 fmt.Fprintf(os.Stderr, "getting password error: %v\n", err) 24 continue 25 } 26 password := strings.TrimSpace(input) 27 if len(password) == 0 { 28 fmt.Fprintf(os.Stderr, "empty password\n") 29 continue 30 } 31 if oldConfig.Authenticate(context.Background(), username, password) { 32 return config.GenerateSHA256PasswordHash(password) 33 } 34 fmt.Fprintf(os.Stderr, "password for %s doesn't match what's in the old config file\n", username) 35 confirmed, err := promptConfirm(p, fmt.Sprintf( 36 "The password you entered for %s doesn't match what's "+ 37 "currently in the old config file. Still use it?\n", 38 username), false) 39 if err != nil { 40 fmt.Fprintf(os.Stderr, "getting confirmation error: %v\n", err) 41 continue 42 } 43 if confirmed { 44 return config.GenerateSHA256PasswordHash(password) 45 } 46 } 47 } 48 49 func upgradeToSHA256WithPrompter(kbpConfigDir string, prompter prompter) (err error) { 50 kbpConfigPath, err := kbpConfigPath(kbpConfigDir) 51 if err != nil { 52 return err 53 } 54 f, err := os.Open(kbpConfigPath) 55 switch { 56 case err == nil: 57 case os.IsNotExist(err): 58 return fmt.Errorf("no kbpages config file exists in %s", kbpConfigDir) 59 default: 60 return fmt.Errorf("open file %s error: %v", kbpConfigPath, err) 61 } 62 63 cfg, originalConfigStr, err := readConfigAndClose(f) 64 if err != nil { 65 return fmt.Errorf( 66 "reading config file %s error: %v", kbpConfigPath, err) 67 } 68 if cfg.Version() != config.Version1 { 69 return fmt.Errorf( 70 "unsupported config version %s", cfg.Version()) 71 } 72 73 oldConfig := cfg.(*config.V1) 74 needsUpgrade, err := oldConfig.HasBcryptPasswords() 75 if err != nil { 76 return err 77 } 78 if !needsUpgrade { 79 fmt.Printf("Config file %s is already the latest version (%s).\n", 80 kbpConfigPath, cfg.Version()) 81 return nil 82 } 83 84 confirmed, err := promptConfirm(prompter, 85 "You are about to migrate some password hashes in your "+ 86 "kbpages config file from bcrypt to sha256. You will be "+ 87 "prompted to enter passwords for each user one by one. "+ 88 "If you don't know the password for any user(s), you may "+ 89 "enter new passwords for them. Continue?", true) 90 if err != nil { 91 return err 92 } 93 if !confirmed { 94 return fmt.Errorf("not confirmed") 95 } 96 97 newConfig := config.DefaultV1() 98 for p, acl := range oldConfig.ACLs { 99 if newConfig.ACLs == nil { 100 newConfig.ACLs = make(map[string]config.PerPathConfigV1) 101 } 102 // shadow copy since oldConfig is one-time use anyway 103 newConfig.ACLs[p] = acl 104 } 105 for p, perPathConfig := range oldConfig.PerPathConfigs { 106 if newConfig.PerPathConfigs == nil { 107 newConfig.PerPathConfigs = make(map[string]config.PerPathConfigV1) 108 } 109 // shadow copy since oldConfig is one-time use anyway 110 newConfig.PerPathConfigs[p] = perPathConfig 111 } 112 for user := range oldConfig.Users { 113 if newConfig.Users == nil { 114 newConfig.Users = make(map[string]string) 115 } 116 newConfig.Users[user], err = migrateUserToSHA256Hash( 117 prompter, user, oldConfig) 118 if err != nil { 119 return fmt.Errorf("migrating to sha256 error: %v", err) 120 } 121 } 122 return confirmAndWrite(originalConfigStr, newConfig, 123 kbpConfigPath, prompter) 124 } 125 126 func upgradeToSHA256(c *cli.Context) { 127 term, err := minterm.New() 128 if err != nil { 129 fmt.Fprintf(os.Stderr, "opening terminal error: %s\n", err) 130 os.Exit(1) 131 } 132 if err = upgradeToSHA256WithPrompter(c.GlobalString("dir"), term); err != nil { 133 fmt.Fprintf(os.Stderr, "upgrading to SHA256 error: %s\n", err) 134 os.Exit(1) 135 } 136 } 137 138 var upgradeCmd = cli.Command{ 139 Name: "upgrade", 140 Usage: "upgrade config file to the latest version", 141 UsageText: "upgrade", 142 Action: upgradeToSHA256, 143 }