code.vegaprotocol.io/vega@v0.79.0/cmd/vegawallet/commands/api_token_init.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package cmd
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  
    23  	"code.vegaprotocol.io/vega/cmd/vegawallet/commands/cli"
    24  	"code.vegaprotocol.io/vega/cmd/vegawallet/commands/flags"
    25  	"code.vegaprotocol.io/vega/cmd/vegawallet/commands/printer"
    26  	"code.vegaprotocol.io/vega/paths"
    27  	tokenStoreV1 "code.vegaprotocol.io/vega/wallet/service/v2/connections/store/longliving/v1"
    28  
    29  	"github.com/spf13/cobra"
    30  )
    31  
    32  var (
    33  	apiTokenInitLong = cli.LongDesc(`
    34  		Initialise the system supporting long-living API tokens
    35  	`)
    36  
    37  	apiTokenInitExample = cli.Examples(`
    38  		# Initialise the system supporting long-living API tokens
    39  		{{.Software}} api-token init
    40  	`)
    41  
    42  	tokenPassphraseOptions = flags.PassphraseOptions{
    43  		Name:        "tokens store",
    44  		Description: "This passphrase is used to encrypt the long-living connection tokens.\nThis passphrase will be asked to start the wallet service.",
    45  	}
    46  )
    47  
    48  type APITokenInitHandler func(home string, f *InitAPITokenFlags) (bool, error)
    49  
    50  func NewCmdInitAPIToken(w io.Writer, rf *RootFlags) *cobra.Command {
    51  	return BuildCmdInitAPIToken(w, InitAPIToken, rf)
    52  }
    53  
    54  func BuildCmdInitAPIToken(w io.Writer, handler APITokenInitHandler, rf *RootFlags) *cobra.Command {
    55  	f := &InitAPITokenFlags{}
    56  
    57  	cmd := &cobra.Command{
    58  		Use:     "init",
    59  		Short:   "Initialise the system supporting long-living API tokens",
    60  		Long:    apiTokenInitLong,
    61  		Example: apiTokenInitExample,
    62  		RunE: func(_ *cobra.Command, _ []string) error {
    63  			initialized, err := handler(rf.Home, f)
    64  			if err != nil {
    65  				return err
    66  			}
    67  
    68  			switch rf.Output {
    69  			case flags.InteractiveOutput:
    70  				PrintAPITokenInitResponse(w, initialized)
    71  			}
    72  			return nil
    73  		},
    74  	}
    75  
    76  	cmd.Flags().StringVar(&f.PassphraseFile,
    77  		"passphrase-file",
    78  		"",
    79  		"Path to the file containing the tokens database passphrase",
    80  	)
    81  
    82  	cmd.Flags().BoolVarP(&f.Force,
    83  		"force", "f",
    84  		false,
    85  		"Remove the existing token database and recreate it",
    86  	)
    87  
    88  	return cmd
    89  }
    90  
    91  type InitAPITokenFlags struct {
    92  	PassphraseFile string
    93  	Force          bool
    94  }
    95  
    96  func InitAPIToken(home string, f *InitAPITokenFlags) (bool, error) {
    97  	vegaPaths := paths.New(home)
    98  
    99  	// Verify the init state of the tokens store
   100  	init, err := tokenStoreV1.IsStoreBootstrapped(vegaPaths)
   101  	if err != nil {
   102  		return false, fmt.Errorf("could not verify the initialization state of the tokens store: %w", err)
   103  	}
   104  	if init && !f.Force {
   105  		return false, nil
   106  	}
   107  
   108  	passphrase, err := flags.GetConfirmedPassphraseWithContext(tokenPassphraseOptions, f.PassphraseFile)
   109  	if err != nil {
   110  		return false, err
   111  	}
   112  	tokenStore, err := tokenStoreV1.ReinitialiseStore(vegaPaths, passphrase)
   113  	if err != nil {
   114  		return false, fmt.Errorf("couldn't initialise the tokens store: %w", err)
   115  	}
   116  	tokenStore.Close()
   117  	return true, nil
   118  }
   119  
   120  func PrintAPITokenInitResponse(w io.Writer, init bool) {
   121  	p := printer.NewInteractivePrinter(w)
   122  
   123  	str := p.String()
   124  	defer p.Print(str)
   125  
   126  	if init {
   127  		str.CheckMark().SuccessText("Support for long-living tokens has been initialised.").NextSection()
   128  	} else {
   129  		str.CheckMark().SuccessText("Support for long-living tokens has ").SuccessBold("already").SuccessText(" been initialised.").NextSection()
   130  	}
   131  
   132  	str.BlueArrow().InfoText("Generate a long-living API token").NextLine()
   133  	str.Text("To generate a long-living API token, use the following command:").NextSection()
   134  	str.Code(fmt.Sprintf("%s api-token generate --wallet-name \"WALLET_ASSOCIATED_TO_THE_TOKEN\"", os.Args[0])).NextSection()
   135  	str.Text("For more information, use ").Bold("--help").Text(" flag.").NextLine()
   136  }