github.com/kbehouse/nsc@v0.0.6/cmd/importcollector.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  	"sort"
    22  
    23  	"github.com/kbehouse/nsc/cmd/store"
    24  	"github.com/nats-io/jwt/v2"
    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 := ""
    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  	// an actual export
    76  	k := "->"
    77  	if aec.Selection.IsService() {
    78  		k = "<-"
    79  	}
    80  
    81  	p := ""
    82  	if aec.Selection.TokenReq {
    83  		p = "[!]"
    84  	}
    85  
    86  	footer := ""
    87  	if aec.Selection.Description != "" {
    88  		footer = fmt.Sprintf("\n       Description: %s", aec.Selection.Description)
    89  	}
    90  	if aec.Selection.InfoURL != "" {
    91  		footer = fmt.Sprintf("%s\n       Link: %s", footer, aec.Selection.InfoURL)
    92  	}
    93  
    94  	if aec.Selection.Name == string(aec.Selection.Subject) {
    95  		return fmt.Sprintf("  %s %s %s%s", k, aec.Selection.Subject, p, footer)
    96  	}
    97  
    98  	return fmt.Sprintf("  %s [%s] %s %s%s", k, aec.Selection.Name, aec.Selection.Subject, p, footer)
    99  }
   100  
   101  type AccountImport struct {
   102  	Name string
   103  	ID   string
   104  }
   105  
   106  type AccountImportChoice struct {
   107  	AccountImport
   108  	Selection *jwt.Import
   109  }
   110  
   111  type AccountImportChoices []AccountImportChoice
   112  
   113  func (aes AccountImportChoices) String() []string {
   114  	var choices []string
   115  	for _, c := range aes {
   116  		choices = append(choices, c.String())
   117  	}
   118  	return choices
   119  }
   120  
   121  func (aec *AccountImportChoice) String() string {
   122  	label := aec.Name
   123  	if label == "" {
   124  		label = aec.ID
   125  	}
   126  
   127  	// an actual export
   128  	k := "->"
   129  	if aec.Selection.IsService() {
   130  		k = "<-"
   131  	}
   132  
   133  	p := ""
   134  	if aec.Selection.Token != "" {
   135  		p = "[!]"
   136  	}
   137  
   138  	if aec.Selection.Name == string(aec.Selection.Subject) {
   139  		return fmt.Sprintf("  %s %s %s (%s)", k, aec.Selection.Subject, p, label)
   140  	}
   141  
   142  	return fmt.Sprintf("  %s [%s] %s %s (%s)", k, aec.Selection.Name, aec.Selection.Subject, p, label)
   143  }
   144  
   145  func GetAccountImports(ac *jwt.AccountClaims) (AccountImportChoices, error) {
   146  	config := GetConfig()
   147  	if config.StoreRoot == "" {
   148  		return nil, errors.New("no store set - `env --store <dir>`")
   149  	}
   150  	idToName := make(map[string]string)
   151  	operators := config.ListOperators()
   152  	for _, o := range operators {
   153  		if o == "" {
   154  			continue
   155  		}
   156  		s, err := config.LoadStore(o)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  		accounts, err := s.ListSubContainers(store.Accounts)
   161  		if err != nil {
   162  			return nil, err
   163  		}
   164  		for _, a := range accounts {
   165  			ac, err := s.ReadAccountClaim(a)
   166  			if err != nil {
   167  				if store.IsNotExist(err) {
   168  					// ignore it and move on
   169  					continue
   170  				}
   171  				return nil, err
   172  			}
   173  			if ac != nil {
   174  				idToName[ac.Subject] = ac.Name
   175  			}
   176  		}
   177  	}
   178  
   179  	var a AccountImportChoices
   180  	for _, v := range ac.Imports {
   181  		var aic AccountImportChoice
   182  		aic.ID = v.Account
   183  		aic.Name = idToName[aic.ID]
   184  		aic.Selection = v
   185  		a = append(a, aic)
   186  	}
   187  	return a, nil
   188  }
   189  
   190  func GetAccountExports(ac *jwt.AccountClaims) ([]AccountExportChoice, error) {
   191  	if ac == nil {
   192  		return nil, nil
   193  	}
   194  	if len(ac.Exports) == 0 {
   195  		return nil, nil
   196  	}
   197  	var export AccountExport
   198  	export.Exports = ac.Exports
   199  	export.AccountClaims = *ac
   200  	return export.Choices()[1:], nil
   201  }
   202  
   203  func GetAllExports() ([]AccountExport, error) {
   204  	var exports []AccountExport
   205  
   206  	config := GetConfig()
   207  	if config.StoreRoot == "" {
   208  		return nil, errors.New("no store set - `env --store <dir>`")
   209  	}
   210  	operators := config.ListOperators()
   211  	for _, o := range operators {
   212  		if o == "" {
   213  			continue
   214  		}
   215  
   216  		s, err := config.LoadStore(o)
   217  		if err != nil {
   218  			return nil, err
   219  		}
   220  		accounts, err := s.ListSubContainers(store.Accounts)
   221  		if err != nil {
   222  			return nil, err
   223  		}
   224  		for _, a := range accounts {
   225  			ac, err := s.ReadAccountClaim(a)
   226  			if err != nil {
   227  				if store.IsNotExist(err) {
   228  					// ignore it and move on
   229  					continue
   230  				}
   231  				return nil, err
   232  			}
   233  
   234  			if len(ac.Exports) == 0 {
   235  				continue
   236  			}
   237  
   238  			var export AccountExport
   239  			export.OperatorName = o
   240  			export.Exports = ac.Exports
   241  			export.AccountClaims = *ac
   242  			exports = append(exports, export)
   243  		}
   244  	}
   245  
   246  	sort.Sort(ByAccountName(exports))
   247  	return exports, nil
   248  }