2023-03-15 12:00:52 -04:00
// Copyright (c) HashiCorp, Inc.
2023-08-10 21:14:03 -04:00
// SPDX-License-Identifier: BUSL-1.1
2023-03-15 12:00:52 -04:00
2017-09-05 00:01:55 -04:00
package command
import (
"bytes"
"fmt"
"io"
"os"
"strings"
2023-12-04 14:05:02 -05:00
"github.com/hashicorp/cli"
2021-07-15 20:17:31 -04:00
"github.com/hashicorp/go-secure-stdlib/password"
2017-09-05 00:01:55 -04:00
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/pgpkeys"
2021-12-01 08:05:49 -05:00
"github.com/hashicorp/vault/sdk/helper/roottoken"
2017-09-05 00:01:55 -04:00
"github.com/posener/complete"
)
2021-04-08 12:43:39 -04:00
var (
_ cli . Command = ( * OperatorGenerateRootCommand ) ( nil )
_ cli . CommandAutocomplete = ( * OperatorGenerateRootCommand ) ( nil )
)
2017-09-05 00:01:55 -04:00
2024-04-17 14:14:14 -04:00
//go:generate enumer -type=generateRootKind -trimprefix=generateRoot
2019-10-15 00:55:31 -04:00
type generateRootKind int
const (
generateRootRegular generateRootKind = iota
generateRootDR
generateRootRecovery
)
2017-09-07 22:03:12 -04:00
type OperatorGenerateRootCommand struct {
2017-09-05 00:01:55 -04:00
* BaseCommand
2019-10-15 00:55:31 -04:00
flagInit bool
flagCancel bool
flagStatus bool
flagDecode string
flagOTP string
flagPGPKey string
flagNonce string
flagGenerateOTP bool
flagDRToken bool
flagRecoveryToken bool
2017-09-05 00:01:55 -04:00
testStdin io . Reader // for tests
}
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) Synopsis ( ) string {
2023-08-10 16:26:20 -04:00
return "Generates a new root, DR operation, or recovery token"
2017-09-05 00:01:55 -04:00
}
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) Help ( ) string {
2017-09-05 00:01:55 -04:00
helpText := `
2023-08-10 16:26:20 -04:00
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
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
Generates a new root token by combining a quorum of share holders .
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
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 ) .
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
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 .
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
Form 1 ( - init ) - Start a token generation :
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
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 :
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
- 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 .
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
The Vault server will generate a suitable OTP for you , and return it :
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
$ vault operator generate - root - init
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
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 :
2017-09-05 00:01:55 -04:00
2023-08-10 16:26:20 -04:00
$ 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
2017-09-05 00:01:55 -04:00
` + c . Flags ( ) . Help ( )
return strings . TrimSpace ( helpText )
}
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) Flags ( ) * FlagSets {
2018-02-12 18:12:16 -05:00
set := c . flagSet ( FlagSetHTTP | FlagSetOutputFormat )
2017-09-05 00:01:55 -04:00
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 ,
2017-09-07 22:03:12 -04:00
Usage : "Print the status of the current attempt without providing an " +
2017-09-05 00:01:55 -04:00
"unseal key." ,
} )
f . StringVar ( & StringVar {
Name : "decode" ,
Target : & c . flagDecode ,
Default : "" ,
EnvVar : "" ,
Completion : complete . PredictAnything ,
2021-10-20 12:29:17 -04:00
Usage : "The value to decode; setting this triggers a decode operation. " +
" If the value is \"-\" then read the encoded token from stdin." ,
2017-09-05 00:01:55 -04:00
} )
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." ,
} )
2018-01-19 19:25:45 -05:00
f . BoolVar ( & BoolVar {
Name : "dr-token" ,
Target : & c . flagDRToken ,
Default : false ,
EnvVar : "" ,
Completion : complete . PredictNothing ,
2023-08-10 16:26:20 -04:00
Usage : "Set this flag to do generate root operations on DR operation " +
2018-01-19 19:25:45 -05:00
"tokens." ,
} )
2019-10-15 00:55:31 -04:00
f . BoolVar ( & BoolVar {
Name : "recovery-token" ,
Target : & c . flagRecoveryToken ,
Default : false ,
EnvVar : "" ,
Completion : complete . PredictNothing ,
2023-08-10 16:26:20 -04:00
Usage : "Set this flag to do generate root operations on recovery " +
2019-10-15 00:55:31 -04:00
"tokens." ,
} )
2017-09-05 00:01:55 -04:00
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 " +
2021-11-08 13:04:59 -05:00
"public PGP key. This can also be specified as a Keybase username " +
2017-09-05 00:01:55 -04:00
"using the format \"keybase:<username>\". When supplied, the generated " +
"root token will be encrypted and base64-encoded with the given public " +
2023-08-10 16:26:20 -04:00
"key. Must be used with \"-init\"." ,
2017-09-05 00:01:55 -04:00
} )
f . StringVar ( & StringVar {
Name : "nonce" ,
Target : & c . flagNonce ,
Default : "" ,
EnvVar : "" ,
Completion : complete . PredictAnything ,
2023-08-10 16:26:20 -04:00
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." ,
2017-09-05 00:01:55 -04:00
} )
return set
}
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) AutocompleteArgs ( ) complete . Predictor {
2017-09-05 00:01:55 -04:00
return nil
}
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) AutocompleteFlags ( ) complete . Flags {
2017-09-05 00:01:55 -04:00
return c . Flags ( ) . Completions ( )
}
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) Run ( args [ ] string ) int {
2017-09-05 00:01:55 -04:00
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
}
2019-10-15 00:55:31 -04:00
if c . flagDRToken && c . flagRecoveryToken {
c . UI . Error ( "Both -recovery-token and -dr-token flags are set" )
return 1
}
2017-09-05 00:01:55 -04:00
client , err := c . Client ( )
if err != nil {
c . UI . Error ( err . Error ( ) )
return 2
}
2019-10-15 00:55:31 -04:00
kind := generateRootRegular
switch {
case c . flagDRToken :
kind = generateRootDR
case c . flagRecoveryToken :
kind = generateRootRecovery
}
2017-09-05 00:01:55 -04:00
switch {
case c . flagGenerateOTP :
2019-10-15 00:55:31 -04:00
otp , code := c . generateOTP ( client , kind )
2018-08-22 14:37:40 -04:00
if code == 0 {
2020-02-14 21:26:49 -05:00
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 )
}
2018-08-22 14:37:40 -04:00
}
return code
2017-09-05 00:01:55 -04:00
case c . flagDecode != "" :
2019-10-15 00:55:31 -04:00
return c . decode ( client , c . flagDecode , c . flagOTP , kind )
2017-09-05 00:01:55 -04:00
case c . flagCancel :
2019-10-15 00:55:31 -04:00
return c . cancel ( client , kind )
2017-09-05 00:01:55 -04:00
case c . flagInit :
2019-10-15 00:55:31 -04:00
return c . init ( client , c . flagOTP , c . flagPGPKey , kind )
2017-09-05 00:01:55 -04:00
case c . flagStatus :
2019-10-15 00:55:31 -04:00
return c . status ( client , kind )
2017-09-05 00:01:55 -04:00
default :
// If there are no other flags, prompt for an unseal key.
key := ""
if len ( args ) > 0 {
key = strings . TrimSpace ( args [ 0 ] )
}
2019-10-15 00:55:31 -04:00
return c . provide ( client , key , kind )
2017-09-05 00:01:55 -04:00
}
}
2018-08-22 14:37:40 -04:00
// generateOTP generates a suitable OTP code for generating a root token.
2019-10-15 00:55:31 -04:00
func ( c * OperatorGenerateRootCommand ) generateOTP ( client * api . Client , kind generateRootKind ) ( string , int ) {
2018-08-22 14:37:40 -04:00
f := client . Sys ( ) . GenerateRootStatus
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-08-22 14:37:40 -04:00
f = client . Sys ( ) . GenerateDROperationTokenStatus
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
f = client . Sys ( ) . GenerateRecoveryOperationTokenStatus
2017-09-05 00:01:55 -04:00
}
2019-10-15 00:55:31 -04:00
2018-08-22 14:37:40 -04:00
status , err := f ( )
2017-09-05 00:01:55 -04:00
if err != nil {
2018-08-22 14:37:40 -04:00
c . UI . Error ( fmt . Sprintf ( "Error getting root generation status: %s" , err ) )
return "" , 2
2017-09-05 00:01:55 -04:00
}
2021-12-01 08:05:49 -05:00
otp , err := roottoken . GenerateOTP ( status . OTPLength )
var retCode int
if err != nil {
retCode = 2
c . UI . Error ( err . Error ( ) )
} else {
retCode = 0
2018-08-22 14:37:40 -04:00
}
2021-12-01 08:05:49 -05:00
return otp , retCode
2017-09-05 00:01:55 -04:00
}
// decode decodes the given value using the otp.
2019-10-15 00:55:31 -04:00
func ( c * OperatorGenerateRootCommand ) decode ( client * api . Client , encoded , otp string , kind generateRootKind ) int {
2017-09-05 00:01:55 -04:00
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
}
2021-10-20 12:29:17 -04:00
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
}
}
2018-08-22 14:37:40 -04:00
f := client . Sys ( ) . GenerateRootStatus
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-08-22 14:37:40 -04:00
f = client . Sys ( ) . GenerateDROperationTokenStatus
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
f = client . Sys ( ) . GenerateRecoveryOperationTokenStatus
2017-09-05 00:01:55 -04:00
}
2019-10-15 00:55:31 -04:00
2018-08-22 14:37:40 -04:00
status , err := f ( )
2017-09-05 00:01:55 -04:00
if err != nil {
2018-08-22 14:37:40 -04:00
c . UI . Error ( fmt . Sprintf ( "Error getting root generation status: %s" , err ) )
return 2
2017-09-05 00:01:55 -04:00
}
2021-12-01 08:05:49 -05:00
token , err := roottoken . DecodeToken ( encoded , otp , status . OTPLength )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error decoding root token: %s" , err ) )
return 1
2020-02-14 21:26:49 -05:00
}
2018-08-22 14:37:40 -04:00
2020-02-14 21:26:49 -05:00
switch Format ( c . UI ) {
case "" , "table" :
return PrintRaw ( c . UI , token )
default :
tokenJSON := map [ string ] interface { } {
"token" : token ,
}
return OutputData ( c . UI , tokenJSON )
2018-08-22 14:37:40 -04:00
}
2017-09-05 00:01:55 -04:00
}
// init is used to start the generation process
2019-10-15 00:55:31 -04:00
func ( c * OperatorGenerateRootCommand ) init ( client * api . Client , otp , pgpKey string , kind generateRootKind ) int {
2017-09-05 00:01:55 -04:00
// Validate incoming fields. Either OTP OR PGP keys must be supplied.
2018-08-22 14:37:40 -04:00
if otp != "" && pgpKey != "" {
2017-09-05 00:01:55 -04:00
c . UI . Error ( "Error initializing: cannot specify both -otp and -pgp-key" )
return 1
}
// Start the root generation
2018-01-19 19:25:45 -05:00
f := client . Sys ( ) . GenerateRootInit
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-01-19 19:25:45 -05:00
f = client . Sys ( ) . GenerateDROperationTokenInit
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
f = client . Sys ( ) . GenerateRecoveryOperationTokenInit
2018-01-19 19:25:45 -05:00
}
status , err := f ( otp , pgpKey )
2017-09-05 00:01:55 -04:00
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error initializing root generation: %s" , err ) )
return 2
}
2018-02-12 18:12:16 -05:00
switch Format ( c . UI ) {
case "table" :
return c . printStatus ( status )
default :
return OutputData ( c . UI , status )
}
2017-09-05 00:01:55 -04:00
}
// 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.
2019-10-15 00:55:31 -04:00
func ( c * OperatorGenerateRootCommand ) provide ( client * api . Client , key string , kind generateRootKind ) int {
2018-01-19 19:25:45 -05:00
f := client . Sys ( ) . GenerateRootStatus
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-01-19 19:25:45 -05:00
f = client . Sys ( ) . GenerateDROperationTokenStatus
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
f = client . Sys ( ) . GenerateRecoveryOperationTokenStatus
2018-01-19 19:25:45 -05:00
}
status , err := f ( )
2017-09-05 00:01:55 -04:00
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 " +
2018-06-07 00:11:21 -04:00
"running \"vault operator generate-root -init\"." ) )
2018-08-22 14:37:40 -04:00
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 ) ) )
2017-09-05 00:01:55 -04:00
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 )
2018-07-06 09:02:47 -04:00
fmt . Fprintf ( w , "Operation nonce: %s\n" , nonce )
2017-09-05 00:01:55 -04:00
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
2018-01-19 19:25:45 -05:00
fUpd := client . Sys ( ) . GenerateRootUpdate
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-01-19 19:25:45 -05:00
fUpd = client . Sys ( ) . GenerateDROperationTokenUpdate
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
fUpd = client . Sys ( ) . GenerateRecoveryOperationTokenUpdate
2018-01-19 19:25:45 -05:00
}
status , err = fUpd ( key , nonce )
2017-09-05 00:01:55 -04:00
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error posting unseal key: %s" , err ) )
return 2
}
2018-02-12 18:12:16 -05:00
switch Format ( c . UI ) {
case "table" :
return c . printStatus ( status )
default :
return OutputData ( c . UI , status )
}
2017-09-05 00:01:55 -04:00
}
// cancel cancels the root token generation
2019-10-15 00:55:31 -04:00
func ( c * OperatorGenerateRootCommand ) cancel ( client * api . Client , kind generateRootKind ) int {
2018-01-19 19:25:45 -05:00
f := client . Sys ( ) . GenerateRootCancel
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-01-19 19:25:45 -05:00
f = client . Sys ( ) . GenerateDROperationTokenCancel
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
f = client . Sys ( ) . GenerateRecoveryOperationTokenCancel
2018-01-19 19:25:45 -05:00
}
if err := f ( ) ; err != nil {
2017-09-05 00:01:55 -04:00
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
2019-10-15 00:55:31 -04:00
func ( c * OperatorGenerateRootCommand ) status ( client * api . Client , kind generateRootKind ) int {
2018-01-19 19:25:45 -05:00
f := client . Sys ( ) . GenerateRootStatus
2019-10-15 00:55:31 -04:00
switch kind {
case generateRootDR :
2018-01-19 19:25:45 -05:00
f = client . Sys ( ) . GenerateDROperationTokenStatus
2019-10-15 00:55:31 -04:00
case generateRootRecovery :
f = client . Sys ( ) . GenerateRecoveryOperationTokenStatus
2018-01-19 19:25:45 -05:00
}
2019-10-15 00:55:31 -04:00
2018-01-19 19:25:45 -05:00
status , err := f ( )
2017-09-05 00:01:55 -04:00
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error getting root generation status: %s" , err ) )
return 2
}
2018-02-12 18:12:16 -05:00
switch Format ( c . UI ) {
case "table" :
return c . printStatus ( status )
default :
return OutputData ( c . UI , status )
}
2017-09-05 00:01:55 -04:00
}
// printStatus dumps the status to output
2017-09-07 22:03:12 -04:00
func ( c * OperatorGenerateRootCommand ) printStatus ( status * api . GenerateRootStatusResponse ) int {
2017-09-05 00:01:55 -04:00
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 ) )
}
2018-04-10 11:21:38 -04:00
switch {
case status . EncodedToken != "" :
2018-07-06 09:02:47 -04:00
out = append ( out , fmt . Sprintf ( "Encoded Token | %s" , status . EncodedToken ) )
case status . EncodedRootToken != "" :
out = append ( out , fmt . Sprintf ( "Encoded Root Token | %s" , status . EncodedRootToken ) )
2017-09-05 00:01:55 -04:00
}
2018-08-22 14:37:40 -04:00
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 ) )
}
2017-09-05 00:01:55 -04:00
2017-09-07 22:03:12 -04:00
output := columnOutput ( out , nil )
2017-09-05 00:01:55 -04:00
c . UI . Output ( output )
return 0
}