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, ¶ms); err != nil { 62 return err 63 } 64 return nil 65 }, 66 } 67 cmd.Flags().BoolVarP(¶ms.Operator, "operator", "o", false, "export operator keys") 68 cmd.Flags().BoolVarP(¶ms.Accounts, "accounts", "a", false, "export account keys") 69 cmd.Flags().BoolVarP(¶ms.Users, "users", "u", false, "export user keys") 70 cmd.Flags().StringVarP(¶ms.Account, "account", "", "", "change account context to the named account") 71 cmd.Flags().StringVarP(¶ms.User, "user", "", "", "export specified user key") 72 cmd.Flags().BoolVarP(¶ms.All, "all", "A", false, "export operator, accounts and users keys") 73 cmd.Flags().StringVarP(¶ms.Filter, "filter", "f", "", "export keys containing string") 74 cmd.Flags().BoolVarP(¶ms.Unreferenced, "not-referenced", "", false, "export keys that are not referenced in the current operator context") 75 cmd.Flags().StringVarP(¶ms.Dir, "dir", "d", "", "directory to export keys to") 76 cmd.Flags().BoolVarP(¶ms.Force, "force", "F", false, "overwrite existing files") 77 cmd.Flags().BoolVarP(¶ms.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 }