ethkey: Added --stdoutkeystore parameter to avoid I/O operations

This commit is contained in:
Konrad Janica 2018-01-21 13:24:00 -08:00
parent 02aeb3d766
commit 1b2915451b
2 changed files with 88 additions and 56 deletions

View file

@ -13,6 +13,8 @@ If you want to use an existing private key to use in the keyfile, it can be
specified by setting `--privatekey` with the location of the file containing the specified by setting `--privatekey` with the location of the file containing the
private key. private key.
`--stdoutkeystore` option is available to avoid writing the keystore to file and
instead output and entire contents of the keystore to standard output (stdout).
### `ethkey inspect <keyfile>` ### `ethkey inspect <keyfile>`
@ -39,3 +41,8 @@ For every command that uses a keyfile, you will be prompted to provide the
passphrase for decrypting the keyfile. To avoid this message, it is possible passphrase for decrypting the keyfile. To avoid this message, it is possible
to pass the passphrase by using the `--passphrase` flag pointing to a file that to pass the passphrase by using the `--passphrase` flag pointing to a file that
contains the passphrase. contains the passphrase.
## JSON
For every command with output, the `--json` option is available to output JSON
instead of human-readable format.

View file

@ -52,67 +52,92 @@ If you want to encrypt an existing private key, it can be specified by setting
Name: "privatekey", Name: "privatekey",
Usage: "file containing a raw private key to encrypt", Usage: "file containing a raw private key to encrypt",
}, },
cli.BoolFlag{
Name: "stdoutkeystore",
Usage: "prevents writing keystore to file, instead outputs the keystore to standard output (stdout)",
},
}, },
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
// Check if keyfile path given and make sure it doesn't already exist. if ctx.Bool("stdoutkeystore") {
keyfilepath := ctx.Args().First() // Generate and output the keystore
if keyfilepath == "" { _, keyjson := newKeyStore(ctx)
keyfilepath = defaultKeyfileName fmt.Printf("%s\n", keyjson)
}
if _, err := os.Stat(keyfilepath); err == nil {
utils.Fatalf("Keyfile already exists at %s.", keyfilepath)
} else if !os.IsNotExist(err) {
utils.Fatalf("Error checking if keyfile exists: %v", err)
}
var privateKey *ecdsa.PrivateKey
var err error
if file := ctx.String("privatekey"); file != "" {
// Load private key from file.
privateKey, err = crypto.LoadECDSA(file)
if err != nil {
utils.Fatalf("Can't load private key: %v", err)
}
} else { } else {
// If not loaded, generate random. // Generate and write keystore to file
privateKey, err = crypto.GenerateKey() storeKeyStore(ctx)
if err != nil {
utils.Fatalf("Failed to generate random private key: %v", err)
}
} }
// Create the keyfile object with a random UUID.
id := uuid.NewRandom()
key := &keystore.Key{
Id: id,
Address: crypto.PubkeyToAddress(privateKey.PublicKey),
PrivateKey: privateKey,
}
// Encrypt key with passphrase.
passphrase := getPassPhrase(ctx, true)
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
utils.Fatalf("Error encrypting key: %v", err)
}
// Store the file to disk.
if err := os.MkdirAll(filepath.Dir(keyfilepath), 0700); err != nil {
utils.Fatalf("Could not create directory %s", filepath.Dir(keyfilepath))
}
if err := ioutil.WriteFile(keyfilepath, keyjson, 0600); err != nil {
utils.Fatalf("Failed to write keyfile to %s: %v", keyfilepath, err)
}
// Output some information.
out := outputGenerate{
Address: key.Address.Hex(),
}
if ctx.Bool(jsonFlag.Name) {
mustPrintJSON(out)
} else {
fmt.Println("Address:", out.Address)
}
return nil return nil
}, },
} }
// storeKeyStore creates and stores a keystore from given parameters.
// exits the program with an error message on failure.
func storeKeyStore(ctx *cli.Context) {
// Check if keyfile path given and make sure it doesn't already exist.
keyfilepath := ctx.Args().First()
if keyfilepath == "" {
keyfilepath = defaultKeyfileName
}
if _, err := os.Stat(keyfilepath); err == nil {
utils.Fatalf("Keyfile already exists at %s.", keyfilepath)
} else if !os.IsNotExist(err) {
utils.Fatalf("Error checking if keyfile exists: %v", err)
}
key, keyjson := newKeyStore(ctx)
if err := os.MkdirAll(filepath.Dir(keyfilepath), 0700); err != nil {
utils.Fatalf("Could not create directory %s", filepath.Dir(keyfilepath))
}
if err := ioutil.WriteFile(keyfilepath, keyjson, 0600); err != nil {
utils.Fatalf("Failed to write keyfile to %s: %v", keyfilepath, err)
}
// Output some information.
out := outputGenerate{
Address: key.Address.Hex(),
}
if ctx.Bool(jsonFlag.Name) {
mustPrintJSON(out)
} else {
fmt.Println("Address:", out.Address)
}
}
// newKeyStore outputs a new key and keystore from given parameters
// exits the program with an error message on failure.
func newKeyStore(ctx *cli.Context) (*keystore.Key, []byte) {
var privateKey *ecdsa.PrivateKey
var err error
if file := ctx.String("privatekey"); file != "" {
// Load private key from file.
privateKey, err = crypto.LoadECDSA(file)
if err != nil {
utils.Fatalf("Can't load private key: %v", err)
}
} else {
// If not loaded, generate random.
privateKey, err = crypto.GenerateKey()
if err != nil {
utils.Fatalf("Failed to generate random private key: %v", err)
}
}
// Create the keyfile object with a random UUID.
id := uuid.NewRandom()
key := &keystore.Key{
Id: id,
Address: crypto.PubkeyToAddress(privateKey.PublicKey),
PrivateKey: privateKey,
}
// Encrypt key with passphrase.
passphrase := getPassPhrase(ctx, true)
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
utils.Fatalf("Error encrypting key: %v", err)
}
return key, keyjson
}