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

     1  /*
     2   * Copyright 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  	"os"
    22  
    23  	cli "github.com/nats-io/cliprompts/v2"
    24  	"github.com/nats-io/nkeys"
    25  	"github.com/nats-io/nsc/cmd/store"
    26  	"github.com/spf13/cobra"
    27  )
    28  
    29  func createDeleteUserCmd() *cobra.Command {
    30  	var params DeleteUserParams
    31  	cmd := &cobra.Command{
    32  		Use:   "user",
    33  		Short: "Delete an user",
    34  		Args:  cobra.MaximumNArgs(1),
    35  		Example: `nsc delete user -n name
    36  nsc delete user -i`,
    37  		RunE: func(cmd *cobra.Command, args []string) error {
    38  			return RunAction(cmd, args, &params)
    39  		},
    40  	}
    41  	cmd.Flags().StringSliceVarP(&params.names, "name", "n", nil, "name of user(s) to delete")
    42  	cmd.Flags().BoolVarP(&params.revoke, "revoke", "R", false, "revoke user before deleting")
    43  	cmd.Flags().BoolVarP(&params.rmNKey, "rm-nkey", "D", false, "delete the user key")
    44  	cmd.Flags().BoolVarP(&params.rmCreds, "rm-creds", "C", false, "delete the user creds")
    45  	params.AccountContextParams.BindFlags(cmd)
    46  
    47  	return cmd
    48  }
    49  
    50  func init() {
    51  	deleteCmd.AddCommand(createDeleteUserCmd())
    52  }
    53  
    54  type DeleteUserParams struct {
    55  	AccountContextParams
    56  	SignerParams
    57  	names   []string
    58  	revoke  bool
    59  	rmNKey  bool
    60  	rmCreds bool
    61  }
    62  
    63  func (p *DeleteUserParams) SetDefaults(ctx ActionCtx) error {
    64  	if err := p.AccountContextParams.SetDefaults(ctx); err != nil {
    65  		return err
    66  	}
    67  	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
    68  
    69  	if len(ctx.Args()) > 0 {
    70  		p.names = append(p.names, ctx.Args()[0])
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  func (p *DeleteUserParams) PreInteractive(ctx ActionCtx) error {
    77  	var err error
    78  	if err = p.AccountContextParams.Edit(ctx); err != nil {
    79  		return err
    80  	}
    81  
    82  	users, err := ctx.StoreCtx().Store.ListEntries(store.Accounts, p.AccountContextParams.Name, store.Users)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if len(users) == 0 {
    87  		return fmt.Errorf("account %q doesn't have any users - add one first", p.AccountContextParams.Name)
    88  	}
    89  	if len(users) > 0 {
    90  		sel, err := cli.MultiSelect("select users", users)
    91  		if err != nil {
    92  			return err
    93  		}
    94  		p.names = nil
    95  		for _, i := range sel {
    96  			p.names = append(p.names, users[i])
    97  		}
    98  	}
    99  
   100  	m := "revoke user before deleting"
   101  	if len(p.names) > 1 {
   102  		m = "revoke users before deleting"
   103  	}
   104  	p.revoke, err = cli.Confirm(m, false)
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	m = "delete associated nkey"
   110  	if len(p.names) > 1 {
   111  		m = "delete associated nkeys"
   112  	}
   113  	p.rmNKey, err = cli.Confirm(m, false)
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	m = "delete associated creds file"
   119  	if len(p.names) > 1 {
   120  		m = "delete associated creds files"
   121  	}
   122  	p.rmCreds, err = cli.Confirm(m, false)
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	return nil
   128  }
   129  
   130  func (p *DeleteUserParams) Load(ctx ActionCtx) error {
   131  	return nil
   132  }
   133  
   134  func (p *DeleteUserParams) PostInteractive(ctx ActionCtx) error {
   135  	var err error
   136  
   137  	m := "deleting a user, nkey or creds file cannot be undone - continue"
   138  	if len(p.names) > 1 {
   139  		m = "deleting users, nkeys or creds files cannot be undone - continue"
   140  	}
   141  	ok, err := cli.Confirm(m, false)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	if !ok {
   146  		return fmt.Errorf("delete cancelled")
   147  	}
   148  
   149  	if err := p.SignerParams.Edit(ctx); err != nil {
   150  		return err
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  func (p *DeleteUserParams) Validate(ctx ActionCtx) error {
   157  	if len(p.names) == 0 {
   158  		return errors.New("please specify an user to delete")
   159  	}
   160  
   161  	s := ctx.StoreCtx().Store
   162  	for _, n := range p.names {
   163  		_, err := s.ReadUserClaim(p.AccountContextParams.Name, n)
   164  		if err != nil {
   165  			return err
   166  		}
   167  	}
   168  
   169  	if err := p.SignerParams.Resolve(ctx); err != nil {
   170  		return err
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  func (p *DeleteUserParams) Run(ctx ActionCtx) (store.Status, error) {
   177  	r := store.NewReport(store.OK, "delete users")
   178  	revoked := false
   179  	s := ctx.StoreCtx().Store
   180  	ac, err := s.ReadAccountClaim(p.AccountContextParams.Name)
   181  	if err != nil {
   182  		r.AddError("error loading account: %v", err)
   183  		return r, err
   184  	}
   185  	for _, n := range p.names {
   186  		// cannot fail
   187  		uc, err := s.ReadUserClaim(p.AccountContextParams.Name, n)
   188  		if err != nil {
   189  			r.AddError("error loading user %s: %v", n, err)
   190  			continue
   191  		}
   192  
   193  		ru := store.NewReport(store.OK, fmt.Sprintf("user %s [%s]", n, uc.Subject))
   194  		r.Add(ru)
   195  
   196  		if p.revoke {
   197  			if ac.Revocations[uc.Subject] == 0 {
   198  				ac.Revoke(uc.Subject)
   199  				ru.AddOK("revoked user")
   200  				revoked = true
   201  			} else {
   202  				ru.AddOK("user is already revoked")
   203  			}
   204  		}
   205  
   206  		if err := s.Delete(store.Accounts, p.AccountContextParams.Name, store.Users, store.JwtName(n)); err != nil {
   207  			ru.AddFromError(err)
   208  		} else {
   209  			ru.AddOK("user deleted")
   210  		}
   211  		if p.rmNKey {
   212  			if ctx.StoreCtx().KeyStore.HasPrivateKey(uc.Subject) {
   213  				if err := ctx.StoreCtx().KeyStore.Remove(uc.Subject); err != nil {
   214  					ru.AddFromError(err)
   215  				} else {
   216  					ru.AddOK("deleted private key")
   217  				}
   218  			} else {
   219  				ru.AddOK("private key is not stored")
   220  			}
   221  		}
   222  		if p.rmCreds {
   223  			fp := ctx.StoreCtx().KeyStore.GetUserCredsPath(p.AccountContextParams.Name, n)
   224  			if _, err := os.Stat(fp); os.IsNotExist(err) {
   225  				ru.AddOK("creds file is not stored")
   226  			} else {
   227  				if err := os.Remove(fp); err != nil {
   228  					ru.AddError("error deleting creds file %s: %v", fp, err)
   229  				} else {
   230  					ru.AddOK("removed creds file")
   231  				}
   232  			}
   233  		}
   234  	}
   235  
   236  	if revoked {
   237  		token, err := ac.Encode(p.signerKP)
   238  		if err != nil {
   239  			return nil, err
   240  		}
   241  		StoreAccountAndUpdateStatus(ctx, token, r)
   242  		if ctx.StoreCtx().Store.IsManaged() {
   243  			_, err := ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
   244  			if err != nil {
   245  				r.AddWarning("unable to read account %q: %v", p.AccountContextParams.Name, err)
   246  			}
   247  		}
   248  		r.AddOK("edited account %q", p.AccountContextParams.Name)
   249  	}
   250  
   251  	return r, nil
   252  }