diff --git a/cmd/ipfs/rotate.go b/cmd/ipfs/rotate.go deleted file mode 100644 index 2dd583ab66ef..000000000000 --- a/cmd/ipfs/rotate.go +++ /dev/null @@ -1,116 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" - - cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" - oldcmds "github.com/ipfs/go-ipfs/commands" - fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" - "github.com/ipfs/interface-go-ipfs-core/options" -) - -const ( - oldKeyOptionName = "oldkey" -) - -var rotateCmd = &cmds.Command{ - Helptext: cmds.HelpText{ - Tagline: "Rotates the ipfs identity.", - ShortDescription: ` -Generates a new ipfs identity and saves it to the ipfs config file. -The daemon must not be running when calling this command. - -ipfs uses a repository in the local file system. By default, the repo is -located at ~/.ipfs. To change the repo location, set the $IPFS_PATH -environment variable: - - export IPFS_PATH=/path/to/ipfsrepo -`, - }, - Arguments: []cmds.Argument{}, - Options: []cmds.Option{ - cmds.StringOption(oldKeyOptionName, "o", "Keystore name for the old/rotated-out key."), - cmds.StringOption(algorithmOptionName, "a", "Cryptographic algorithm to use for key generation.").WithDefault(algorithmDefault), - cmds.IntOption(bitsOptionName, "b", "Number of bits to use in the generated RSA private key."), - }, - NoRemote: true, - PreRun: func(req *cmds.Request, env cmds.Environment) error { - cctx := env.(*oldcmds.Context) - daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot) - if err != nil { - return err - } - - log.Info("checking if daemon is running...") - if daemonLocked { - log.Debug("ipfs daemon is running") - e := "ipfs daemon is running. please stop it to run this command" - return cmds.ClientError(e) - } - - return nil - }, - Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - cctx := env.(*oldcmds.Context) - nBitsForKeypair, nBitsGiven := req.Options[bitsOptionName].(int) - algorithm, _ := req.Options[algorithmOptionName].(string) - oldKey, ok := req.Options[oldKeyOptionName].(string) - if !ok { - return fmt.Errorf("keystore name for backing up old key must be provided") - } - return doRotate(os.Stdout, cctx.ConfigRoot, oldKey, algorithm, nBitsForKeypair, nBitsGiven) - }, -} - -func doRotate(out io.Writer, repoRoot string, oldKey string, algorithm string, nBitsForKeypair int, nBitsGiven bool) error { - // Open repo - repo, err := fsrepo.Open(repoRoot) - if err != nil { - return fmt.Errorf("opening repo (%v)", err) - } - defer repo.Close() - - // Read config file from repo - cfg, err := repo.Config() - if err != nil { - return fmt.Errorf("reading config from repo (%v)", err) - } - - // Generate new identity - var identity config.Identity - if nBitsGiven { - identity, err = config.CreateIdentity(out, []options.KeyGenerateOption{ - options.Key.Size(nBitsForKeypair), - options.Key.Type(algorithm), - }) - } else { - identity, err = config.CreateIdentity(out, []options.KeyGenerateOption{ - options.Key.Type(algorithm), - }) - } - if err != nil { - return fmt.Errorf("creating identity (%v)", err) - } - - // Save old identity to keystore - oldPrivKey, err := cfg.Identity.DecodePrivateKey("") - if err != nil { - return fmt.Errorf("decoding old private key (%v)", err) - } - keystore := repo.Keystore() - if err := keystore.Put(oldKey, oldPrivKey); err != nil { - return fmt.Errorf("saving old key in keystore (%v)", err) - } - - // Update identity - cfg.Identity = identity - - // Write config file to repo - if err = repo.SetConfig(cfg); err != nil { - return fmt.Errorf("saving new key to config (%v)", err) - } - return nil -} diff --git a/core/commands/keystore.go b/core/commands/keystore.go index 639cc5fabd96..bce4702a3cc1 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -3,6 +3,8 @@ package commands import ( "bytes" "fmt" + config "github.com/ipfs/go-ipfs-config" + oldcmds "github.com/ipfs/go-ipfs/commands" "io" "io/ioutil" "os" @@ -44,6 +46,7 @@ publish'. "list": keyListCmd, "rename": keyRenameCmd, "rm": keyRmCmd, + "rotate": keyRotateCmd, }, } @@ -68,6 +71,7 @@ const ( keyStoreTypeOptionName = "type" keyStoreSizeOptionName = "size" keyFormatOptionName = "format" + oldKeyOptionName = "oldkey" ) var keyGenCmd = &cmds.Command{ @@ -413,6 +417,105 @@ var keyRmCmd = &cmds.Command{ Type: KeyOutputList{}, } +var keyRotateCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "Rotates the ipfs identity.", + ShortDescription: ` +Generates a new ipfs identity and saves it to the ipfs config file. +The daemon must not be running when calling this command. + +ipfs uses a repository in the local file system. By default, the repo is +located at ~/.ipfs. To change the repo location, set the $IPFS_PATH +environment variable: + + export IPFS_PATH=/path/to/ipfsrepo +`, + }, + Arguments: []cmds.Argument{}, + Options: []cmds.Option{ + cmds.StringOption(oldKeyOptionName, "o", "Keystore name for the old/rotated-out key."), + cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create: rsa, ed25519").WithDefault("rsa"), + cmds.IntOption(keyStoreSizeOptionName, "s", "size of the key to generate"), + }, + NoRemote: true, + PreRun: func(req *cmds.Request, env cmds.Environment) error { + cctx := env.(*oldcmds.Context) + daemonLocked, err := fsrepo.LockedByOtherProcess(cctx.ConfigRoot) + if err != nil { + return err + } + + log.Info("checking if daemon is running...") + if daemonLocked { + log.Debug("ipfs daemon is running") + e := "ipfs daemon is running. please stop it to run this command" + return cmds.ClientError(e) + } + + return nil + }, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + cctx := env.(*oldcmds.Context) + nBitsForKeypair, nBitsGiven := req.Options[keyStoreSizeOptionName].(int) + algorithm, _ := req.Options[keyStoreTypeOptionName].(string) + oldKey, ok := req.Options[oldKeyOptionName].(string) + if !ok { + return fmt.Errorf("keystore name for backing up old key must be provided") + } + return doRotate(os.Stdout, cctx.ConfigRoot, oldKey, algorithm, nBitsForKeypair, nBitsGiven) + }, +} + +func doRotate(out io.Writer, repoRoot string, oldKey string, algorithm string, nBitsForKeypair int, nBitsGiven bool) error { + // Open repo + repo, err := fsrepo.Open(repoRoot) + if err != nil { + return fmt.Errorf("opening repo (%v)", err) + } + defer repo.Close() + + // Read config file from repo + cfg, err := repo.Config() + if err != nil { + return fmt.Errorf("reading config from repo (%v)", err) + } + + // Generate new identity + var identity config.Identity + if nBitsGiven { + identity, err = config.CreateIdentity(out, []options.KeyGenerateOption{ + options.Key.Size(nBitsForKeypair), + options.Key.Type(algorithm), + }) + } else { + identity, err = config.CreateIdentity(out, []options.KeyGenerateOption{ + options.Key.Type(algorithm), + }) + } + if err != nil { + return fmt.Errorf("creating identity (%v)", err) + } + + // Save old identity to keystore + oldPrivKey, err := cfg.Identity.DecodePrivateKey("") + if err != nil { + return fmt.Errorf("decoding old private key (%v)", err) + } + keystore := repo.Keystore() + if err := keystore.Put(oldKey, oldPrivKey); err != nil { + return fmt.Errorf("saving old key in keystore (%v)", err) + } + + // Update identity + cfg.Identity = identity + + // Write config file to repo + if err = repo.SetConfig(cfg); err != nil { + return fmt.Errorf("saving new key to config (%v)", err) + } + return nil +} + func verifyIDFormatLabel(formatLabel string) error { switch formatLabel { case "b58mh": diff --git a/namesys/ipns_resolver_validation_test.go b/namesys/ipns_resolver_validation_test.go index 1e342f259048..5dbfabf9cd39 100644 --- a/namesys/ipns_resolver_validation_test.go +++ b/namesys/ipns_resolver_validation_test.go @@ -146,7 +146,7 @@ func genKeys(t *testing.T, keyType int) (ci.PrivKey, peer.ID, string, string) { return sk, id, PkKeyForID(id), ipns.RecordKey(id) } -func createIPNSRecordWithEmbeddedPublicKey(sk ci.PrivKey, val []byte, seq uint64, eol time.Time) (*ipns_pb.IpnsEntry, error){ +func createIPNSRecordWithEmbeddedPublicKey(sk ci.PrivKey, val []byte, seq uint64, eol time.Time) (*ipns_pb.IpnsEntry, error) { entry, err := ipns.Create(sk, val, seq, eol) if err != nil { return nil, err diff --git a/test/sharness/t0027-rotate.sh b/test/sharness/t0027-rotate.sh index ddc07bbc784b..9a9b70ef8b3c 100755 --- a/test/sharness/t0027-rotate.sh +++ b/test/sharness/t0027-rotate.sh @@ -35,13 +35,13 @@ test_rotate() { test_expect_success "rotating keys" ' case $TO_ALG in rsa) - ipfs rotate -a=rsa -b=2048 --oldkey=oldkey + ipfs key rotate -a=rsa -b=2048 --oldkey=oldkey ;; ed25519) - ipfs rotate -a=ed25519 --oldkey=oldkey + ipfs key rotate -a=ed25519 --oldkey=oldkey ;; *) - ipfs rotate --oldkey=oldkey + ipfs key rotate --oldkey=oldkey ;; esac '