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

     1  /*
     2   * Copyright 2018-2020 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  	"fmt"
    20  	"time"
    21  
    22  	"github.com/kbehouse/nsc/cmd/store"
    23  	cli "github.com/nats-io/cliprompts/v2"
    24  	"github.com/nats-io/jwt/v2"
    25  	"github.com/nats-io/nkeys"
    26  	"github.com/spf13/cobra"
    27  	"github.com/xlab/tablewriter"
    28  )
    29  
    30  func createRevokeListActivationCmd() *cobra.Command {
    31  	var params RevokeListActivationParams
    32  	cmd := &cobra.Command{
    33  		Use:          "list_activations",
    34  		Aliases:      []string{"list-activations"},
    35  		Short:        "List account revocations for an export",
    36  		Args:         MaxArgs(0),
    37  		SilenceUsage: true,
    38  		RunE: func(cmd *cobra.Command, args []string) error {
    39  			return RunAction(cmd, args, &params)
    40  		},
    41  	}
    42  
    43  	cmd.Flags().StringVarP(&params.subject, "subject", "s", "", "export subject")
    44  	cmd.Flags().BoolVarP(&params.service, "service", "", false, "service")
    45  
    46  	params.AccountContextParams.BindFlags(cmd)
    47  
    48  	return cmd
    49  }
    50  
    51  func init() {
    52  	revokeCmd.AddCommand(createRevokeListActivationCmd())
    53  }
    54  
    55  // RevokeListActivationParams hold the info necessary to add a user to the revocation list in an account
    56  type RevokeListActivationParams struct {
    57  	AccountContextParams
    58  	SignerParams
    59  	claim           *jwt.AccountClaims
    60  	export          *jwt.Export
    61  	possibleExports jwt.Exports
    62  	subject         string
    63  	service         bool
    64  }
    65  
    66  func (p *RevokeListActivationParams) SetDefaults(ctx ActionCtx) error {
    67  	p.AccountContextParams.SetDefaults(ctx)
    68  	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
    69  	return nil
    70  }
    71  
    72  func (p *RevokeListActivationParams) PreInteractive(ctx ActionCtx) error {
    73  	var err error
    74  
    75  	if err = p.AccountContextParams.Edit(ctx); err != nil {
    76  		return err
    77  	}
    78  
    79  	p.service, err = cli.Confirm("is service", p.service)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func (p *RevokeListActivationParams) Load(ctx ActionCtx) error {
    88  	var err error
    89  
    90  	if err = p.AccountContextParams.Validate(ctx); err != nil {
    91  		return err
    92  	}
    93  
    94  	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	if len(p.claim.Exports) == 0 {
   100  		return fmt.Errorf("account %q doesn't have exports", p.AccountContextParams.Name)
   101  	}
   102  
   103  	kind := jwt.Stream
   104  	if p.service {
   105  		kind = jwt.Service
   106  	}
   107  
   108  	for _, v := range p.claim.Exports {
   109  		if v.Type != kind {
   110  			continue
   111  		}
   112  		p.possibleExports.Add(v)
   113  	}
   114  
   115  	if len(p.possibleExports) == 0 {
   116  		return fmt.Errorf("account %q doesn't have %v exports",
   117  			p.AccountContextParams.Name, kind)
   118  	}
   119  
   120  	return nil
   121  }
   122  
   123  func (p *RevokeListActivationParams) Validate(ctx ActionCtx) error {
   124  
   125  	if len(p.possibleExports) == 1 && p.subject == "" {
   126  		p.subject = string(p.possibleExports[0].Subject)
   127  	}
   128  
   129  	if p.subject == "" {
   130  		ctx.CurrentCmd().SilenceUsage = false
   131  		return fmt.Errorf("a subject is required")
   132  	}
   133  
   134  	sub := jwt.Subject(p.subject)
   135  	for _, e := range p.possibleExports {
   136  		if sub.IsContainedIn(e.Subject) {
   137  			p.export = e
   138  			break
   139  		}
   140  	}
   141  
   142  	if err := p.SignerParams.Resolve(ctx); err != nil {
   143  		return err
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  func (p *RevokeListActivationParams) PostInteractive(ctx ActionCtx) error {
   150  	var choices []string
   151  	if p.subject == "" {
   152  		for _, v := range p.possibleExports {
   153  			choices = append(choices, string(v.Subject))
   154  		}
   155  	}
   156  	kind := jwt.Stream
   157  	if p.service {
   158  		kind = jwt.Service
   159  	}
   160  
   161  	i, err := cli.Select(fmt.Sprintf("select %s export", kind.String()), "", choices)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	p.export = p.possibleExports[i]
   166  	if p.subject == "" {
   167  		p.subject = string(p.export.Subject)
   168  	}
   169  
   170  	if err := p.SignerParams.Edit(ctx); err != nil {
   171  		return err
   172  	}
   173  
   174  	return nil
   175  }
   176  
   177  func (p *RevokeListActivationParams) Run(ctx ActionCtx) (store.Status, error) {
   178  	if p.export == nil {
   179  		return nil, fmt.Errorf("unable to locate export")
   180  	}
   181  	kind := jwt.Stream
   182  	if p.service {
   183  		kind = jwt.Service
   184  	}
   185  	if len(p.export.Revocations) == 0 {
   186  		return nil, fmt.Errorf("%v %s has no revocations", kind, p.export.Name)
   187  	}
   188  
   189  	name := p.export.Name
   190  	if name == "" {
   191  		name = string(p.export.Subject)
   192  	}
   193  
   194  	table := tablewriter.CreateTable()
   195  	table.AddTitle(fmt.Sprintf("Revoked Accounts for %v %s", kind, name))
   196  	table.AddHeaders("Public Key", "Revoke Credentials Before")
   197  
   198  	for pubKey, at := range p.export.Revocations {
   199  		if pubKey == "*" {
   200  			pubKey = "* [All Accounts]"
   201  		}
   202  		t := time.Unix(at, 0)
   203  		formatted := t.Format(time.RFC1123)
   204  		table.AddRow(pubKey, formatted)
   205  	}
   206  
   207  	return nil, Write("--", []byte(table.Render()))
   208  }