github.com/kbehouse/nsc@v0.0.6/cmd/keycollector.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  	"sort"
    20  	"strings"
    21  
    22  	"github.com/kbehouse/nsc/cmd/store"
    23  	"github.com/nats-io/nkeys"
    24  )
    25  
    26  type KeyCollectorParams struct {
    27  	Operator     bool
    28  	Accounts     bool
    29  	Users        bool
    30  	All          bool
    31  	Unreferenced bool
    32  	Account      string
    33  	User         string
    34  	Filter       string
    35  }
    36  
    37  func (p *KeyCollectorParams) SetDefaults(ctx ActionCtx) error {
    38  	conf := GetConfig()
    39  
    40  	if ctx.NothingToDo("operator", "accounts", "users", "all") {
    41  		// default if no args
    42  		account := p.Account
    43  		if account == "" {
    44  			account = conf.Account
    45  		}
    46  		p.Operator = true
    47  		p.Account = account
    48  		p.Accounts = true
    49  		p.Users = true
    50  	}
    51  	if p.All {
    52  		p.Operator = true
    53  		p.Accounts = true
    54  		p.Users = true
    55  	}
    56  	return nil
    57  }
    58  
    59  func (p *KeyCollectorParams) handleOperator(ctx ActionCtx) (KeyList, error) {
    60  	var keys KeyList
    61  	sctx := ctx.StoreCtx()
    62  
    63  	// if we don't have a store - ignore this operator details
    64  	if sctx.Operator.Name == "" {
    65  		return nil, nil
    66  	}
    67  	oc, err := sctx.Store.ReadOperatorClaim()
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	var oki Key
    72  	oki.Name = oc.Name
    73  	oki.ExpectedKind = nkeys.PrefixByteOperator
    74  	oki.Pub = oc.Subject
    75  	oki.Resolve(sctx.KeyStore)
    76  	keys = append(keys, &oki)
    77  
    78  	for _, k := range oc.SigningKeys {
    79  		var sk Key
    80  		sk.Name = oc.Name
    81  		sk.Pub = k
    82  		sk.Signing = true
    83  		sk.ExpectedKind = nkeys.PrefixByteOperator
    84  		sk.Resolve(sctx.KeyStore)
    85  		keys = append(keys, &sk)
    86  	}
    87  
    88  	return keys, nil
    89  }
    90  
    91  func (p *KeyCollectorParams) handleAccount(ctx ActionCtx, parent string, name string) (KeyList, error) {
    92  	s := ctx.StoreCtx().Store
    93  	ks := ctx.StoreCtx().KeyStore
    94  
    95  	var keys KeyList
    96  
    97  	ac, err := s.ReadAccountClaim(name)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	var aki Key
   102  	aki.Parent = parent
   103  	aki.Name = ac.Name
   104  	aki.ExpectedKind = nkeys.PrefixByteAccount
   105  	aki.Pub = ac.Subject
   106  	aki.Resolve(ks)
   107  	keys = append(keys, &aki)
   108  
   109  	for k := range ac.SigningKeys {
   110  		var ask Key
   111  		ask.Name = ac.Name
   112  		ask.Pub = k
   113  		ask.Signing = true
   114  		ask.Resolve(ks)
   115  		keys = append(keys, &ask)
   116  	}
   117  	return keys, nil
   118  }
   119  
   120  func (p *KeyCollectorParams) handleUsers(ctx ActionCtx, account string) (KeyList, error) {
   121  	var keys KeyList
   122  
   123  	s := ctx.StoreCtx().Store
   124  	ac, err := s.ReadAccountClaim(account)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	users, err := s.ListEntries(store.Accounts, account, store.Users)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	sort.Strings(users)
   134  	for _, u := range users {
   135  		uk, err := p.handleUser(ctx, account, u)
   136  		if err != nil {
   137  			return nil, err
   138  		}
   139  		uk.Parent = ac.Subject
   140  		keys = append(keys, uk)
   141  	}
   142  	return keys, nil
   143  }
   144  
   145  func (p *KeyCollectorParams) handleUser(ctx ActionCtx, account string, name string) (*Key, error) {
   146  	s := ctx.StoreCtx().Store
   147  	ks := ctx.StoreCtx().KeyStore
   148  
   149  	uc, err := s.ReadUserClaim(account, name)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	var uki Key
   154  	uki.Name = uc.Name
   155  	uki.Pub = uc.Subject
   156  	uki.ExpectedKind = nkeys.PrefixByteUser
   157  	uki.Resolve(ks)
   158  	return &uki, nil
   159  }
   160  
   161  func (p *KeyCollectorParams) Run(ctx ActionCtx) (KeyList, error) {
   162  	keys, err := p.handleOperator(ctx)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	// if we have an operator, we can resolve other things
   168  	if keys != nil {
   169  		var accounts []string
   170  		if p.Account != "" {
   171  			accounts = append(accounts, p.Account)
   172  		} else {
   173  			an, err := GetConfig().ListAccounts()
   174  			if err != nil {
   175  				return nil, err
   176  			}
   177  			accounts = append(accounts, an...)
   178  		}
   179  		for _, a := range accounts {
   180  			akeys, err := p.handleAccount(ctx, keys[0].Pub, a)
   181  			if err != nil {
   182  				return nil, err
   183  			}
   184  			keys = append(keys, akeys...)
   185  
   186  			if p.User != "" {
   187  				uk, err := p.handleUser(ctx, a, p.User)
   188  				if err != nil {
   189  					return nil, err
   190  				}
   191  				keys = append(keys, uk)
   192  			} else {
   193  				ukeys, err := p.handleUsers(ctx, a)
   194  				if err != nil {
   195  					return nil, err
   196  				}
   197  				keys = append(keys, ukeys...)
   198  			}
   199  		}
   200  	}
   201  
   202  	if p.Unreferenced {
   203  		all, err := ctx.StoreCtx().KeyStore.AllKeys()
   204  		if err != nil {
   205  			return nil, err
   206  		}
   207  		m := make(map[string]*Key)
   208  		for _, v := range keys {
   209  			m[v.Pub] = v
   210  		}
   211  		ks := ctx.StoreCtx().KeyStore
   212  		var okeys KeyList
   213  		var akeys KeyList
   214  		var ukeys KeyList
   215  		for _, v := range all {
   216  			_, ok := m[v]
   217  			if !ok {
   218  				var k Key
   219  				k.Name = "?"
   220  				k.Pub = v
   221  				k.ExpectedKind, err = store.PubKeyType(k.Pub)
   222  				if err != nil {
   223  					return nil, err
   224  				}
   225  				k.Resolve(ks)
   226  				switch k.ExpectedKind {
   227  				case nkeys.PrefixByteOperator:
   228  					okeys = append(okeys, &k)
   229  				case nkeys.PrefixByteAccount:
   230  					akeys = append(akeys, &k)
   231  				case nkeys.PrefixByteUser:
   232  					ukeys = append(ukeys, &k)
   233  				}
   234  			}
   235  		}
   236  		sort.Sort(okeys)
   237  		sort.Sort(akeys)
   238  		sort.Sort(ukeys)
   239  		keys = KeyList{}
   240  		keys = append(keys, okeys...)
   241  		keys = append(keys, akeys...)
   242  		keys = append(keys, ukeys...)
   243  	}
   244  
   245  	var keyFilter = strings.ToUpper(p.Filter)
   246  	var filteredKeys KeyList
   247  	for _, k := range keys {
   248  		if !p.Operator && k.ExpectedKind == nkeys.PrefixByteOperator {
   249  			continue
   250  		}
   251  		if !p.Accounts && k.ExpectedKind == nkeys.PrefixByteAccount {
   252  			continue
   253  		}
   254  		if !p.Users && k.ExpectedKind == nkeys.PrefixByteUser {
   255  			continue
   256  		}
   257  		if keyFilter != "" && !strings.Contains(k.Pub, keyFilter) {
   258  			continue
   259  		}
   260  		filteredKeys = append(filteredKeys, k)
   261  	}
   262  
   263  	return filteredKeys, nil
   264  }
   265  
   266  type Key struct {
   267  	Name         string
   268  	Pub          string
   269  	Parent       string
   270  	ExpectedKind nkeys.PrefixByte
   271  	Signing      bool
   272  	KeyPath      string
   273  	Invalid      bool
   274  }
   275  
   276  func (k *Key) Resolve(ks store.KeyStore) {
   277  	kp, _ := ks.GetKeyPair(k.Pub)
   278  	if kp != nil {
   279  		k.KeyPath = ks.GetKeyPath(k.Pub)
   280  		pk, _ := kp.PublicKey()
   281  		k.Invalid = pk != k.Pub
   282  	}
   283  }
   284  
   285  func (k *Key) HasKey() bool {
   286  	return k.KeyPath != ""
   287  }
   288  
   289  type Keys struct {
   290  	KeyList
   291  	MessageFn func(ks Keys) string
   292  }
   293  
   294  func (keys Keys) Message() string {
   295  	return keys.MessageFn(keys)
   296  }
   297  
   298  type KeyList []*Key
   299  
   300  func (ks KeyList) Code() store.StatusCode {
   301  	return store.OK
   302  }
   303  
   304  func (ks KeyList) Len() int {
   305  	return len(ks)
   306  }
   307  
   308  func (ks KeyList) Swap(i, j int) {
   309  	ks[i], ks[j] = ks[j], ks[i]
   310  }
   311  
   312  func (ks KeyList) Less(i, j int) bool {
   313  	return ks[i].Pub < ks[j].Pub
   314  }