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, ¶ms) 38 }, 39 } 40 41 cmd.Flags().StringVarP(¶ms.subject, "subject", "s", "", "export subject") 42 cmd.Flags().BoolVarP(¶ms.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 }