mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	 961bf20bdb
			
		
	
	961bf20bdb
	
	
	
		
			
			We have many hand-written String() methods (and similar) for enums. These require more maintenance and are more error-prone than using automatically generated methods. In addition, the auto-generated versions can be more efficient. Here, we switch to using https://github.com/loggerhead/enumer, itself a fork of https://github.com/diegostamigni/enumer, no longer maintained, and a fork of the mostly standard tool https://pkg.go.dev/golang.org/x/tools/cmd/stringer. We use this fork of enumer for Go 1.20+ compatibility and because we require the `-transform` flag to be able to generate constants that match our current code base. Some enums were not targeted for this change:
		
			
				
	
	
		
			630 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			630 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)
 | |
| )
 | |
| 
 | |
| //go:generate enumer -type=generateRootKind -trimprefix=generateRoot
 | |
| 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
 | |
| }
 |