mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-26 21:07:45 +08:00
Merge pull request #7599 from ipfs/feat/move-key-rotate
Move key rotation command to ipfs key rotate
This commit is contained in:
commit
992e4a71ca
@ -22,7 +22,6 @@ var commandsClientCmd = commands.CommandsCmd(Root)
|
||||
var localCommands = map[string]*cmds.Command{
|
||||
"daemon": daemonCmd,
|
||||
"init": initCmd,
|
||||
"rotate": rotateCmd,
|
||||
"commands": commandsClientCmd,
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -138,6 +138,7 @@ func TestCommands(t *testing.T) {
|
||||
"/key/list",
|
||||
"/key/rename",
|
||||
"/key/rm",
|
||||
"/key/rotate",
|
||||
"/log",
|
||||
"/log/level",
|
||||
"/log/ls",
|
||||
|
||||
@ -11,6 +11,8 @@ import (
|
||||
"text/tabwriter"
|
||||
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
config "github.com/ipfs/go-ipfs-config"
|
||||
oldcmds "github.com/ipfs/go-ipfs/commands"
|
||||
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
|
||||
"github.com/ipfs/go-ipfs/core/commands/e"
|
||||
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
|
||||
@ -44,6 +46,7 @@ publish'.
|
||||
"list": keyListCmd,
|
||||
"rename": keyRenameCmd,
|
||||
"rm": keyRmCmd,
|
||||
"rotate": keyRotateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
@ -65,9 +68,11 @@ type KeyRenameOutput struct {
|
||||
}
|
||||
|
||||
const (
|
||||
keyStoreTypeOptionName = "type"
|
||||
keyStoreSizeOptionName = "size"
|
||||
keyFormatOptionName = "format"
|
||||
keyStoreAlgorithmDefault = options.RSAKey
|
||||
keyStoreTypeOptionName = "type"
|
||||
keyStoreSizeOptionName = "size"
|
||||
keyFormatOptionName = "format"
|
||||
oldKeyOptionName = "oldkey"
|
||||
)
|
||||
|
||||
var keyGenCmd = &cmds.Command{
|
||||
@ -75,7 +80,7 @@ var keyGenCmd = &cmds.Command{
|
||||
Tagline: "Create a new keypair",
|
||||
},
|
||||
Options: []cmds.Option{
|
||||
cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create: rsa, ed25519").WithDefault("rsa"),
|
||||
cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create: rsa, ed25519").WithDefault(keyStoreAlgorithmDefault),
|
||||
cmds.IntOption(keyStoreSizeOptionName, "s", "size of the key to generate"),
|
||||
cmds.StringOption(keyFormatOptionName, "f", "output format: b58mh or b36cid").WithDefault("b58mh"),
|
||||
},
|
||||
@ -413,6 +418,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(keyStoreAlgorithmDefault),
|
||||
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":
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 -t=rsa -s=2048 --oldkey=oldkey
|
||||
;;
|
||||
ed25519)
|
||||
ipfs rotate -a=ed25519 --oldkey=oldkey
|
||||
ipfs key rotate -t=ed25519 --oldkey=oldkey
|
||||
;;
|
||||
*)
|
||||
ipfs rotate --oldkey=oldkey
|
||||
ipfs key rotate --oldkey=oldkey
|
||||
;;
|
||||
esac
|
||||
'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user