github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/cmd/revoke_clearactivation.go (about)

     1  /*
     2   * Copyright 2018-2022 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  	cli "github.com/nats-io/cliprompts/v2"
    22  	"github.com/nats-io/jwt/v2"
    23  	"github.com/nats-io/nkeys"
    24  	"github.com/nats-io/nsc/cmd/store"
    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  	if err := p.accountKey.SetDefaults(ctx); err != nil {
    70  		return err
    71  	}
    72  	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
    73  	return nil
    74  }
    75  
    76  func (p *RevokeClearActivationParams) PreInteractive(ctx ActionCtx) error {
    77  	var err error
    78  
    79  	if err = p.AccountContextParams.Edit(ctx); err != nil {
    80  		return err
    81  	}
    82  
    83  	p.service, err = cli.Confirm("is service", p.service)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	return nil
    89  }
    90  
    91  func (p *RevokeClearActivationParams) Load(ctx ActionCtx) error {
    92  	var err error
    93  
    94  	if err = p.AccountContextParams.Validate(ctx); err != nil {
    95  		return err
    96  	}
    97  
    98  	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	if len(p.claim.Exports) == 0 {
   104  		return fmt.Errorf("account %q doesn't have exports", p.AccountContextParams.Name)
   105  	}
   106  
   107  	kind := jwt.Stream
   108  	if p.service {
   109  		kind = jwt.Service
   110  	}
   111  
   112  	for _, v := range p.claim.Exports {
   113  		if v.Type != kind {
   114  			continue
   115  		}
   116  		p.possibleExports.Add(v)
   117  	}
   118  
   119  	if len(p.possibleExports) == 0 {
   120  		return fmt.Errorf("account %q doesn't have %v exports",
   121  			p.AccountContextParams.Name, kind)
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func (p *RevokeClearActivationParams) PostInteractive(ctx ActionCtx) error {
   128  	var exports []string
   129  	if p.subject == "" {
   130  		for _, v := range p.possibleExports {
   131  			exports = append(exports, string(v.Subject))
   132  		}
   133  	}
   134  	kind := jwt.Stream
   135  	if p.service {
   136  		kind = jwt.Service
   137  	}
   138  
   139  	i, err := cli.Select(fmt.Sprintf("select %v export", kind), "", exports)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	p.export = p.possibleExports[i]
   144  	if p.subject == "" {
   145  		p.subject = string(p.export.Subject)
   146  	}
   147  	if len(p.export.Revocations) == 0 {
   148  		return fmt.Errorf("%v export %s doesn't have revocations", kind, p.export.Name)
   149  	}
   150  	accounts, err := ListAccounts(ctx.StoreCtx().Store)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	keyToName := make(map[string]string)
   155  	keyToName["*"] = "* [All Accounts]"
   156  	for _, a := range accounts {
   157  		if a.Err == nil {
   158  			keyToName[a.Claims.Claims().Subject] = a.Name
   159  		}
   160  	}
   161  	var keys []PubKeyChoice
   162  	for k := range p.export.Revocations {
   163  		n := keyToName[k]
   164  		if n == "" {
   165  			n = "[Unknown Account]"
   166  		}
   167  		n = fmt.Sprintf("%s: %s", k, n)
   168  		keys = append(keys, PubKeyChoice{Key: k, Label: n})
   169  	}
   170  	if err = p.accountKey.Select("select account revocation to delete", keys...); err != nil {
   171  		return err
   172  	}
   173  	return p.SignerParams.Edit(ctx)
   174  }
   175  
   176  func (p *RevokeClearActivationParams) Validate(ctx ActionCtx) error {
   177  	if len(p.possibleExports) == 1 && p.subject == "" {
   178  		p.subject = string(p.possibleExports[0].Subject)
   179  	}
   180  	if p.subject == "" {
   181  		ctx.CurrentCmd().SilenceUsage = false
   182  		return fmt.Errorf("a subject is required")
   183  	}
   184  	if err := p.accountKey.Valid(); err != nil {
   185  		return err
   186  	}
   187  	sub := jwt.Subject(p.subject)
   188  	for _, e := range p.possibleExports {
   189  		if sub.IsContainedIn(e.Subject) {
   190  			p.export = e
   191  			break
   192  		}
   193  	}
   194  	if p.export == nil {
   195  		return fmt.Errorf("unable to locate export")
   196  	}
   197  	return p.SignerParams.Resolve(ctx)
   198  }
   199  
   200  func (p *RevokeClearActivationParams) Run(ctx ActionCtx) (store.Status, error) {
   201  	p.export.ClearRevocation(p.accountKey.publicKey)
   202  	token, err := p.claim.Encode(p.signerKP)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	r := store.NewDetailedReport(true)
   207  	StoreAccountAndUpdateStatus(ctx, token, r)
   208  	if r.HasNoErrors() {
   209  		kind := jwt.Stream
   210  		if p.service {
   211  			kind = jwt.Service
   212  		}
   213  
   214  		if p.accountKey.publicKey == jwt.All {
   215  			r.AddOK("deleted %v %s revocation for all accounts", kind, p.export.Name)
   216  		} else {
   217  			r.AddOK("deleted %v %s revocation for account %s", kind, p.export.Name, p.accountKey.publicKey)
   218  		}
   219  	}
   220  	return r, nil
   221  }