github.com/kbehouse/nsc@v0.0.6/cmd/exportkeys.go (about)

     1  /*
     2   * Copyright 2018-2019 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  
    25  	"github.com/kbehouse/nsc/cmd/store"
    26  	"github.com/spf13/cobra"
    27  )
    28  
    29  func createExportKeysCmd() *cobra.Command {
    30  	var params ExportKeysParams
    31  	cmd := &cobra.Command{
    32  		Use:   "keys",
    33  		Short: "Export operator, account and user keys in the current operator and account context",
    34  		Long: `Export operator, account and user keys in the current operator and account context.
    35  Additional flags allow you to specify which types of keys to export. For example
    36  the --operator flag exports any operator keys, --accounts exports account keys, etc. 
    37  
    38  To export all key types specify the --all flag.
    39  
    40  
    41  You can limit export to a different account context by specifying --account flag.
    42  You can limit exporting user keys to the specified user by specifying the --user flag.
    43  
    44  The --not-referenced flag exports all keys not relevant to the current  operator, 
    45  accounts and users. These keys may be referenced in a different  operator context.
    46  
    47  The --filter flag allows you to specify a few letters in a public key and export only 
    48  those keys that matching the filter (provided the key type matches --operator, --account,
    49  --user (or --all).
    50  `,
    51  		Example: `nsc export keys --dir <path> (exports the current operator, account and users keys)
    52  nsc export keys --operator --accounts --users (exports current operators, all accounts, and users)
    53  nsc export keys --all (same as specifying --operator --accounts --users)
    54  nsc export keys --operator --not-referenced (exports any other operator keys in the keystore)
    55  nsc export keys --all --filter VSVMGA (exports all keys containing the filter)
    56  nsc export keys --account <name> (changes the account context to the specified account)
    57  `,
    58  		Args:         MaxArgs(0),
    59  		SilenceUsage: false,
    60  		RunE: func(cmd *cobra.Command, args []string) error {
    61  			if err := RunMaybeStorelessAction(cmd, args, &params); err != nil {
    62  				return err
    63  			}
    64  			return nil
    65  		},
    66  	}
    67  	cmd.Flags().BoolVarP(&params.Operator, "operator", "o", false, "export operator keys")
    68  	cmd.Flags().BoolVarP(&params.Accounts, "accounts", "a", false, "export account keys")
    69  	cmd.Flags().BoolVarP(&params.Users, "users", "u", false, "export user keys")
    70  	cmd.Flags().StringVarP(&params.Account, "account", "", "", "change account context to the named account")
    71  	cmd.Flags().StringVarP(&params.User, "user", "", "", "export specified user key")
    72  	cmd.Flags().BoolVarP(&params.All, "all", "A", false, "export operator, accounts and users keys")
    73  	cmd.Flags().StringVarP(&params.Filter, "filter", "f", "", "export keys containing string")
    74  	cmd.Flags().BoolVarP(&params.Unreferenced, "not-referenced", "", false, "export keys that are not referenced in the current operator context")
    75  	cmd.Flags().StringVarP(&params.Dir, "dir", "d", "", "directory to export keys to")
    76  	cmd.Flags().BoolVarP(&params.Force, "force", "F", false, "overwrite existing files")
    77  	cmd.Flags().BoolVarP(&params.Remove, "remove", "R", false, "removes the original key file from the keyring after exporting it")
    78  	cmd.MarkFlagRequired("dir")
    79  
    80  	return cmd
    81  }
    82  
    83  func init() {
    84  	exportCmd.AddCommand(createExportKeysCmd())
    85  }
    86  
    87  type ExportKeysParams struct {
    88  	Force  bool
    89  	Remove bool
    90  	Dir    string
    91  	KeyCollectorParams
    92  }
    93  
    94  func (p *ExportKeysParams) SetDefaults(ctx ActionCtx) error {
    95  	return p.KeyCollectorParams.SetDefaults(ctx)
    96  }
    97  
    98  func (p *ExportKeysParams) PreInteractive(ctx ActionCtx) error {
    99  	return nil
   100  }
   101  
   102  func (p *ExportKeysParams) Load(ctx ActionCtx) error {
   103  	return nil
   104  }
   105  
   106  func (p *ExportKeysParams) PostInteractive(ctx ActionCtx) error {
   107  	return nil
   108  }
   109  
   110  func (p *ExportKeysParams) Validate(ctx ActionCtx) error {
   111  	d := store.GetKeysDir()
   112  	_, err := os.Stat(d)
   113  	if os.IsNotExist(err) {
   114  		return fmt.Errorf("keystore %#q does not exist", d)
   115  	}
   116  	return nil
   117  }
   118  
   119  func (p *ExportKeysParams) Run(ctx ActionCtx) (store.Status, error) {
   120  	ctx.CurrentCmd().SilenceUsage = true
   121  
   122  	var wj []ExportJob
   123  	var err error
   124  	var keys Keys
   125  
   126  	ks := ctx.StoreCtx().KeyStore
   127  	p.Dir, err = Expand(p.Dir)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	sr := store.NewDetailedReport(true)
   133  	keys.KeyList, err = p.KeyCollectorParams.Run(ctx)
   134  	for _, k := range keys.KeyList {
   135  		var j ExportJob
   136  		j.description = k.Pub
   137  		if k.HasKey() {
   138  			s, err := ks.GetSeed(k.Pub)
   139  			if err != nil {
   140  				sr.AddError("error reading seed for %s", k.Pub)
   141  				continue
   142  			}
   143  			j.filepath = filepath.Join(p.Dir, fmt.Sprintf("%s.nk", k.Pub))
   144  			_, err = os.Stat(j.filepath)
   145  			if os.IsNotExist(err) || (err == nil && p.Force) {
   146  				j.data = []byte(s)
   147  			} else {
   148  				sr.AddError("%#q already exists - specify --force to overwrite", j.filepath)
   149  				continue
   150  			}
   151  		}
   152  		wj = append(wj, j)
   153  	}
   154  
   155  	if keys.Len() == 0 {
   156  		return nil, errors.New("no keys found to export")
   157  	}
   158  
   159  	if err := MaybeMakeDir(p.Dir); err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	for _, j := range wj {
   164  		if j.filepath != "" {
   165  			j.err = ioutil.WriteFile(j.filepath, j.data, 0700)
   166  			if j.err != nil {
   167  				sr.AddError("error exporting %q: %v", j.description, j.err)
   168  			} else {
   169  				if p.Remove {
   170  					err := ks.Remove(j.description)
   171  					if err != nil {
   172  						sr.AddError("exported %q but failed to delete original file: %v", j.description, err)
   173  						continue
   174  					} else {
   175  						sr.AddOK("moved %q", j.description)
   176  						continue
   177  					}
   178  				}
   179  				sr.AddOK("exported %q", j.description)
   180  			}
   181  		} else {
   182  			sr.AddWarning("skipped %q - no seed available", j.description)
   183  		}
   184  	}
   185  	return sr, err
   186  }
   187  
   188  type ExportJob struct {
   189  	description string
   190  	filepath    string
   191  	data        []byte
   192  	err         error
   193  }