Repository: nats-io/nsc
Pull request #333 (2020-12-09 17:28:31)

allow nsc update to work when encountering jwt v1 operator
Signed-off-by: Matthias Hanel <mh@synadia.com>


Patch:
diff --git a/Makefile b/Makefile
index 3ef7305..d4d832b 100644
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,6 @@ test:
 	rm -rf ./coverage.out
 	staticcheck -f text ./...
 	go test -coverpkg=./... -coverprofile=./coverage.out ./...
-	staticcheck ./...
 
 release: fmt test compile
 
diff --git a/cmd/list.go b/cmd/list.go
index e1a081c..c7f1d57 100644
--- a/cmd/list.go
+++ b/cmd/list.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -40,10 +40,10 @@ func init() {
 	listCmd.AddCommand(createListUsersCmd())
 }
 
-type EntryInfo struct {
-	Name   string
-	Claims jwt.Claims
-	Err    error
+type listEntry struct {
+	name   string
+	claims jwt.Claims
+	err    error
 }
 
 func createListOperatorsCmd() *cobra.Command {
@@ -61,26 +61,26 @@ func createListOperatorsCmd() *cobra.Command {
 				fmt.Println("no operators defined - init an environment")
 			} else {
 				sort.Strings(operators)
-				var infos []*EntryInfo
+				var infos []*listEntry
 				for _, v := range operators {
-					var i EntryInfo
+					var i listEntry
 					infos = append(infos, &i)
-					i.Name = v
+					i.name = v
 					s, err := config.LoadStore(v)
 					if err != nil {
-						i.Err = err
+						i.err = err
 						continue
 					}
 					c, err := s.LoadRootClaim()
 					if err != nil {
-						i.Err = err
+						i.err = err
 						continue
 					}
 					if c == nil {
-						i.Err = fmt.Errorf("%q jwt not found", v)
+						i.err = fmt.Errorf("%q jwt not found", v)
 						continue
 					}
-					i.Claims = c
+					i.claims = c
 				}
 				cmd.Println(listEntities("Operators", infos, config.Operator))
 			}
@@ -91,28 +91,6 @@ func createListOperatorsCmd() *cobra.Command {
 	return cmd
 }
 
-func ListAccounts(s *store.Store) ([]*EntryInfo, error) {
-	accounts, err := s.ListSubContainers(store.Accounts)
-	if err != nil {
-		return nil, err
-	}
-	sort.Strings(accounts)
-
-	var infos []*EntryInfo
-	for _, v := range accounts {
-		var i EntryInfo
-		i.Name = v
-		infos = append(infos, &i)
-		ac, err := s.ReadAccountClaim(v)
-		if err != nil {
-			i.Err = err
-			continue
-		}
-		i.Claims = ac
-	}
-	return infos, nil
-}
-
 func createListAccountsCmd() *cobra.Command {
 	var operator string
 
@@ -143,17 +121,17 @@ func createListAccountsCmd() *cobra.Command {
 				return err
 			}
 
-			var infos []*EntryInfo
+			var infos []*listEntry
 			for _, v := range containers {
-				var i EntryInfo
-				i.Name = v
+				var i listEntry
+				i.name = v
 				infos = append(infos, &i)
 				ac, err := s.ReadAccountClaim(v)
 				if err != nil {
-					i.Err = err
+					i.err = err
 					continue
 				}
-				i.Claims = ac
+				i.claims = ac
 			}
 			cmd.Println(listEntities("Accounts", infos, config.Account))
 			return nil
@@ -165,32 +143,6 @@ func createListAccountsCmd() *cobra.Command {
 	return cmd
 }
 
-func ListUsers(s *store.Store, accountName string) ([]*EntryInfo, error) {
-	names, err := s.ListEntries(store.Accounts, accountName, store.Users)
-	if err != nil {
-		return nil, err
-	}
-	sort.Strings(names)
-
-	var infos []*EntryInfo
-	for _, v := range names {
-		var i EntryInfo
-		i.Name = v
-		infos = append(infos, &i)
-		uc, err := s.ReadUserClaim(accountName, v)
-		if err != nil {
-			i.Err = err
-			continue
-		}
-		if uc == nil {
-			i.Err = fmt.Errorf("%q jwt not found", v)
-			continue
-		}
-		i.Claims = uc
-	}
-	return infos, nil
-}
-
 func createListUsersCmd() *cobra.Command {
 	var operator string
 	var account string
@@ -225,11 +177,28 @@ func createListUsersCmd() *cobra.Command {
 				return err
 			}
 
-			infos, err := ListUsers(s, config.Account)
+			names, err := s.ListEntries(store.Accounts, config.Account, store.Users)
 			if err != nil {
 				return err
 			}
+			sort.Strings(names)
 
+			var infos []*listEntry
+			for _, v := range names {
+				var i listEntry
+				i.name = v
+				infos = append(infos, &i)
+				uc, err := s.ReadUserClaim(config.Account, v)
+				if err != nil {
+					i.err = err
+					continue
+				}
+				if uc == nil {
+					i.err = fmt.Errorf("%q jwt not found", v)
+					continue
+				}
+				i.claims = uc
+			}
 			cmd.Println(listEntities("Users", infos, config.Account))
 			return nil
 		},
@@ -241,7 +210,7 @@ func createListUsersCmd() *cobra.Command {
 	return cmd
 }
 
-func listEntities(title string, infos []*EntryInfo, current string) string {
+func listEntities(title string, infos []*listEntry, current string) string {
 	table := tablewriter.CreateTable()
 	table.AddTitle(title)
 	if len(infos) == 0 {
@@ -249,12 +218,12 @@ func listEntities(title string, infos []*EntryInfo, current string) string {
 	} else {
 		table.AddHeaders("Name", "Public Key")
 		for _, v := range infos {
-			n := v.Name
+			n := v.name
 			var p string
-			if v.Err != nil || v.Claims == nil {
-				p = fmt.Sprintf("error loading jwt - %v", v.Err)
+			if v.err != nil || v.claims == nil {
+				p = fmt.Sprintf("error loading jwt - %v", v.err)
 			} else {
-				c := v.Claims.Claims()
+				c := v.claims.Claims()
 				if c != nil {
 					tn := c.Name
 					if n != tn {
diff --git a/cmd/pubkeyparams.go b/cmd/pubkeyparams.go
index 9168ed9..4efe8dd 100644
--- a/cmd/pubkeyparams.go
+++ b/cmd/pubkeyparams.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -18,24 +18,16 @@ package cmd
 import (
 	"fmt"
 
-	"github.com/nats-io/jwt"
-
 	cli "github.com/nats-io/cliprompts/v2"
 	"github.com/nats-io/nkeys"
 	"github.com/nats-io/nsc/cmd/store"
 	"github.com/spf13/cobra"
 )
 
-type PubKeyChoice struct {
-	Label string
-	Key   string
-}
-
 type PubKeyParams struct {
-	flagName      string
-	kind          nkeys.PrefixByte
-	publicKey     string
-	AllowWildcard bool
+	flagName  string
+	kind      nkeys.PrefixByte
+	publicKey string
 }
 
 func (e *PubKeyParams) BindFlags(flagName string, shorthand string, kind nkeys.PrefixByte, cmd *cobra.Command) {
@@ -48,9 +40,6 @@ func (e *PubKeyParams) valid(s string) error {
 	if s == "" {
 		return fmt.Errorf("%s cannot be empty", e.flagName)
 	}
-	if e.AllowWildcard && s == jwt.All {
-		return nil
-	}
 
 	if !store.IsPublicKey(e.kind, s) {
 		return fmt.Errorf("%s is not a valid %q public key", e.publicKey, e.kind.String())
@@ -63,28 +52,8 @@ func (e *PubKeyParams) Valid() error {
 	return e.valid(e.publicKey)
 }
 
-func (e *PubKeyParams) Select(label string, choices ...PubKeyChoice) error {
-	var labels []string
-	for _, c := range choices {
-		labels = append(labels, c.Label)
-	}
-	sel, err := cli.Select(label, "", labels)
-	if err != nil {
-		return err
-	}
-	if sel == -1 {
-		return fmt.Errorf("nothing selected")
-	}
-	e.publicKey = choices[sel].Key
-	return nil
-}
-
 func (e *PubKeyParams) Edit() error {
-	m := fmt.Sprintf("%s public key", e.flagName)
-	if e.AllowWildcard {
-		m = fmt.Sprintf("%s or '*' to match any %s", m, e.flagName)
-	}
-	sv, err := cli.Prompt(m, e.publicKey, cli.Val(e.valid))
+	sv, err := cli.Prompt(fmt.Sprintf("%s public key", e.flagName), e.publicKey, cli.Val(e.valid))
 	if err != nil {
 		return err
 	}
diff --git a/cmd/revoke_clearactivation.go b/cmd/revoke_clearactivation.go
index e698674..31a8204 100644
--- a/cmd/revoke_clearactivation.go
+++ b/cmd/revoke_clearactivation.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -34,7 +34,14 @@ func createClearRevokeActivationCmd() *cobra.Command {
 		Args:         MaxArgs(0),
 		SilenceUsage: true,
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return RunAction(cmd, args, &params)
+			if err := RunAction(cmd, args, &params); err != nil {
+				return err
+			}
+
+			if !QuietMode() {
+				cmd.Printf("Cleared revocation for account %s from export %s\n", params.accountKey.publicKey, params.export.Subject)
+			}
+			return nil
 		},
 	}
 
@@ -64,7 +71,6 @@ type RevokeClearActivationParams struct {
 }
 
 func (p *RevokeClearActivationParams) SetDefaults(ctx ActionCtx) error {
-	p.accountKey.AllowWildcard = true
 	p.AccountContextParams.SetDefaults(ctx)
 	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
 	return nil
@@ -114,18 +120,18 @@ func (p *RevokeClearActivationParams) Load(ctx ActionCtx) error {
 	}
 
 	if len(p.possibleExports) == 0 {
-		return fmt.Errorf("account %q doesn't have %v exports",
-			p.AccountContextParams.Name, kind)
+		return fmt.Errorf("account %q doesn't have %s exports that qualify",
+			p.AccountContextParams.Name, kind.String())
 	}
 
 	return nil
 }
 
 func (p *RevokeClearActivationParams) PostInteractive(ctx ActionCtx) error {
-	var exports []string
+	var choices []string
 	if p.subject == "" {
 		for _, v := range p.possibleExports {
-			exports = append(exports, string(v.Subject))
+			choices = append(choices, string(v.Subject))
 		}
 	}
 	kind := jwt.Stream
@@ -133,7 +139,7 @@ func (p *RevokeClearActivationParams) PostInteractive(ctx ActionCtx) error {
 		kind = jwt.Service
 	}
 
-	i, err := cli.Select(fmt.Sprintf("select %v export", kind), "", exports)
+	i, err := cli.Select(fmt.Sprintf("select %s export", kind.String()), "", choices)
 	if err != nil {
 		return err
 	}
@@ -141,46 +147,33 @@ func (p *RevokeClearActivationParams) PostInteractive(ctx ActionCtx) error {
 	if p.subject == "" {
 		p.subject = string(p.export.Subject)
 	}
-	if len(p.export.Revocations) == 0 {
-		return fmt.Errorf("%v export %s doesn't have revocations", kind, p.export.Name)
-	}
-	accounts, err := ListAccounts(ctx.StoreCtx().Store)
-	if err != nil {
+
+	if err = p.accountKey.Edit(); err != nil {
 		return err
 	}
-	keyToName := make(map[string]string)
-	keyToName["*"] = "* [All Accounts]"
-	for _, a := range accounts {
-		if a.Err == nil {
-			keyToName[a.Claims.Claims().Subject] = a.Name
-		}
-	}
-	var keys []PubKeyChoice
-	for k := range p.export.Revocations {
-		n := keyToName[k]
-		if n == "" {
-			n = "[Unknown Account]"
-		}
-		n = fmt.Sprintf("%s: %s", k, n)
-		keys = append(keys, PubKeyChoice{Key: k, Label: n})
-	}
-	if err = p.accountKey.Select("select account revocation to delete", keys...); err != nil {
+
+	if err := p.SignerParams.Edit(ctx); err != nil {
 		return err
 	}
-	return p.SignerParams.Edit(ctx)
+
+	return nil
 }
 
 func (p *RevokeClearActivationParams) Validate(ctx ActionCtx) error {
+
 	if len(p.possibleExports) == 1 && p.subject == "" {
 		p.subject = string(p.possibleExports[0].Subject)
 	}
+
 	if p.subject == "" {
 		ctx.CurrentCmd().SilenceUsage = false
 		return fmt.Errorf("a subject is required")
 	}
+
 	if err := p.accountKey.Valid(); err != nil {
 		return err
 	}
+
 	sub := jwt.Subject(p.subject)
 	for _, e := range p.possibleExports {
 		if sub.IsContainedIn(e.Subject) {
@@ -191,7 +184,12 @@ func (p *RevokeClearActivationParams) Validate(ctx ActionCtx) error {
 	if p.export == nil {
 		return fmt.Errorf("unable to locate export")
 	}
-	return p.SignerParams.Resolve(ctx)
+
+	if err := p.SignerParams.Resolve(ctx); err != nil {
+		return err
+	}
+
+	return nil
 }
 
 func (p *RevokeClearActivationParams) Run(ctx ActionCtx) (store.Status, error) {
@@ -203,16 +201,7 @@ func (p *RevokeClearActivationParams) Run(ctx ActionCtx) (store.Status, error) {
 	r := store.NewDetailedReport(true)
 	StoreAccountAndUpdateStatus(ctx, token, r)
 	if r.HasNoErrors() {
-		kind := jwt.Stream
-		if p.service {
-			kind = jwt.Service
-		}
-
-		if p.accountKey.publicKey == jwt.All {
-			r.AddOK("deleted %v %s revocation for all accounts", kind, p.export.Name)
-		} else {
-			r.AddOK("deleted %v %s revocation for account %s", kind, p.export.Name, p.accountKey.publicKey)
-		}
+		r.AddOK("cleared export revocation %s for account %s", p.export.Name, p.accountKey.publicKey)
 	}
 	return r, nil
 }
diff --git a/cmd/revoke_listactivation.go b/cmd/revoke_listactivation.go
index 9bec7d3..305306b 100644
--- a/cmd/revoke_listactivation.go
+++ b/cmd/revoke_listactivation.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -36,7 +36,11 @@ func createRevokeListActivationCmd() *cobra.Command {
 		Args:         MaxArgs(0),
 		SilenceUsage: true,
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return RunAction(cmd, args, &params)
+			if err := RunAction(cmd, args, &params); err != nil {
+				return err
+			}
+
+			return nil
 		},
 	}
 
@@ -113,8 +117,8 @@ func (p *RevokeListActivationParams) Load(ctx ActionCtx) error {
 	}
 
 	if len(p.possibleExports) == 0 {
-		return fmt.Errorf("account %q doesn't have %v exports",
-			p.AccountContextParams.Name, kind)
+		return fmt.Errorf("account %q doesn't have %s exports that qualify",
+			p.AccountContextParams.Name, kind.String())
 	}
 
 	return nil
@@ -178,13 +182,6 @@ func (p *RevokeListActivationParams) Run(ctx ActionCtx) (store.Status, error) {
 	if p.export == nil {
 		return nil, fmt.Errorf("unable to locate export")
 	}
-	kind := jwt.Stream
-	if p.service {
-		kind = jwt.Service
-	}
-	if len(p.export.Revocations) == 0 {
-		return nil, fmt.Errorf("%v %s has no revocations", kind, p.export.Name)
-	}
 
 	name := p.export.Name
 	if name == "" {
@@ -192,13 +189,10 @@ func (p *RevokeListActivationParams) Run(ctx ActionCtx) (store.Status, error) {
 	}
 
 	table := tablewriter.CreateTable()
-	table.AddTitle(fmt.Sprintf("Revoked Accounts for %v %s", kind, name))
+	table.AddTitle(fmt.Sprintf("Revoked Accounts for %s", name))
 	table.AddHeaders("Public Key", "Revoke Credentials Before")
 
 	for pubKey, at := range p.export.Revocations {
-		if pubKey == "*" {
-			pubKey = "* [All Accounts]"
-		}
 		t := time.Unix(at, 0)
 		formatted := t.Format(time.RFC1123)
 		table.AddRow(pubKey, formatted)
diff --git a/cmd/revoke_listusers.go b/cmd/revoke_listusers.go
index 849002b..fd480bb 100644
--- a/cmd/revoke_listusers.go
+++ b/cmd/revoke_listusers.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -28,13 +28,16 @@ import (
 func createRevokeListUsersCmd() *cobra.Command {
 	var params RevokeListUserParams
 	cmd := &cobra.Command{
-		Use:          "list-users",
-		Aliases:      []string{"list_users"},
+		Use:          "list_users",
+		Aliases:      []string{"list-users"},
 		Short:        "List users revoked in an account",
 		Args:         MaxArgs(0),
 		SilenceUsage: true,
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return RunAction(cmd, args, &params)
+			if err := RunAction(cmd, args, &params); err != nil {
+				return err
+			}
+			return nil
 		},
 	}
 	params.AccountContextParams.BindFlags(cmd)
@@ -53,7 +56,8 @@ type RevokeListUserParams struct {
 }
 
 func (p *RevokeListUserParams) SetDefaults(ctx ActionCtx) error {
-	return p.AccountContextParams.SetDefaults(ctx)
+	p.AccountContextParams.SetDefaults(ctx)
+	return nil
 }
 
 func (p *RevokeListUserParams) PreInteractive(ctx ActionCtx) error {
@@ -94,21 +98,15 @@ func (p *RevokeListUserParams) Run(ctx ActionCtx) (store.Status, error) {
 		name = p.claim.Subject
 	}
 
-	if len(p.claim.Revocations) == 0 {
-		return nil, fmt.Errorf("account %s does not have revoked users", name)
-	}
-
 	table := tablewriter.CreateTable()
 	table.AddTitle(fmt.Sprintf("Revoked Users for %s", name))
 	table.AddHeaders("Public Key", "Revoke Credentials Before")
 
 	for pubKey, at := range p.claim.Revocations {
-		if pubKey == jwt.All {
-			pubKey = fmt.Sprintf("%s [All Users]", pubKey)
-		}
 		t := time.Unix(at, 0)
 		formatted := t.Format(time.RFC1123)
 		table.AddRow(pubKey, formatted)
 	}
+
 	return nil, Write("--", []byte(table.Render()))
 }
diff --git a/cmd/revokeactivation.go b/cmd/revokeactivation.go
index d37311c..9dffd93 100644
--- a/cmd/revokeactivation.go
+++ b/cmd/revokeactivation.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -36,7 +36,14 @@ func createRevokeActivationCmd() *cobra.Command {
 		Args:         MaxArgs(0),
 		SilenceUsage: true,
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return RunAction(cmd, args, &params)
+			if err := RunAction(cmd, args, &params); err != nil {
+				return err
+			}
+
+			if !QuietMode() {
+				cmd.Printf("Revoked account %s from export %s\n", params.accountKey.publicKey, params.export.Subject)
+			}
+			return nil
 		},
 	}
 
@@ -68,7 +75,6 @@ type RevokeActivationParams struct {
 }
 
 func (p *RevokeActivationParams) SetDefaults(ctx ActionCtx) error {
-	p.accountKey.AllowWildcard = true
 	p.AccountContextParams.SetDefaults(ctx)
 	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
 	return nil
@@ -126,8 +132,38 @@ func (p *RevokeActivationParams) Load(ctx ActionCtx) error {
 	}
 
 	if len(p.possibleExports) == 0 {
-		return fmt.Errorf("account %q doesn't have %v exports",
-			p.AccountContextParams.Name, kind)
+		return fmt.Errorf("account %q doesn't have %s exports that qualify",
+			p.AccountContextParams.Name, kind.String())
+	}
+
+	return nil
+}
+
+func (p *RevokeActivationParams) Validate(ctx ActionCtx) error {
+
+	if len(p.possibleExports) == 1 && p.subject == "" {
+		p.subject = string(p.possibleExports[0].Subject)
+	}
+
+	if p.subject == "" {
+		ctx.CurrentCmd().SilenceUsage = false
+		return fmt.Errorf("a subject is required")
+	}
+
+	if err := p.accountKey.Valid(); err != nil {
+		return err
+	}
+
+	sub := jwt.Subject(p.subject)
+	for _, e := range p.possibleExports {
+		if sub.IsContainedIn(e.Subject) {
+			p.export = e
+			break
+		}
+	}
+
+	if err := p.SignerParams.Resolve(ctx); err != nil {
+		return err
 	}
 
 	return nil
@@ -173,35 +209,6 @@ func (p *RevokeActivationParams) PostInteractive(ctx ActionCtx) error {
 	return p.SignerParams.Edit(ctx)
 }
 
-func (p *RevokeActivationParams) Validate(ctx ActionCtx) error {
-
-	if len(p.possibleExports) == 1 && p.subject == "" {
-		p.subject = string(p.possibleExports[0].Subject)
-	}
-
-	if p.subject == "" {
-		ctx.CurrentCmd().SilenceUsage = false
-		return fmt.Errorf("a subject is required")
-	}
-	if err := p.accountKey.Valid(); err != nil {
-		return err
-	}
-
-	sub := jwt.Subject(p.subject)
-	for _, e := range p.possibleExports {
-		if sub.IsContainedIn(e.Subject) {
-			p.export = e
-			break
-		}
-	}
-
-	if err := p.SignerParams.Resolve(ctx); err != nil {
-		return err
-	}
-
-	return nil
-}
-
 func (p *RevokeActivationParams) Run(ctx ActionCtx) (store.Status, error) {
 	if p.export == nil {
 		return nil, fmt.Errorf("unable to locate export")
@@ -220,15 +227,7 @@ func (p *RevokeActivationParams) Run(ctx ActionCtx) (store.Status, error) {
 	r := store.NewDetailedReport(true)
 	StoreAccountAndUpdateStatus(ctx, token, r)
 	if r.HasNoErrors() {
-		if p.accountKey.publicKey == jwt.All {
-			when := int64(p.at)
-			if when == 0 {
-				when = time.Now().Unix()
-			}
-			r.AddOK("revoked all activations for %q issued before %s", p.export.Name, time.Unix(when, 0).String())
-		} else {
-			r.AddOK("revoked activation %q for account %s", p.export.Name, p.accountKey.publicKey)
-		}
+		r.AddOK("revoked activation %s for account %s", p.export.Name, p.accountKey.publicKey)
 	}
 	return r, nil
 }
diff --git a/cmd/revokeclearuser.go b/cmd/revokeclearuser.go
index 6fbce5e..e783c14 100644
--- a/cmd/revokeclearuser.go
+++ b/cmd/revokeclearuser.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -19,6 +19,8 @@ import (
 	"fmt"
 	"strings"
 
+	cli "github.com/nats-io/cliprompts/v2"
+
 	"github.com/nats-io/jwt/v2"
 	"github.com/nats-io/nkeys"
 	"github.com/nats-io/nsc/cmd/store"
@@ -28,17 +30,24 @@ import (
 func createClearRevokeUserCmd() *cobra.Command {
 	var params ClearRevokeUserParams
 	cmd := &cobra.Command{
-		Use:          "delete-user",
-		Aliases:      []string{"delete_user"},
+		Use:          "delete_user",
+		Aliases:      []string{"delete-user"},
 		Short:        "Remove a user revocation",
 		Args:         MaxArgs(0),
 		SilenceUsage: true,
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return RunAction(cmd, args, &params)
+			if err := RunAction(cmd, args, &params); err != nil {
+				return err
+			}
+
+			if !QuietMode() {
+				cmd.Printf("Cleared revocation of user %s with public key %s\n", params.user, params.userPubKey)
+			}
+			return nil
 		},
 	}
 	cmd.Flags().StringVarP(&params.user, "name", "n", "", "user name")
-	params.userKey.BindFlags("user-public-key", "u", nkeys.PrefixByteUser, cmd)
+	cmd.Flags().StringVarP(&params.userPubKey, "user-public-key", "u", "", "public user key (use when user was generated outside of nsc)")
 	params.AccountContextParams.BindFlags(cmd)
 
 	return cmd
@@ -51,122 +60,129 @@ func init() {
 // ClearRevokeUserParams hold the info necessary to add a user to the revocation list in an account
 type ClearRevokeUserParams struct {
 	AccountContextParams
-	user    string
-	userKey PubKeyParams
-	claim   *jwt.AccountClaims
+	user       string
+	userPubKey string
+	claim      *jwt.AccountClaims
 	SignerParams
 }
 
 func (p *ClearRevokeUserParams) SetDefaults(ctx ActionCtx) error {
-	if p.userKey.publicKey != "" && p.user != "" {
-		return fmt.Errorf("user and user-public-key are mutually exclusive")
-	}
-	p.userKey.AllowWildcard = true
 	p.AccountContextParams.SetDefaults(ctx)
 	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
 	return nil
 }
 
 func (p *ClearRevokeUserParams) PreInteractive(ctx ActionCtx) error {
-	return p.AccountContextParams.Edit(ctx)
-}
-
-func (p *ClearRevokeUserParams) Load(ctx ActionCtx) error {
 	var err error
-	if err = p.AccountContextParams.Validate(ctx); err != nil {
-		return err
-	}
-
-	if p.user != "" {
-		entries, err := ListUsers(ctx.StoreCtx().Store, p.AccountContextParams.Name)
-		if err != nil {
-			return err
-		}
 
-		n := strings.ToLower(p.user)
-		for _, e := range entries {
-			if e.Err == nil && strings.ToLower(e.Name) == n {
-				p.userKey.publicKey = e.Claims.Claims().Subject
-				break
-			}
-		}
-		if p.userKey.publicKey == "" {
-			return fmt.Errorf("user %q not found", p.user)
-		}
-	} else if p.user == "" && p.userKey.publicKey == "" && !InteractiveFlag {
-		uc, err := ctx.StoreCtx().DefaultUserClaim(p.AccountContextParams.Name)
-		if err != nil {
-			return err
-		}
-		p.userKey.publicKey = uc.Subject
+	if err = p.AccountContextParams.Edit(ctx); err != nil {
+		return err
 	}
 
-	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
-	return err
-}
-
-func buildRevokedPublicKeyChoices(accountName string, ctx ActionCtx) ([]PubKeyChoice, error) {
-	var choices []PubKeyChoice
 	st := ctx.StoreCtx().Store
-	accClaim, err := st.ReadAccountClaim(accountName)
+	accClaim, err := st.ReadAccountClaim(p.AccountContextParams.Name)
 	if err != nil || len(accClaim.Revocations) == 0 {
-		return choices, err
+		return err
 	}
-
-	keyToName := map[string]string{}
-	keyToName[jwt.All] = "All Users"
-	infos, err := ListUsers(ctx.StoreCtx().Store, accountName)
+	keyToUserName := map[string]string{}
+	users, err := st.ListEntries(store.Accounts, p.AccountContextParams.Name, store.Users)
 	if err != nil {
-		return nil, err
+		return err
 	}
-	for _, i := range infos {
-		if i.Err == nil {
-			keyToName[i.Claims.Claims().Subject] = i.Name
+	for _, user := range users {
+		if uc, err := st.ReadUserClaim(p.AccountContextParams.Name, user); err == nil {
+			if _, ok := accClaim.Revocations[uc.Subject]; ok {
+				keyToUserName[uc.Subject] = uc.Name
+			}
 		}
 	}
 
-	for key := range accClaim.Revocations {
-		pkc := PubKeyChoice{}
-		pkc.Key = key
-		n := keyToName[key]
-		if n == "" {
-			n = "[Unknown User]"
+	choices := make([]string, 1, len(accClaim.Revocations)+1)
+	choices[0] = "none"
+	for userNkey := range accClaim.Revocations {
+		choice := ""
+		if name, ok := keyToUserName[userNkey]; ok {
+			choice = fmt.Sprintf("%s: %s", userNkey, name)
+		} else {
+			choice = userNkey
 		}
-		pkc.Label = fmt.Sprintf("%s: %s", key, n)
-		choices = append(choices, pkc)
+		choices = append(choices, choice)
+	}
+	if choice, err := cli.Select("Revoked users to remove", "", choices); err != nil {
+		return err
+	} else if choice == 0 {
+		return fmt.Errorf("no Nkey selected")
+	} else {
+		p.userPubKey = strings.Split(choices[choice], ":")[0]
+	}
+	if err := p.SignerParams.Edit(ctx); err != nil {
+		return err
 	}
-	return choices, nil
+	return nil
 }
 
-func (p *ClearRevokeUserParams) PostInteractive(ctx ActionCtx) error {
-	choices, err := buildRevokedPublicKeyChoices(p.AccountContextParams.Name, ctx)
-	if err != nil || len(choices) == 0 {
+func (p *ClearRevokeUserParams) Load(ctx ActionCtx) error {
+	var err error
+
+	if err = p.AccountContextParams.Validate(ctx); err != nil {
 		return err
 	}
-	if err := p.userKey.Select("select revoked user to clear", choices...); err != nil {
+
+	if p.user == "" && p.userPubKey == "" {
+		n := ctx.StoreCtx().DefaultUser(p.AccountContextParams.Name)
+		if n != nil {
+			p.user = *n
+		}
+	}
+	if p.userPubKey == "" && p.user == "" {
+		return fmt.Errorf("user or user-public-key are required")
+	}
+	if p.userPubKey != "" && p.user != "" {
+		return fmt.Errorf("user and user-public-key are mutually exclusive")
+	}
+
+	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
+	if err != nil {
 		return err
 	}
-	return p.SignerParams.Edit(ctx)
+
+	if p.userPubKey != "" {
+		return nil
+	}
+	userClaim, err := ctx.StoreCtx().Store.ReadUserClaim(p.AccountContextParams.Name, p.user)
+	if err != nil {
+		return err
+	}
+
+	if err != nil || userClaim == nil {
+		return fmt.Errorf("user is required")
+	}
+
+	p.userPubKey = userClaim.Subject
+
+	return nil
 }
 
 func (p *ClearRevokeUserParams) Validate(ctx ActionCtx) error {
-	if len(p.claim.Revocations) == 0 {
-		return fmt.Errorf("no user revocations set in account %s", p.AccountContextParams.Name)
-	}
-	if p.userKey.publicKey == "" && p.user == "" {
-		return fmt.Errorf("user or user-public-key is required")
+	if !nkeys.IsValidPublicUserKey(p.userPubKey) {
+		return fmt.Errorf("user-public-key %q is not a valid public user nkey", p.userPubKey)
 	}
-	if err := p.userKey.Valid(); err != nil {
+	if err := p.SignerParams.Resolve(ctx); err != nil {
 		return err
 	}
-	return p.SignerParams.Resolve(ctx)
+
+	return nil
+}
+
+func (p *ClearRevokeUserParams) PostInteractive(ctx ActionCtx) error {
+	return nil
 }
 
 func (p *ClearRevokeUserParams) Run(ctx ActionCtx) (store.Status, error) {
-	if _, ok := p.claim.Revocations[p.userKey.publicKey]; !ok {
-		return nil, fmt.Errorf("user with public key %s is not revoked", p.userKey.publicKey)
+	if _, ok := p.claim.Revocations[p.userPubKey]; !ok {
+		return nil, fmt.Errorf("user with public key %s is not revoked", p.userPubKey)
 	}
-	p.claim.ClearRevocation(p.userKey.publicKey)
+	p.claim.ClearRevocation(p.userPubKey)
 	token, err := p.claim.Encode(p.signerKP)
 	if err != nil {
 		return nil, err
@@ -174,11 +190,7 @@ func (p *ClearRevokeUserParams) Run(ctx ActionCtx) (store.Status, error) {
 	r := store.NewDetailedReport(true)
 	StoreAccountAndUpdateStatus(ctx, token, r)
 	if r.HasNoErrors() {
-		if p.userKey.publicKey == jwt.All {
-			r.AddOK("deleted all user revocation")
-		} else {
-			r.AddOK("deleted user revocation for %q", p.userKey.publicKey)
-		}
+		r.AddOK("cleared user revocation for account %s", p.userPubKey)
 	}
 	return r, nil
 }
diff --git a/cmd/revokeuser.go b/cmd/revokeuser.go
index cd8fcf8..e1e5511 100644
--- a/cmd/revokeuser.go
+++ b/cmd/revokeuser.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -18,7 +18,6 @@ package cmd
 import (
 	"fmt"
 	"strconv"
-	"strings"
 	"time"
 
 	cli "github.com/nats-io/cliprompts/v2"
@@ -31,8 +30,8 @@ import (
 func createRevokeUserCmd() *cobra.Command {
 	var params RevokeUserParams
 	cmd := &cobra.Command{
-		Use:          "add-user",
-		Aliases:      []string{"add_user"},
+		Use:          "add_user",
+		Aliases:      []string{"add-user"},
 		Short:        "Revoke a user",
 		Args:         MaxArgs(0),
 		SilenceUsage: true,
@@ -42,7 +41,8 @@ func createRevokeUserCmd() *cobra.Command {
 	}
 	cmd.Flags().StringVarP(&params.user, "name", "n", "", "user name")
 	cmd.Flags().IntVarP(&params.at, "at", "", 0, "revokes all user credentials created before a Unix timestamp ('0' is treated as now)")
-	params.userKey.BindFlags("user-public-key", "u", nkeys.PrefixByteUser, cmd)
+	cmd.Flags().StringVarP(&params.userPubKey, "user-public-key", "u", "", "public user key (use when user was generated outside of nsc)")
+
 	params.AccountContextParams.BindFlags(cmd)
 
 	return cmd
@@ -55,18 +55,14 @@ func init() {
 // RevokeUserParams hold the info necessary to add a user to the revocation list in an account
 type RevokeUserParams struct {
 	AccountContextParams
-	at      int
-	user    string
-	userKey PubKeyParams
-	claim   *jwt.AccountClaims
+	at         int
+	user       string
+	userPubKey string
+	claim      *jwt.AccountClaims
 	SignerParams
 }
 
 func (p *RevokeUserParams) SetDefaults(ctx ActionCtx) error {
-	if p.userKey.publicKey != "" && p.user != "" {
-		return fmt.Errorf("user and user-public-key are mutually exclusive")
-	}
-	p.userKey.AllowWildcard = true
 	p.AccountContextParams.SetDefaults(ctx)
 	p.SignerParams.SetDefaults(nkeys.PrefixByteOperator, true, ctx)
 	return nil
@@ -81,83 +77,23 @@ func (p *RevokeUserParams) canParse(s string) error {
 }
 
 func (p *RevokeUserParams) PreInteractive(ctx ActionCtx) error {
-	return p.AccountContextParams.Edit(ctx)
-}
-
-func (p *RevokeUserParams) Load(ctx ActionCtx) error {
-	var err error
-	if err = p.AccountContextParams.Validate(ctx); err != nil {
+	if err := p.AccountContextParams.Edit(ctx); err != nil {
 		return err
 	}
-
-	if p.user != "" {
-		entries, err := ListUsers(ctx.StoreCtx().Store, p.AccountContextParams.Name)
-		if err != nil {
-			return err
-		}
-
-		n := strings.ToLower(p.user)
-		for _, e := range entries {
-			if e.Err == nil && strings.ToLower(e.Name) == n {
-				p.userKey.publicKey = e.Claims.Claims().Subject
-				break
-			}
-		}
-		if p.userKey.publicKey == "" {
-			return fmt.Errorf("user %q not found", p.user)
-		}
-	} else if p.user == "" && p.userKey.publicKey == "" && !InteractiveFlag {
-		uc, err := ctx.StoreCtx().DefaultUserClaim(p.AccountContextParams.Name)
-		if err != nil {
-			return err
-		}
-		p.userKey.publicKey = uc.Subject
-	}
-
-	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
-	return err
-}
-
-func buildUserPublicKeyChoices(accountName string, ctx ActionCtx) ([]PubKeyChoice, error) {
-	var choices []PubKeyChoice
-	keyToName := map[string]string{}
-	keyToName[jwt.All] = "All Users"
-	infos, err := ListUsers(ctx.StoreCtx().Store, accountName)
+	byName, err := cli.Confirm("Do you want to revoke a user (known to nsc) by name?", true)
 	if err != nil {
-		return nil, err
-	}
-	for _, i := range infos {
-		if i.Err == nil {
-			pkc := PubKeyChoice{}
-			pkc.Key = i.Claims.Claims().Subject
-			pkc.Label = i.Name
-			choices = append(choices, pkc)
-		}
-	}
-	return choices, nil
-}
-
-func (p *RevokeUserParams) PostInteractive(ctx ActionCtx) error {
-	choices, err := buildUserPublicKeyChoices(p.AccountContextParams.Name, ctx)
-	byName := false
-
-	if len(choices) > 0 {
-		byName, err = cli.Confirm("Revoke a user by name", true)
-		if err != nil {
-			return err
-		}
+		return err
 	}
 	if byName {
-		if err != nil || len(choices) == 0 {
-			return err
-		}
-		if err := p.userKey.Select("Select revoked user to clear", choices...); err != nil {
-			return err
+		if p.user == "" {
+			p.user, err = ctx.StoreCtx().PickUser(p.AccountContextParams.Name)
+			if err != nil {
+				return err
+			}
 		}
-	} else if err := p.userKey.Edit(); err != nil {
+	} else if p.userPubKey, err = cli.Prompt("Enter user public nkey", ""); err != nil {
 		return err
 	}
-
 	if p.at == 0 {
 		at := fmt.Sprintf("%d", p.at)
 		at, err := cli.Prompt("revoke all credentials created before (0 is now)", at, cli.Val(p.canParse))
@@ -176,38 +112,77 @@ func (p *RevokeUserParams) PostInteractive(ctx ActionCtx) error {
 	return nil
 }
 
+func (p *RevokeUserParams) Load(ctx ActionCtx) error {
+	var err error
+
+	if err = p.AccountContextParams.Validate(ctx); err != nil {
+		return err
+	}
+
+	if p.user == "" && p.userPubKey == "" {
+		n := ctx.StoreCtx().DefaultUser(p.AccountContextParams.Name)
+		if n != nil {
+			p.user = *n
+		}
+	}
+	if p.userPubKey == "" && p.user == "" {
+		return fmt.Errorf("user or user-public-key are required")
+	}
+	if p.userPubKey != "" && p.user != "" {
+		return fmt.Errorf("user and user-public-key are mutually exclusive")
+	}
+	p.claim, err = ctx.StoreCtx().Store.ReadAccountClaim(p.AccountContextParams.Name)
+	if err != nil {
+		return err
+	}
+	if p.userPubKey != "" {
+		return nil
+	}
+	userClaim, err := ctx.StoreCtx().Store.ReadUserClaim(p.AccountContextParams.Name, p.user)
+	if err != nil {
+		return err
+	}
+
+	if err != nil || userClaim == nil {
+		return fmt.Errorf("user is required")
+	}
+
+	p.userPubKey = userClaim.Subject
+
+	return nil
+}
+
 func (p *RevokeUserParams) Validate(ctx ActionCtx) error {
-	if p.userKey.publicKey == "" && p.user == "" {
-		return fmt.Errorf("user or user-public-key is required")
+	if !nkeys.IsValidPublicUserKey(p.userPubKey) {
+		return fmt.Errorf("user-public-key %q is not a valid public user nkey", p.userPubKey)
 	}
-	if err := p.userKey.Valid(); err != nil {
+	if err := p.SignerParams.Resolve(ctx); err != nil {
 		return err
 	}
-	return p.SignerParams.Resolve(ctx)
+
+	return nil
+}
+
+func (p *RevokeUserParams) PostInteractive(ctx ActionCtx) error {
+	return nil
 }
 
 func (p *RevokeUserParams) Run(ctx ActionCtx) (store.Status, error) {
 	if p.at == 0 {
-		p.claim.Revoke(p.userKey.publicKey)
+		p.claim.Revoke(p.userPubKey)
 	} else {
-		p.claim.RevokeAt(p.userKey.publicKey, time.Unix(int64(p.at), 0))
+		p.claim.RevokeAt(p.userPubKey, time.Unix(int64(p.at), 0))
 	}
+
 	token, err := p.claim.Encode(p.signerKP)
 	if err != nil {
 		return nil, err
 	}
+
 	r := store.NewDetailedReport(true)
 	StoreAccountAndUpdateStatus(ctx, token, r)
 	if r.HasNoErrors() {
-		if p.userKey.publicKey == jwt.All {
-			when := int64(p.at)
-			if when == 0 {
-				when = time.Now().Unix()
-			}
-			r.AddOK("revoked all users issued before %s", time.Unix(when, 0).String())
-		} else {
-			r.AddOK("revoked user %q", p.userKey.publicKey)
-		}
+		r.AddOK("revoked user %s", p.userPubKey)
 	}
 	return r, nil
 }
diff --git a/cmd/root.go b/cmd/root.go
index e80f375..3b8dcc8 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -118,7 +118,7 @@ var rootCmd = &cobra.Command{
 					return fmt.Errorf("the store %#q is at version %d. To upgrade nsc - type `%s update`",
 						store.GetName(), c.Version, os.Args[0])
 				} else if c.Version == 1 {
-					allowCmdWithJWTV1Store := cmd.Name() == "upgrade-jwt" || cmd.Name() == "env" || cmd.Name() == "help"
+					allowCmdWithJWTV1Store := cmd.Name() == "upgrade-jwt" || cmd.Name() == "env" || cmd.Name() == "help"  || cmd.Name() == "update"
 					if !allowCmdWithJWTV1Store && cmd.Name() == "operator" {
 						for _, v := range addCmd.Commands() {
 							if v == cmd {
diff --git a/cmd/store/store.go b/cmd/store/store.go
index 3d96209..b0738b6 100644
--- a/cmd/store/store.go
+++ b/cmd/store/store.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018-2019 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -841,18 +841,6 @@ func (ctx *Context) DefaultUser(accountName string) *string {
 	return nil
 }
 
-func (ctx *Context) DefaultUserClaim(accountName string) (*jwt.UserClaims, error) {
-	n := ctx.DefaultUser(accountName)
-	if n != nil {
-		userClaim, err := ctx.Store.ReadUserClaim(accountName, *n)
-		if err != nil {
-			return nil, err
-		}
-		return userClaim, nil
-	}
-	return nil, fmt.Errorf("no default user available for account %s", accountName)
-}
-
 func (ctx *Context) PickUser(accountName string) (string, error) {
 	var err error
 	if accountName == "" {


Test patch:
diff --git a/cmd/revoke_clearactivation_test.go b/cmd/revoke_clearactivation_test.go
index 053e246..7a839ea 100644
--- a/cmd/revoke_clearactivation_test.go
+++ b/cmd/revoke_clearactivation_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -86,7 +86,7 @@ func TestClearRevokeActivationInteractive(t *testing.T) {
 		require.False(t, exp.Revocations.IsRevoked(pub, time.Unix(1001, 0)))
 	}
 
-	input = []interface{}{1, true, 0, 0} // second account "B"
+	input = []interface{}{1, true, 0, pub} // second account "B"
 	cmd = createClearRevokeActivationCmd()
 	HoistRootFlags(cmd)
 	_, _, err = ExecuteInteractiveCmd(cmd, input, "-i")
@@ -99,103 +99,3 @@ func TestClearRevokeActivationInteractive(t *testing.T) {
 		require.Len(t, exp.Revocations, 0)
 	}
 }
-
-func TestClearRevokeActivationNoExports(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createClearRevokeActivationCmd())
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "account \"A\" doesn't have exports")
-}
-
-func TestClearRevokeActivationNoServiceExports(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "foo.>", false)
-	_, _, err := ExecuteCmd(createClearRevokeActivationCmd(), "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "account \"A\" doesn't have service exports")
-}
-
-func TestClearRevokeActivationNoStreamExports(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-	_, _, err := ExecuteCmd(createClearRevokeActivationCmd())
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "account \"A\" doesn't have stream exports")
-}
-
-func TestClearRevokeActivationServiceNoExports(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "foo.>", false)
-	_, _, err := ExecuteCmd(createClearRevokeActivationCmd(), "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "account \"A\" doesn't have service exports")
-}
-
-func TestClearRevokeActivationInteractiveServiceNoRevocations(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-	input := []interface{}{true, 0}
-	_, _, err := ExecuteInteractiveCmd(createClearRevokeActivationCmd(), input)
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "service export q doesn't have revocations")
-}
-
-func TestClearRevokeActivationInteractiveStreamNoRevocations(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "q", false)
-	input := []interface{}{false, 0}
-	_, _, err := ExecuteInteractiveCmd(createClearRevokeActivationCmd(), input)
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "stream export q doesn't have revocations")
-}
-
-func TestClearRevokeActivationDefault(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "s", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--target-account", "*")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createClearRevokeActivationCmd(), "--target-account", "*")
-	require.NoError(t, err)
-}
-
-func TestClearRevokeActivationNotFound(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "s", false)
-	ts.AddExport(t, "A", jwt.Stream, "r", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--target-account", "*", "--subject", "s")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createRevokeActivationCmd(), "--target-account", "*", "--subject", "r")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createClearRevokeActivationCmd(), "--target-account", "*", "--subject", "k")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "unable to locate export")
-}
-
-func TestClearRevokeActivationSubjectRequired(t *testing.T) {
-	ts := NewTestStore(t, "test")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "s", false)
-	ts.AddExport(t, "A", jwt.Stream, "r", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--target-account", "*", "--subject", "s")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createClearRevokeActivationCmd(), "--target-account", "*")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "a subject is required")
-}
diff --git a/cmd/revoke_listactivation_test.go b/cmd/revoke_listactivation_test.go
index 7599577..8cae038 100644
--- a/cmd/revoke_listactivation_test.go
+++ b/cmd/revoke_listactivation_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -64,112 +64,5 @@ func TestRevokeListActivation(t *testing.T) {
 	require.True(t, strings.Contains(stdout, pub))
 	require.False(t, strings.Contains(stdout, time.Unix(1001, 0).Format(time.RFC1123)))
 	require.True(t, strings.Contains(stdout, time.Unix(2001, 0).Format(time.RFC1123)))
-}
-
-func TestRevokeListActivationNoAccount(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	_, _, err := ExecuteInteractiveCmd(createRevokeListActivationCmd(), []interface{}{})
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "no accounts defined")
-}
-
-func TestRevokeListActivationNoAccountInteractive(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	_, _, err := ExecuteCmd(createRevokeListActivationCmd())
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "an account is required")
-}
-
-func TestRevokeListActivationNoExport(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeListActivationCmd(), "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "doesn't have exports")
-}
 
-func TestRevokeListActivationNoServiceExport(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "s", false)
-	_, _, err := ExecuteCmd(createRevokeListActivationCmd(), "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "doesn't have service exports")
-}
-
-func TestRevokeListActivationNoStreamExport(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "s", false)
-	_, _, err := ExecuteCmd(createRevokeListActivationCmd())
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "doesn't have stream exports")
-}
-
-func TestRevokeListActivationDefaultExport(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "s", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--service", "--target-account", "*")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createRevokeListActivationCmd(), "--service")
-	require.NoError(t, err)
-}
-
-func TestRevokeListActivationNoDefaultExport(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "s", false)
-	ts.AddExport(t, "A", jwt.Service, "r", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--service", "--target-account", "*", "--subject", "s")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createRevokeActivationCmd(), "--service", "--target-account", "*", "--subject", "r")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createRevokeListActivationCmd(), "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "a subject is required")
-}
-
-func TestRevokeListActivationExportNotFound(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "s", false)
-	ts.AddExport(t, "A", jwt.Service, "r", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--service", "--target-account", "*", "--subject", "s")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createRevokeActivationCmd(), "--service", "--target-account", "*", "--subject", "r")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createRevokeListActivationCmd(), "--service", "--subject", "x")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "unable to locate export")
-}
-
-func TestRevokeListActivationHasNoRevocations(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "s", false)
-	_, _, err := ExecuteCmd(createRevokeListActivationCmd(), "--service", "--subject", "s")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "service s has no revocations")
-}
-
-func TestRevokeListActivationInteractive(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "s", false)
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "--service", "--subject", "s", "--target-account", "*")
-	require.NoError(t, err)
-	args := []interface{}{true, 0}
-	_, _, err = ExecuteInteractiveCmd(createRevokeListActivationCmd(), args)
-	require.NoError(t, err)
 }
diff --git a/cmd/revoke_listusers_test.go b/cmd/revoke_listusers_test.go
index ecd7759..efba6d1 100644
--- a/cmd/revoke_listusers_test.go
+++ b/cmd/revoke_listusers_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -20,8 +20,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/nats-io/jwt"
-
 	"github.com/stretchr/testify/require"
 )
 
@@ -53,36 +51,3 @@ func TestRevokeListUsers(t *testing.T) {
 	require.True(t, strings.Contains(stdout, u.Subject))
 	require.True(t, strings.Contains(stdout, time.Unix(2001, 0).Format(time.RFC1123)))
 }
-
-func TestRevokeListUsersNoAccount(t *testing.T) {
-	ts := NewTestStore(t, "revoke_clear_user")
-	defer ts.Done(t)
-	_, _, err := ExecuteInteractiveCmd(createRevokeListUsersCmd(), []interface{}{})
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "no accounts defined")
-}
-
-func TestRevokeListUsersNoRevocations(t *testing.T) {
-	ts := NewTestStore(t, "revoke_clear_user")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeListUsersCmd())
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "does not have revoked users")
-}
-
-func TestRevokeListUsersAllUsers(t *testing.T) {
-	ts := NewTestStore(t, "revoke_clear_user")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*")
-	require.NoError(t, err)
-
-	ac, err := ts.Store.ReadAccountClaim("A")
-	require.NoError(t, err)
-	require.Contains(t, ac.Revocations, jwt.All)
-
-	stdout, _, err := ExecuteCmd(createRevokeListUsersCmd())
-	require.NoError(t, err)
-	require.Contains(t, stdout, "* [All Users]")
-}
diff --git a/cmd/revokeactivation_test.go b/cmd/revokeactivation_test.go
index 9e1989b..5cfdbc8 100644
--- a/cmd/revokeactivation_test.go
+++ b/cmd/revokeactivation_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -157,89 +157,3 @@ func TestRevokeActivationForServiceInteractive(t *testing.T) {
 		require.False(t, exp.Revocations.IsRevoked(pub, time.Unix(1001, 0)))
 	}
 }
-
-func TestRevokeActivationNoExports(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "doesn't have exports")
-}
-
-func TestRevokeActivationServiceNoExports(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "doesn't have stream exports")
-}
-
-func TestRevokeActivationStreamNoExports(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Stream, "q", false)
-
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "doesn't have service exports")
-}
-
-func TestRevokeActivationSubjectRequired(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-	ts.AddExport(t, "A", jwt.Service, "qq", false)
-
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "a subject is required")
-}
-
-func TestRevokeActivationExportNotFound(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service", "--subject", "foo")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "unable to locate export")
-}
-
-func TestRevokeActivationDefaultSubject(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service")
-	require.NoError(t, err)
-}
-
-func TestRevokeActivationAll(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-
-	_, _, err := ExecuteCmd(createRevokeActivationCmd(), "-t", "*", "--service", "--subject", "q")
-	require.NoError(t, err)
-}
-
-func TestRevokeActivationBadInteractiveAt(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddExport(t, "A", jwt.Service, "q", false)
-
-	input := []interface{}{true, 0, "*", "hello"}
-	_, _, err := ExecuteInteractiveCmd(createRevokeActivationCmd(), input)
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "hello is invalid:")
-}
diff --git a/cmd/revokeclearuser_test.go b/cmd/revokeclearuser_test.go
index 8ce82e5..5824989 100644
--- a/cmd/revokeclearuser_test.go
+++ b/cmd/revokeclearuser_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -18,8 +18,6 @@ package cmd
 import (
 	"testing"
 
-	cli "github.com/nats-io/cliprompts/v2"
-
 	"github.com/stretchr/testify/require"
 )
 
@@ -77,11 +75,9 @@ func TestRevokeClearUserInteractive(t *testing.T) {
 	require.NoError(t, err)
 	require.Contains(t, ac.Revocations, u.Subject)
 
-	// first account and first user
-	input := []interface{}{0, 0}
+	input := []interface{}{0, 1}
 	cmd := createClearRevokeUserCmd()
 	HoistRootFlags(cmd)
-	cli.LogFn = t.Log
 	_, _, err = ExecuteInteractiveCmd(cmd, input, "-i")
 	require.NoError(t, err)
 
@@ -89,59 +85,3 @@ func TestRevokeClearUserInteractive(t *testing.T) {
 	require.NoError(t, err)
 	require.Len(t, ac.Revocations, 0)
 }
-
-func TestClearRevokeUserUserAndKey(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createClearRevokeUserCmd(), "--name", "a", "--user-public-key", "UAUGJSHSTZY4ESHTL32CYYQNGT6MHXDQY6APMFMVRXWZN76RHE2IRN5O")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "user and user-public-key are mutually exclusive")
-}
-
-func TestClearRevokeUserNotFound(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddUser(t, "A", "U")
-	_, _, err := ExecuteCmd(createClearRevokeUserCmd(), "--name", "uu")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "not found")
-}
-
-func TestClearRevokeDefaultUser(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddUser(t, "A", "U")
-	_, _, err := ExecuteCmd(createRevokeUserCmd())
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createClearRevokeUserCmd())
-	require.NoError(t, err)
-}
-
-func TestClearRevokeRevocationNotFound(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddUser(t, "A", "U")
-	_, _, err := ExecuteCmd(createRevokeUserCmd())
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createClearRevokeUserCmd(), "-u", "*")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "user with public key * is not revoked")
-}
-
-func TestClearRevokeAllUsers(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*")
-	require.NoError(t, err)
-	_, _, err = ExecuteCmd(createClearRevokeUserCmd(), "-u", "*")
-	require.NoError(t, err)
-
-	ac, err := ts.Store.ReadAccountClaim("A")
-	require.NoError(t, err)
-	require.Empty(t, ac.Revocations)
-}
diff --git a/cmd/revokeuser_test.go b/cmd/revokeuser_test.go
index 0b89b1e..9a060d5 100644
--- a/cmd/revokeuser_test.go
+++ b/cmd/revokeuser_test.go
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018-2020 The NATS Authors
+ * Copyright 2018 The NATS Authors
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -20,8 +20,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/nats-io/jwt"
-
 	"github.com/stretchr/testify/require"
 )
 
@@ -196,87 +194,3 @@ func TestRevokeUserByNkey(t *testing.T) {
 	require.NoError(t, err)
 	require.False(t, ac.IsClaimRevoked(u))
 }
-
-func TestRevokeUserNameKey(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "a", "--user-public-key", "UAUGJSHSTZY4ESHTL32CYYQNGT6MHXDQY6APMFMVRXWZN76RHE2IRN5O")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "user and user-public-key are mutually exclusive")
-}
-
-func TestRevokeUserNameNotFound(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddUser(t, "A", "U")
-	_, _, err := ExecuteCmd(createRevokeUserCmd(), "--name", "a")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "not found")
-
-	_, _, err = ExecuteCmd(createRevokeUserCmd(), "--name", "U")
-	require.NoError(t, err)
-	ac, err := ts.Store.ReadAccountClaim("A")
-	require.NoError(t, err)
-	upk := ts.GetUserPublicKey(t, "A", "U")
-	require.NotEmpty(t, upk)
-	require.Contains(t, ac.Revocations, upk)
-}
-
-func TestRevokeDefaultUser(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddUser(t, "A", "U")
-	_, _, err := ExecuteCmd(createRevokeUserCmd())
-	require.NoError(t, err)
-
-	upk := ts.GetUserPublicKey(t, "A", "U")
-	ac, err := ts.Store.ReadAccountClaim("A")
-	require.NoError(t, err)
-	_, ok := ac.Revocations[upk]
-	require.True(t, ok)
-}
-
-func TestRevokeUserRequired(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	ts.AddUser(t, "A", "U")
-	ts.AddUser(t, "A", "Y")
-	_, _, err := ExecuteCmd(createRevokeUserCmd())
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "no default user available")
-}
-
-func TestRevokeAllUsers(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*")
-	require.NoError(t, err)
-
-	ac, err := ts.Store.ReadAccountClaim("A")
-	require.NoError(t, err)
-	require.Contains(t, ac.Revocations, jwt.All)
-}
-
-func TestRevokeBadUnixTime(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	_, _, err := ExecuteCmd(createRevokeUserCmd(), "-u", "*", "--at", "hello")
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "invalid argument")
-}
-
-func TestRevokeBadUnixTimeInteractive(t *testing.T) {
-	ts := NewTestStore(t, "O")
-	defer ts.Done(t)
-	ts.AddAccount(t, "A")
-	input := []interface{}{"*", "hello"}
-	_, _, err := ExecuteInteractiveCmd(createRevokeUserCmd(), input)
-	require.Error(t, err)
-	require.Contains(t, err.Error(), "hello is invalid:")
-}