mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 12:37:59 +00:00 
			
		
		
		
	@mitchellh suggested we fork `cli` and switch to that. Since we primarily use the interfaces in `cli`, and the new fork has not changed those, this is (mostly) a drop-in replacement. A small fix will be necessary for Vault Enterprise, I believe.
		
			
				
	
	
		
			629 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			629 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: BUSL-1.1
 | 
						|
 | 
						|
package command
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/hashicorp/cli"
 | 
						|
	"github.com/hashicorp/go-secure-stdlib/password"
 | 
						|
	"github.com/hashicorp/vault/api"
 | 
						|
	"github.com/hashicorp/vault/helper/pgpkeys"
 | 
						|
	"github.com/hashicorp/vault/sdk/helper/roottoken"
 | 
						|
	"github.com/posener/complete"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	_ cli.Command             = (*OperatorGenerateRootCommand)(nil)
 | 
						|
	_ cli.CommandAutocomplete = (*OperatorGenerateRootCommand)(nil)
 | 
						|
)
 | 
						|
 | 
						|
type generateRootKind int
 | 
						|
 | 
						|
const (
 | 
						|
	generateRootRegular generateRootKind = iota
 | 
						|
	generateRootDR
 | 
						|
	generateRootRecovery
 | 
						|
)
 | 
						|
 | 
						|
type OperatorGenerateRootCommand struct {
 | 
						|
	*BaseCommand
 | 
						|
 | 
						|
	flagInit          bool
 | 
						|
	flagCancel        bool
 | 
						|
	flagStatus        bool
 | 
						|
	flagDecode        string
 | 
						|
	flagOTP           string
 | 
						|
	flagPGPKey        string
 | 
						|
	flagNonce         string
 | 
						|
	flagGenerateOTP   bool
 | 
						|
	flagDRToken       bool
 | 
						|
	flagRecoveryToken bool
 | 
						|
 | 
						|
	testStdin io.Reader // for tests
 | 
						|
}
 | 
						|
 | 
						|
func (c *OperatorGenerateRootCommand) Synopsis() string {
 | 
						|
	return "Generates a new root, DR operation, or recovery token"
 | 
						|
}
 | 
						|
 | 
						|
func (c *OperatorGenerateRootCommand) Help() string {
 | 
						|
	helpText := `
 | 
						|
Usage: vault operator generate-root [options] -init [-otp=...] [-pgp-key=...]
 | 
						|
       vault operator generate-root [options] [-nonce=... KEY]
 | 
						|
       vault operator generate-root [options] -decode=... -otp=...
 | 
						|
       vault operator generate-root [options] -generate-otp
 | 
						|
       vault operator generate-root [options] -status
 | 
						|
       vault operator generate-root [options] -cancel
 | 
						|
 | 
						|
  Generates a new root token by combining a quorum of share holders.
 | 
						|
 | 
						|
  This command is unusual, as it is effectively six separate subcommands,
 | 
						|
  selected via the options -init, -decode, -generate-otp, -status, -cancel, 
 | 
						|
  or the absence of any of the previous five options (which selects the 
 | 
						|
  "provide a key share" form).
 | 
						|
 | 
						|
  With the -dr-token or -recovery-token options, a DR operation token or a
 | 
						|
  recovery token is generated instead of a root token - the relevant option
 | 
						|
  must be included in every form of the generate-root command.
 | 
						|
 | 
						|
  Form 1 (-init) - Start a token generation:
 | 
						|
 | 
						|
    When starting a root or privileged operation token generation, you must
 | 
						|
    choose one of the following protection methods for how the token will be
 | 
						|
    returned:
 | 
						|
 | 
						|
      - A base64-encoded one-time-password (OTP). The resulting token is XORed
 | 
						|
        with this value when it is returned. Use the "-decode" form of this
 | 
						|
        command to output the final value.
 | 
						|
 | 
						|
        The Vault server will generate a suitable OTP for you, and return it:
 | 
						|
 | 
						|
            $ vault operator generate-root -init
 | 
						|
 | 
						|
        Vault versions before 0.11.2, released in 2018, required you to
 | 
						|
        generate your own OTP (see the "-generate-otp" form) and pass it in,
 | 
						|
        but this is no longer necessary. The command is still supported for
 | 
						|
        compatibility, though:
 | 
						|
 | 
						|
            $ vault operator generate-root -init -otp="..."
 | 
						|
 | 
						|
      - A PGP key. The resulting token is encrypted with this public key.
 | 
						|
        The key may be specified as a path to a file, or a string of the
 | 
						|
        form "keybase:<username>" to fetch the key from the keybase.io API.
 | 
						|
 | 
						|
            $ vault operator generate-root -init -pgp-key="..."
 | 
						|
 | 
						|
  Form 2 (no option) - Enter an unseal key to progress root token generation:
 | 
						|
 | 
						|
    In the sub-form intended for interactive use, the command will
 | 
						|
    automatically look up the nonce of the currently active generation
 | 
						|
    operation, and will prompt for the key to be entered:
 | 
						|
 | 
						|
        $ vault operator generate-root
 | 
						|
 | 
						|
    In the sub-form intended for automation, the operation nonce must be
 | 
						|
    explicitly provided, and the key is provided directly on the command line
 | 
						|
 | 
						|
        $ vault operator generate-root -nonce=... KEY
 | 
						|
 | 
						|
    If key is specified as "-", the command will read from stdin.
 | 
						|
 | 
						|
  Form 3 (-decode) - Decode a generated token protected with an OTP:
 | 
						|
 | 
						|
        $ vault operator generate-root -decode=ENCODED_TOKEN -otp=OTP
 | 
						|
 | 
						|
    If encoded token is specified as "-", the command will read from stdin.
 | 
						|
 | 
						|
  Form 4 (-generate-otp) - Generate an OTP code for the final token:
 | 
						|
 | 
						|
        $ vault operator generate-root -generate-otp
 | 
						|
 | 
						|
    Since changes in Vault 0.11.2 in 2018, there is no longer any reason to
 | 
						|
    use this form, as a suitable OTP will be returned as part of the "-init"
 | 
						|
    command.
 | 
						|
 | 
						|
  Form 5 (-status) - Get the status of a token generation that is in progress:
 | 
						|
 | 
						|
        $ vault operator generate-root -status
 | 
						|
 | 
						|
    This form also returns the length of the a correct OTP, for the running
 | 
						|
    version and configuration of Vault.
 | 
						|
 | 
						|
  Form 6 (-cancel) - Cancel a token generation that is in progress:
 | 
						|
 | 
						|
    This would be used to remove an in progress generation operation, so that
 | 
						|
    a new one can be started with different parameters.
 | 
						|
 | 
						|
        $ vault operator generate-root -cancel
 | 
						|
 | 
						|
` + c.Flags().Help()
 | 
						|
	return strings.TrimSpace(helpText)
 | 
						|
}
 | 
						|
 | 
						|
func (c *OperatorGenerateRootCommand) Flags() *FlagSets {
 | 
						|
	set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
 | 
						|
 | 
						|
	f := set.NewFlagSet("Command Options")
 | 
						|
 | 
						|
	f.BoolVar(&BoolVar{
 | 
						|
		Name:       "init",
 | 
						|
		Target:     &c.flagInit,
 | 
						|
		Default:    false,
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictNothing,
 | 
						|
		Usage: "Start a root token generation. This can only be done if " +
 | 
						|
			"there is not currently one in progress.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.BoolVar(&BoolVar{
 | 
						|
		Name:       "cancel",
 | 
						|
		Target:     &c.flagCancel,
 | 
						|
		Default:    false,
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictNothing,
 | 
						|
		Usage: "Reset the root token generation progress. This will discard any " +
 | 
						|
			"submitted unseal keys or configuration.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.BoolVar(&BoolVar{
 | 
						|
		Name:       "status",
 | 
						|
		Target:     &c.flagStatus,
 | 
						|
		Default:    false,
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictNothing,
 | 
						|
		Usage: "Print the status of the current attempt without providing an " +
 | 
						|
			"unseal key.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.StringVar(&StringVar{
 | 
						|
		Name:       "decode",
 | 
						|
		Target:     &c.flagDecode,
 | 
						|
		Default:    "",
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictAnything,
 | 
						|
		Usage: "The value to decode; setting this triggers a decode operation. " +
 | 
						|
			" If the value is \"-\" then read the encoded token from stdin.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.BoolVar(&BoolVar{
 | 
						|
		Name:       "generate-otp",
 | 
						|
		Target:     &c.flagGenerateOTP,
 | 
						|
		Default:    false,
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictNothing,
 | 
						|
		Usage: "Generate and print a high-entropy one-time-password (OTP) " +
 | 
						|
			"suitable for use with the \"-init\" flag.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.BoolVar(&BoolVar{
 | 
						|
		Name:       "dr-token",
 | 
						|
		Target:     &c.flagDRToken,
 | 
						|
		Default:    false,
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictNothing,
 | 
						|
		Usage: "Set this flag to do generate root operations on DR operation " +
 | 
						|
			"tokens.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.BoolVar(&BoolVar{
 | 
						|
		Name:       "recovery-token",
 | 
						|
		Target:     &c.flagRecoveryToken,
 | 
						|
		Default:    false,
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictNothing,
 | 
						|
		Usage: "Set this flag to do generate root operations on recovery " +
 | 
						|
			"tokens.",
 | 
						|
	})
 | 
						|
 | 
						|
	f.StringVar(&StringVar{
 | 
						|
		Name:       "otp",
 | 
						|
		Target:     &c.flagOTP,
 | 
						|
		Default:    "",
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictAnything,
 | 
						|
		Usage:      "OTP code to use with \"-decode\" or \"-init\".",
 | 
						|
	})
 | 
						|
 | 
						|
	f.VarFlag(&VarFlag{
 | 
						|
		Name:       "pgp-key",
 | 
						|
		Value:      (*pgpkeys.PubKeyFileFlag)(&c.flagPGPKey),
 | 
						|
		Default:    "",
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictAnything,
 | 
						|
		Usage: "Path to a file on disk containing a binary or base64-encoded " +
 | 
						|
			"public PGP key. This can also be specified as a Keybase username " +
 | 
						|
			"using the format \"keybase:<username>\". When supplied, the generated " +
 | 
						|
			"root token will be encrypted and base64-encoded with the given public " +
 | 
						|
			"key. Must be used with \"-init\".",
 | 
						|
	})
 | 
						|
 | 
						|
	f.StringVar(&StringVar{
 | 
						|
		Name:       "nonce",
 | 
						|
		Target:     &c.flagNonce,
 | 
						|
		Default:    "",
 | 
						|
		EnvVar:     "",
 | 
						|
		Completion: complete.PredictAnything,
 | 
						|
		Usage: "Nonce value returned at initialization. The same nonce value " +
 | 
						|
			"must be provided with each unseal or recovery key. Only needed " +
 | 
						|
			"when providing an unseal or recovery key.",
 | 
						|
	})
 | 
						|
 | 
						|
	return set
 | 
						|
}
 | 
						|
 | 
						|
func (c *OperatorGenerateRootCommand) AutocompleteArgs() complete.Predictor {
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (c *OperatorGenerateRootCommand) AutocompleteFlags() complete.Flags {
 | 
						|
	return c.Flags().Completions()
 | 
						|
}
 | 
						|
 | 
						|
func (c *OperatorGenerateRootCommand) Run(args []string) int {
 | 
						|
	f := c.Flags()
 | 
						|
 | 
						|
	if err := f.Parse(args); err != nil {
 | 
						|
		c.UI.Error(err.Error())
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	args = f.Args()
 | 
						|
	if len(args) > 1 {
 | 
						|
		c.UI.Error(fmt.Sprintf("Too many arguments (expected 0-1, got %d)", len(args)))
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	if c.flagDRToken && c.flagRecoveryToken {
 | 
						|
		c.UI.Error("Both -recovery-token and -dr-token flags are set")
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	client, err := c.Client()
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(err.Error())
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
 | 
						|
	kind := generateRootRegular
 | 
						|
	switch {
 | 
						|
	case c.flagDRToken:
 | 
						|
		kind = generateRootDR
 | 
						|
	case c.flagRecoveryToken:
 | 
						|
		kind = generateRootRecovery
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case c.flagGenerateOTP:
 | 
						|
		otp, code := c.generateOTP(client, kind)
 | 
						|
		if code == 0 {
 | 
						|
			switch Format(c.UI) {
 | 
						|
			case "", "table":
 | 
						|
				return PrintRaw(c.UI, otp)
 | 
						|
			default:
 | 
						|
				status := map[string]interface{}{
 | 
						|
					"otp":        otp,
 | 
						|
					"otp_length": len(otp),
 | 
						|
				}
 | 
						|
				return OutputData(c.UI, status)
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return code
 | 
						|
	case c.flagDecode != "":
 | 
						|
		return c.decode(client, c.flagDecode, c.flagOTP, kind)
 | 
						|
	case c.flagCancel:
 | 
						|
		return c.cancel(client, kind)
 | 
						|
	case c.flagInit:
 | 
						|
		return c.init(client, c.flagOTP, c.flagPGPKey, kind)
 | 
						|
	case c.flagStatus:
 | 
						|
		return c.status(client, kind)
 | 
						|
	default:
 | 
						|
		// If there are no other flags, prompt for an unseal key.
 | 
						|
		key := ""
 | 
						|
		if len(args) > 0 {
 | 
						|
			key = strings.TrimSpace(args[0])
 | 
						|
		}
 | 
						|
		return c.provide(client, key, kind)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// generateOTP generates a suitable OTP code for generating a root token.
 | 
						|
func (c *OperatorGenerateRootCommand) generateOTP(client *api.Client, kind generateRootKind) (string, int) {
 | 
						|
	f := client.Sys().GenerateRootStatus
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		f = client.Sys().GenerateDROperationTokenStatus
 | 
						|
	case generateRootRecovery:
 | 
						|
		f = client.Sys().GenerateRecoveryOperationTokenStatus
 | 
						|
	}
 | 
						|
 | 
						|
	status, err := f()
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err))
 | 
						|
		return "", 2
 | 
						|
	}
 | 
						|
 | 
						|
	otp, err := roottoken.GenerateOTP(status.OTPLength)
 | 
						|
	var retCode int
 | 
						|
	if err != nil {
 | 
						|
		retCode = 2
 | 
						|
		c.UI.Error(err.Error())
 | 
						|
	} else {
 | 
						|
		retCode = 0
 | 
						|
	}
 | 
						|
	return otp, retCode
 | 
						|
}
 | 
						|
 | 
						|
// decode decodes the given value using the otp.
 | 
						|
func (c *OperatorGenerateRootCommand) decode(client *api.Client, encoded, otp string, kind generateRootKind) int {
 | 
						|
	if encoded == "" {
 | 
						|
		c.UI.Error("Missing encoded value: use -decode=<string> to supply it")
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
	if otp == "" {
 | 
						|
		c.UI.Error("Missing otp: use -otp to supply it")
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	if encoded == "-" {
 | 
						|
		// Pull our fake stdin if needed
 | 
						|
		stdin := (io.Reader)(os.Stdin)
 | 
						|
		if c.testStdin != nil {
 | 
						|
			stdin = c.testStdin
 | 
						|
		}
 | 
						|
 | 
						|
		var buf bytes.Buffer
 | 
						|
		if _, err := io.Copy(&buf, stdin); err != nil {
 | 
						|
			c.UI.Error(fmt.Sprintf("Failed to read from stdin: %s", err))
 | 
						|
			return 1
 | 
						|
		}
 | 
						|
 | 
						|
		encoded = buf.String()
 | 
						|
 | 
						|
		if encoded == "" {
 | 
						|
			c.UI.Error("Missing encoded value. When using -decode=\"-\" value must be passed via stdin.")
 | 
						|
			return 1
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	f := client.Sys().GenerateRootStatus
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		f = client.Sys().GenerateDROperationTokenStatus
 | 
						|
	case generateRootRecovery:
 | 
						|
		f = client.Sys().GenerateRecoveryOperationTokenStatus
 | 
						|
	}
 | 
						|
 | 
						|
	status, err := f()
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err))
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
 | 
						|
	token, err := roottoken.DecodeToken(encoded, otp, status.OTPLength)
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error decoding root token: %s", err))
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	switch Format(c.UI) {
 | 
						|
	case "", "table":
 | 
						|
		return PrintRaw(c.UI, token)
 | 
						|
	default:
 | 
						|
		tokenJSON := map[string]interface{}{
 | 
						|
			"token": token,
 | 
						|
		}
 | 
						|
		return OutputData(c.UI, tokenJSON)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// init is used to start the generation process
 | 
						|
func (c *OperatorGenerateRootCommand) init(client *api.Client, otp, pgpKey string, kind generateRootKind) int {
 | 
						|
	// Validate incoming fields. Either OTP OR PGP keys must be supplied.
 | 
						|
	if otp != "" && pgpKey != "" {
 | 
						|
		c.UI.Error("Error initializing: cannot specify both -otp and -pgp-key")
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	// Start the root generation
 | 
						|
	f := client.Sys().GenerateRootInit
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		f = client.Sys().GenerateDROperationTokenInit
 | 
						|
	case generateRootRecovery:
 | 
						|
		f = client.Sys().GenerateRecoveryOperationTokenInit
 | 
						|
	}
 | 
						|
	status, err := f(otp, pgpKey)
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error initializing root generation: %s", err))
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
 | 
						|
	switch Format(c.UI) {
 | 
						|
	case "table":
 | 
						|
		return c.printStatus(status)
 | 
						|
	default:
 | 
						|
		return OutputData(c.UI, status)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// provide prompts the user for the seal key and posts it to the update root
 | 
						|
// endpoint. If this is the last unseal, this function outputs it.
 | 
						|
func (c *OperatorGenerateRootCommand) provide(client *api.Client, key string, kind generateRootKind) int {
 | 
						|
	f := client.Sys().GenerateRootStatus
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		f = client.Sys().GenerateDROperationTokenStatus
 | 
						|
	case generateRootRecovery:
 | 
						|
		f = client.Sys().GenerateRecoveryOperationTokenStatus
 | 
						|
	}
 | 
						|
	status, err := f()
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err))
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
 | 
						|
	// Verify a root token generation is in progress. If there is not one in
 | 
						|
	// progress, return an error instructing the user to start one.
 | 
						|
	if !status.Started {
 | 
						|
		c.UI.Error(wrapAtLength(
 | 
						|
			"No root generation is in progress. Start a root generation by " +
 | 
						|
				"running \"vault operator generate-root -init\"."))
 | 
						|
		c.UI.Warn(wrapAtLength(fmt.Sprintf(
 | 
						|
			"If starting root generation using the OTP method and generating "+
 | 
						|
				"your own OTP, the length of the OTP string needs to be %d "+
 | 
						|
				"characters in length.", status.OTPLength)))
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	var nonce string
 | 
						|
 | 
						|
	switch key {
 | 
						|
	case "-": // Read from stdin
 | 
						|
		nonce = c.flagNonce
 | 
						|
 | 
						|
		// Pull our fake stdin if needed
 | 
						|
		stdin := (io.Reader)(os.Stdin)
 | 
						|
		if c.testStdin != nil {
 | 
						|
			stdin = c.testStdin
 | 
						|
		}
 | 
						|
 | 
						|
		var buf bytes.Buffer
 | 
						|
		if _, err := io.Copy(&buf, stdin); err != nil {
 | 
						|
			c.UI.Error(fmt.Sprintf("Failed to read from stdin: %s", err))
 | 
						|
			return 1
 | 
						|
		}
 | 
						|
 | 
						|
		key = buf.String()
 | 
						|
	case "": // Prompt using the tty
 | 
						|
		// Nonce value is not required if we are prompting via the terminal
 | 
						|
		nonce = status.Nonce
 | 
						|
 | 
						|
		w := getWriterFromUI(c.UI)
 | 
						|
		fmt.Fprintf(w, "Operation nonce: %s\n", nonce)
 | 
						|
		fmt.Fprintf(w, "Unseal Key (will be hidden): ")
 | 
						|
		key, err = password.Read(os.Stdin)
 | 
						|
		fmt.Fprintf(w, "\n")
 | 
						|
		if err != nil {
 | 
						|
			if err == password.ErrInterrupted {
 | 
						|
				c.UI.Error("user canceled")
 | 
						|
				return 1
 | 
						|
			}
 | 
						|
 | 
						|
			c.UI.Error(wrapAtLength(fmt.Sprintf("An error occurred attempting to "+
 | 
						|
				"ask for the unseal key. The raw error message is shown below, but "+
 | 
						|
				"usually this is because you attempted to pipe a value into the "+
 | 
						|
				"command or you are executing outside of a terminal (tty). If you "+
 | 
						|
				"want to pipe the value, pass \"-\" as the argument to read from "+
 | 
						|
				"stdin. The raw error was: %s", err)))
 | 
						|
			return 1
 | 
						|
		}
 | 
						|
	default: // Supplied directly as an arg
 | 
						|
		nonce = c.flagNonce
 | 
						|
	}
 | 
						|
 | 
						|
	// Trim any whitespace from they key, especially since we might have prompted
 | 
						|
	// the user for it.
 | 
						|
	key = strings.TrimSpace(key)
 | 
						|
 | 
						|
	// Verify we have a nonce value
 | 
						|
	if nonce == "" {
 | 
						|
		c.UI.Error("Missing nonce value: specify it via the -nonce flag")
 | 
						|
		return 1
 | 
						|
	}
 | 
						|
 | 
						|
	// Provide the key, this may potentially complete the update
 | 
						|
	fUpd := client.Sys().GenerateRootUpdate
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		fUpd = client.Sys().GenerateDROperationTokenUpdate
 | 
						|
	case generateRootRecovery:
 | 
						|
		fUpd = client.Sys().GenerateRecoveryOperationTokenUpdate
 | 
						|
	}
 | 
						|
	status, err = fUpd(key, nonce)
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error posting unseal key: %s", err))
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
	switch Format(c.UI) {
 | 
						|
	case "table":
 | 
						|
		return c.printStatus(status)
 | 
						|
	default:
 | 
						|
		return OutputData(c.UI, status)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// cancel cancels the root token generation
 | 
						|
func (c *OperatorGenerateRootCommand) cancel(client *api.Client, kind generateRootKind) int {
 | 
						|
	f := client.Sys().GenerateRootCancel
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		f = client.Sys().GenerateDROperationTokenCancel
 | 
						|
	case generateRootRecovery:
 | 
						|
		f = client.Sys().GenerateRecoveryOperationTokenCancel
 | 
						|
	}
 | 
						|
	if err := f(); err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error canceling root token generation: %s", err))
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
	c.UI.Output("Success! Root token generation canceled (if it was started)")
 | 
						|
	return 0
 | 
						|
}
 | 
						|
 | 
						|
// status is used just to fetch and dump the status
 | 
						|
func (c *OperatorGenerateRootCommand) status(client *api.Client, kind generateRootKind) int {
 | 
						|
	f := client.Sys().GenerateRootStatus
 | 
						|
	switch kind {
 | 
						|
	case generateRootDR:
 | 
						|
		f = client.Sys().GenerateDROperationTokenStatus
 | 
						|
	case generateRootRecovery:
 | 
						|
		f = client.Sys().GenerateRecoveryOperationTokenStatus
 | 
						|
	}
 | 
						|
 | 
						|
	status, err := f()
 | 
						|
	if err != nil {
 | 
						|
		c.UI.Error(fmt.Sprintf("Error getting root generation status: %s", err))
 | 
						|
		return 2
 | 
						|
	}
 | 
						|
	switch Format(c.UI) {
 | 
						|
	case "table":
 | 
						|
		return c.printStatus(status)
 | 
						|
	default:
 | 
						|
		return OutputData(c.UI, status)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// printStatus dumps the status to output
 | 
						|
func (c *OperatorGenerateRootCommand) printStatus(status *api.GenerateRootStatusResponse) int {
 | 
						|
	out := []string{}
 | 
						|
	out = append(out, fmt.Sprintf("Nonce | %s", status.Nonce))
 | 
						|
	out = append(out, fmt.Sprintf("Started | %t", status.Started))
 | 
						|
	out = append(out, fmt.Sprintf("Progress | %d/%d", status.Progress, status.Required))
 | 
						|
	out = append(out, fmt.Sprintf("Complete | %t", status.Complete))
 | 
						|
	if status.PGPFingerprint != "" {
 | 
						|
		out = append(out, fmt.Sprintf("PGP Fingerprint | %s", status.PGPFingerprint))
 | 
						|
	}
 | 
						|
	switch {
 | 
						|
	case status.EncodedToken != "":
 | 
						|
		out = append(out, fmt.Sprintf("Encoded Token | %s", status.EncodedToken))
 | 
						|
	case status.EncodedRootToken != "":
 | 
						|
		out = append(out, fmt.Sprintf("Encoded Root Token | %s", status.EncodedRootToken))
 | 
						|
	}
 | 
						|
	if status.OTP != "" {
 | 
						|
		c.UI.Warn(wrapAtLength("A One-Time-Password has been generated for you and is shown in the OTP field. You will need this value to decode the resulting root token, so keep it safe."))
 | 
						|
		out = append(out, fmt.Sprintf("OTP | %s", status.OTP))
 | 
						|
	}
 | 
						|
	if status.OTPLength != 0 {
 | 
						|
		out = append(out, fmt.Sprintf("OTP Length | %d", status.OTPLength))
 | 
						|
	}
 | 
						|
 | 
						|
	output := columnOutput(out, nil)
 | 
						|
	c.UI.Output(output)
 | 
						|
	return 0
 | 
						|
}
 |