github.com/kbehouse/nsc@v0.0.6/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 "github.com/kbehouse/nsc/cmd/store" 24 cli "github.com/nats-io/cliprompts/v2" 25 "github.com/nats-io/nkeys" 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, ¶ms) 39 }, 40 } 41 cmd.Flags().StringSliceVarP(¶ms.names, "name", "n", nil, "name of user(s) to delete") 42 cmd.Flags().BoolVarP(¶ms.revoke, "revoke", "R", false, "revoke user before deleting") 43 cmd.Flags().BoolVarP(¶ms.rmNKey, "rm-nkey", "D", false, "delete the user key") 44 cmd.Flags().BoolVarP(¶ms.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 }