github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/crypto/keys/client/export_test.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/gnolang/gno/tm2/pkg/commands"
    11  	"github.com/gnolang/gno/tm2/pkg/crypto/keys"
    12  	"github.com/gnolang/gno/tm2/pkg/testutils"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  // newTestKeybase generates a new test key-base
    17  // Returns the temporary key-base, and its path
    18  func newTestKeybase(t *testing.T) (keys.Keybase, string) {
    19  	t.Helper()
    20  
    21  	// Generate a temporary key-base directory
    22  	kbHome, kbCleanUp := testutils.NewTestCaseDir(t)
    23  
    24  	t.Cleanup(func() {
    25  		kbCleanUp()
    26  	})
    27  
    28  	kb, err := keys.NewKeyBaseFromDir(kbHome)
    29  	if err != nil {
    30  		t.Fatalf(
    31  			"unable to create a key base in directory %s, %v",
    32  			kbHome,
    33  			err,
    34  		)
    35  	}
    36  
    37  	return kb, kbHome
    38  }
    39  
    40  // addRandomKeyToKeybase adds a random key to the key-base
    41  func addRandomKeyToKeybase(
    42  	kb keys.Keybase,
    43  	keyName,
    44  	encryptPassword string,
    45  ) (keys.Info, error) {
    46  	// Generate a random mnemonic
    47  	mnemonic, err := GenerateMnemonic(mnemonicEntropySize)
    48  	if err != nil {
    49  		return nil, fmt.Errorf(
    50  			"unable to generate a mnemonic phrase, %w",
    51  			err,
    52  		)
    53  	}
    54  
    55  	// Add the key to the key base
    56  	return kb.CreateAccount(
    57  		keyName,
    58  		mnemonic,
    59  		"",
    60  		encryptPassword,
    61  		0,
    62  		0,
    63  	)
    64  }
    65  
    66  type testCmdKeyOptsBase struct {
    67  	kbHome  string
    68  	keyName string
    69  	unsafe  bool
    70  }
    71  
    72  type testExportKeyOpts struct {
    73  	testCmdKeyOptsBase
    74  
    75  	outputPath string
    76  }
    77  
    78  // exportKey runs the private key export command
    79  // using the provided options
    80  func exportKey(
    81  	exportOpts testExportKeyOpts,
    82  	input io.Reader,
    83  ) error {
    84  	cfg := &ExportCfg{
    85  		RootCfg: &BaseCfg{
    86  			BaseOptions: BaseOptions{
    87  				Home:                  exportOpts.kbHome,
    88  				InsecurePasswordStdin: true,
    89  			},
    90  		},
    91  		NameOrBech32: exportOpts.keyName,
    92  		OutputPath:   exportOpts.outputPath,
    93  		Unsafe:       exportOpts.unsafe,
    94  	}
    95  
    96  	cmdIO := commands.NewTestIO()
    97  	cmdIO.SetIn(input)
    98  
    99  	return execExport(cfg, cmdIO)
   100  }
   101  
   102  // TestExport_ExportKey makes sure the key can be exported correctly
   103  func TestExport_ExportKey(t *testing.T) {
   104  	t.Parallel()
   105  
   106  	// numLines returns the number of new lines
   107  	// in a string
   108  	numLines := func(s string) int {
   109  		n := strings.Count(s, "\n")
   110  		if len(s) > 0 && !strings.HasSuffix(s, "\n") {
   111  			n++
   112  		}
   113  
   114  		return n
   115  	}
   116  
   117  	const (
   118  		keyName  = "key name"
   119  		password = "password"
   120  	)
   121  
   122  	testTable := []struct {
   123  		name     string
   124  		baseOpts testCmdKeyOptsBase
   125  		input    io.Reader
   126  	}{
   127  		{
   128  			"encrypted key export",
   129  			testCmdKeyOptsBase{},
   130  			strings.NewReader(
   131  				fmt.Sprintf(
   132  					"%s\n%s\n%s\n",
   133  					password, // decrypt
   134  					password, // encrypt
   135  					password, // encrypt confirm
   136  				),
   137  			),
   138  		},
   139  		{
   140  			"unencrypted key export",
   141  			testCmdKeyOptsBase{
   142  				unsafe: true,
   143  			},
   144  			strings.NewReader(
   145  				fmt.Sprintf(
   146  					"%s\n",
   147  					password, // decrypt
   148  				),
   149  			),
   150  		},
   151  	}
   152  
   153  	for _, testCase := range testTable {
   154  		testCase := testCase
   155  
   156  		t.Run(testCase.name, func(t *testing.T) {
   157  			t.Parallel()
   158  
   159  			// Generate a temporary key-base directory
   160  			kb, kbHome := newTestKeybase(t)
   161  
   162  			// Add an initial key to the key base
   163  			info, err := addRandomKeyToKeybase(kb, keyName, password)
   164  			if err != nil {
   165  				t.Fatalf(
   166  					"unable to create a key base account, %v",
   167  					err,
   168  				)
   169  			}
   170  
   171  			outputFile, outputCleanupFn := testutils.NewTestFile(t)
   172  			t.Cleanup(func() {
   173  				outputCleanupFn()
   174  			})
   175  
   176  			// Make sure the command executes correctly
   177  			assert.NoError(
   178  				t,
   179  				exportKey(
   180  					testExportKeyOpts{
   181  						testCmdKeyOptsBase: testCmdKeyOptsBase{
   182  							kbHome:  kbHome,
   183  							keyName: info.GetName(),
   184  							unsafe:  testCase.baseOpts.unsafe,
   185  						},
   186  						outputPath: outputFile.Name(),
   187  					},
   188  					testCase.input,
   189  				),
   190  			)
   191  
   192  			// Make sure the encrypted armor has been written to disk
   193  			buff, err := os.ReadFile(outputFile.Name())
   194  			if err != nil {
   195  				t.Fatalf(
   196  					"unable to read temporary file from disk, %v",
   197  					err,
   198  				)
   199  			}
   200  
   201  			assert.Greater(t, numLines(string(buff)), 1)
   202  		})
   203  	}
   204  }
   205  
   206  func TestExport_ExportKeyWithEmptyName(t *testing.T) {
   207  	// Generate a temporary key-base directory
   208  	_, kbHome := newTestKeybase(t)
   209  	err := exportKey(
   210  		testExportKeyOpts{
   211  			testCmdKeyOptsBase: testCmdKeyOptsBase{
   212  				kbHome:  kbHome,
   213  				keyName: "",
   214  			},
   215  		},
   216  		nil,
   217  	)
   218  	assert.Error(t, err)
   219  	assert.EqualError(t, err, "key to be exported shouldn't be empty")
   220  }