github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/importcollector.go (about) 1 /* 2 * Copyright 2018-2023 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 "sort" 22 23 "github.com/nats-io/jwt/v2" 24 "github.com/nats-io/nsc/v2/cmd/store" 25 ) 26 27 type AccountExport struct { 28 OperatorName string 29 jwt.AccountClaims 30 } 31 32 func (ae *AccountExport) Choices() []AccountExportChoice { 33 var choices []AccountExportChoice 34 // choice without a selection is an account label 35 choices = append(choices, AccountExportChoice{AccountExport: *ae}) 36 for _, v := range ae.Exports { 37 choices = append(choices, AccountExportChoice{*ae, v}) 38 } 39 return choices 40 } 41 42 type ByAccountName []AccountExport 43 44 func (a ByAccountName) Len() int { return len(a) } 45 func (a ByAccountName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 46 func (a ByAccountName) Less(i, j int) bool { return a[i].Name < a[j].Name } 47 48 type AccountExportChoice struct { 49 AccountExport 50 Selection *jwt.Export 51 } 52 53 type AccountExportChoices []AccountExportChoice 54 55 func (aes AccountExportChoices) String() []string { 56 var choices []string 57 for _, c := range aes { 58 choices = append(choices, c.String()) 59 } 60 return choices 61 } 62 63 func (aec *AccountExportChoice) String() string { 64 // label 65 if aec.Selection == nil { 66 footer := fmt.Sprintf("[%s]", aec.Subject) 67 if aec.AccountExport.Description != "" { 68 footer = aec.AccountExport.Description 69 } 70 if aec.AccountExport.InfoURL != "" { 71 footer = fmt.Sprintf("%s\n Link: %s", footer, aec.AccountExport.InfoURL) 72 } 73 return fmt.Sprintf("%s: %s", aec.Name, footer) 74 } 75 // the cli ui is expecting an unique name in the select 76 // if not the index returned on selection will match the 77 // last one in the list 78 accName := aec.Name 79 // an actual export 80 k := "->" 81 if aec.Selection.IsService() { 82 k = "<-" 83 } 84 85 p := "" 86 if aec.Selection.TokenReq { 87 p = "[!]" 88 } 89 90 footer := "" 91 if aec.Selection.Description != "" { 92 footer = fmt.Sprintf("\n Description: %s", aec.Selection.Description) 93 } 94 if aec.Selection.InfoURL != "" { 95 footer = fmt.Sprintf("%s\n Link: %s", footer, aec.Selection.InfoURL) 96 } 97 98 if aec.Selection.Name == string(aec.Selection.Subject) { 99 return fmt.Sprintf(" %s %s %s %s%s", accName, k, aec.Selection.Subject, p, footer) 100 } 101 102 return fmt.Sprintf(" %s %s [%s] %s %s%s", accName, k, aec.Selection.Name, aec.Selection.Subject, p, footer) 103 } 104 105 type AccountImport struct { 106 Name string 107 ID string 108 } 109 110 type AccountImportChoice struct { 111 AccountImport 112 Selection *jwt.Import 113 } 114 115 type AccountImportChoices []AccountImportChoice 116 117 func (aes AccountImportChoices) String() []string { 118 var choices []string 119 for _, c := range aes { 120 choices = append(choices, c.String()) 121 } 122 return choices 123 } 124 125 func (aec *AccountImportChoice) String() string { 126 label := aec.Name 127 if label == "" { 128 label = aec.ID 129 } 130 131 // an actual export 132 k := "->" 133 if aec.Selection.IsService() { 134 k = "<-" 135 } 136 137 p := "" 138 if aec.Selection.Token != "" { 139 p = "[!]" 140 } 141 142 if aec.Selection.Name == string(aec.Selection.Subject) { 143 return fmt.Sprintf(" %s %s %s (%s)", k, aec.Selection.Subject, p, label) 144 } 145 146 return fmt.Sprintf(" %s [%s] %s %s (%s)", k, aec.Selection.Name, aec.Selection.Subject, p, label) 147 } 148 149 func GetAccountImports(ac *jwt.AccountClaims) (AccountImportChoices, error) { 150 config := GetConfig() 151 if config.StoreRoot == "" { 152 return nil, errors.New("no store set - `env --store <dir>`") 153 } 154 idToName := make(map[string]string) 155 operators := config.ListOperators() 156 for _, o := range operators { 157 if o == "" { 158 continue 159 } 160 s, err := config.LoadStore(o) 161 if err != nil { 162 return nil, err 163 } 164 accounts, err := s.ListSubContainers(store.Accounts) 165 if err != nil { 166 return nil, err 167 } 168 for _, a := range accounts { 169 ac, err := s.ReadAccountClaim(a) 170 if err != nil { 171 if store.IsNotExist(err) { 172 // ignore it and move on 173 continue 174 } 175 return nil, err 176 } 177 if ac != nil { 178 idToName[ac.Subject] = ac.Name 179 } 180 } 181 } 182 183 var a AccountImportChoices 184 for _, v := range ac.Imports { 185 var aic AccountImportChoice 186 aic.ID = v.Account 187 aic.Name = idToName[aic.ID] 188 aic.Selection = v 189 a = append(a, aic) 190 } 191 return a, nil 192 } 193 194 func GetAccountExports(ac *jwt.AccountClaims) ([]AccountExportChoice, error) { 195 if ac == nil { 196 return nil, nil 197 } 198 if len(ac.Exports) == 0 { 199 return nil, nil 200 } 201 var export AccountExport 202 export.Exports = ac.Exports 203 export.AccountClaims = *ac 204 return export.Choices()[1:], nil 205 } 206 207 func GetAllExports() ([]AccountExport, error) { 208 var exports []AccountExport 209 210 config := GetConfig() 211 if config.StoreRoot == "" { 212 return nil, errors.New("no store set - `env --store <dir>`") 213 } 214 operators := config.ListOperators() 215 for _, o := range operators { 216 if o == "" { 217 continue 218 } 219 220 s, err := config.LoadStore(o) 221 if err != nil { 222 return nil, err 223 } 224 accounts, err := s.ListSubContainers(store.Accounts) 225 if err != nil { 226 return nil, err 227 } 228 for _, a := range accounts { 229 ac, err := s.ReadAccountClaim(a) 230 if err != nil { 231 if store.IsNotExist(err) { 232 // ignore it and move on 233 continue 234 } 235 return nil, err 236 } 237 238 if len(ac.Exports) == 0 { 239 continue 240 } 241 242 var export AccountExport 243 export.OperatorName = o 244 export.Exports = ac.Exports 245 export.AccountClaims = *ac 246 exports = append(exports, export) 247 } 248 } 249 250 sort.Sort(ByAccountName(exports)) 251 return exports, nil 252 }