github.com/kbehouse/nsc@v0.0.6/cmd/revoke_clearactivation.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  
    21  	"github.com/kbehouse/nsc/cmd/store"
    22  	cli "github.com/nats-io/cliprompts/v2"
    23  	"github.com/nats-io/jwt/v2"
    24  	"github.com/nats-io/nkeys"
    25  	"github.com/spf13/cobra"
    26  )
    27  
    28  func createClearRevokeActivationCmd() *cobra.Command {
    29  	var params RevokeClearActivationParams
    30  	cmd := &cobra.Command{
    31  		Use:          "delete_activation",
    32  		Aliases:      []string{"delete-activation"},
    33  		Short:        "Remove an account revocation from an export",
    34  		Args:         MaxArgs(0),
    35  		SilenceUsage: true,
    36  		RunE: func(cmd *cobra.Command, args []string) error {
    37  			return RunAction(cmd, args, &params)
    38  		},
    39  	}
    40  
    41  	cmd.Flags().StringVarP(&params.subject, "subject", "s", "", "export subject")
    42  	cmd.Flags().BoolVarP(&params.service, "service", "", false, "service")
    43  	params.accountKey.BindFlags("target-account", "t", nkeys.PrefixByteAccount, cmd)
    44  
    45  	params.AccountContextParams.BindFlags(cmd)
    46  
    47  	return cmd
    48  }
    49  
    50  func init() {
    51  	revokeCmd.AddCommand(createClearRevokeActivationCmd())
    52  }
    53  
    54  // RevokeClearActivationParams hold the info necessary to add a user to the revocation list in an account
    55  type RevokeClearActivationParams struct {
    56  	AccountContextParams
    57  	SignerParams
    58  	claim           *jwt.AccountClaims
    59  	export          *jwt.Export
    60  	possibleExports jwt.Exports
    61  	subject         string
    62  	service         bool
    63  	accountKey      PubKeyParams
    64  }
    65  
    66  func (p *RevokeClearActivationParams) SetDefaults(ctx ActionCtx) error {
    67  	p.accountKey.AllowWildcard = true
    68  	p.AccountContextParams.SetDefaults(ctx)
    69  	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
    70  	return nil
    71  }
    72  
    73  func (p *RevokeClearActivationParams) PreInteractive(ctx ActionCtx) error {
    74  	var err error
    75  
    76  	if err = p.AccountContextParams.Edit(ctx); err != nil {
    77  		return err
    78  	}
    79  
    80  	p.service, err = cli.Confirm("is service", p.service)
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  func (p *RevokeClearActivationParams) Load(ctx ActionCtx) error {
    89  	var err error
    90  
    91  	if err = p.AccountContextParams.Validate(ctx); err != nil {
    92  		return err
    93  	}
    94  
    95  	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	if len(p.claim.Exports) == 0 {
   101  		return fmt.Errorf("account %q doesn't have exports", p.AccountContextParams.Name)
   102  	}
   103  
   104  	kind := jwt.Stream
   105  	if p.service {
   106  		kind = jwt.Service
   107  	}
   108  
   109  	for _, v := range p.claim.Exports {
   110  		if v.Type != kind {
   111  			continue
   112  		}
   113  		p.possibleExports.Add(v)
   114  	}
   115  
   116  	if len(p.possibleExports) == 0 {
   117  		return fmt.Errorf("account %q doesn't have %v exports",
   118  			p.AccountContextParams.Name, kind)
   119  	}
   120  
   121  	return nil
   122  }
   123  
   124  func (p *RevokeClearActivationParams) PostInteractive(ctx ActionCtx) error {
   125  	var exports []string
   126  	if p.subject == "" {
   127  		for _, v := range p.possibleExports {
   128  			exports = append(exports, string(v.Subject))
   129  		}
   130  	}
   131  	kind := jwt.Stream
   132  	if p.service {
   133  		kind = jwt.Service
   134  	}
   135  
   136  	i, err := cli.Select(fmt.Sprintf("select %v export", kind), "", exports)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	p.export = p.possibleExports[i]
   141  	if p.subject == "" {
   142  		p.subject = string(p.export.Subject)
   143  	}
   144  	if len(p.export.Revocations) == 0 {
   145  		return fmt.Errorf("%v export %s doesn't have revocations", kind, p.export.Name)
   146  	}
   147  	accounts, err := ListAccounts(ctx.StoreCtx().Store)
   148  	if err != nil {
   149  		return err
   150  	}
   151  	keyToName := make(map[string]string)
   152  	keyToName["*"] = "* [All Accounts]"
   153  	for _, a := range accounts {
   154  		if a.Err == nil {
   155  			keyToName[a.Claims.Claims().Subject] = a.Name
   156  		}
   157  	}
   158  	var keys []PubKeyChoice
   159  	for k := range p.export.Revocations {
   160  		n := keyToName[k]
   161  		if n == "" {
   162  			n = "[Unknown Account]"
   163  		}
   164  		n = fmt.Sprintf("%s: %s", k, n)
   165  		keys = append(keys, PubKeyChoice{Key: k, Label: n})
   166  	}
   167  	if err = p.accountKey.Select("select account revocation to delete", keys...); err != nil {
   168  		return err
   169  	}
   170  	return p.SignerParams.Edit(ctx)
   171  }
   172  
   173  func (p *RevokeClearActivationParams) Validate(ctx ActionCtx) error {
   174  	if len(p.possibleExports) == 1 && p.subject == "" {
   175  		p.subject = string(p.possibleExports[0].Subject)
   176  	}
   177  	if p.subject == "" {
   178  		ctx.CurrentCmd().SilenceUsage = false
   179  		return fmt.Errorf("a subject is required")
   180  	}
   181  	if err := p.accountKey.Valid(); err != nil {
   182  		return err
   183  	}
   184  	sub := jwt.Subject(p.subject)
   185  	for _, e := range p.possibleExports {
   186  		if sub.IsContainedIn(e.Subject) {
   187  			p.export = e
   188  			break
   189  		}
   190  	}
   191  	if p.export == nil {
   192  		return fmt.Errorf("unable to locate export")
   193  	}
   194  	return p.SignerParams.Resolve(ctx)
   195  }
   196  
   197  func (p *RevokeClearActivationParams) Run(ctx ActionCtx) (store.Status, error) {
   198  	p.export.ClearRevocation(p.accountKey.publicKey)
   199  	token, err := p.claim.Encode(p.signerKP)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	r := store.NewDetailedReport(true)
   204  	StoreAccountAndUpdateStatus(ctx, token, r)
   205  	if r.HasNoErrors() {
   206  		kind := jwt.Stream
   207  		if p.service {
   208  			kind = jwt.Service
   209  		}
   210  
   211  		if p.accountKey.publicKey == jwt.All {
   212  			r.AddOK("deleted %v %s revocation for all accounts", kind, p.export.Name)
   213  		} else {
   214  			r.AddOK("deleted %v %s revocation for account %s", kind, p.export.Name, p.accountKey.publicKey)
   215  		}
   216  	}
   217  	return r, nil
   218  }