Skip to content

Commit

Permalink
CLI-80: users blocks commands (#219)
Browse files Browse the repository at this point in the history
* CLI-80: user-blocks commands with user_id
  • Loading branch information
mhsu-auth0 authored Apr 23, 2021
1 parent e5b542e commit 7263e5a
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 1 deletion.
2 changes: 1 addition & 1 deletion internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var requiredScopes = []string{
"create:clients", "delete:clients", "read:clients", "update:clients",
"create:resource_servers", "delete:resource_servers", "read:resource_servers", "update:resource_servers",
"create:rules", "delete:rules", "read:rules", "update:rules",
"read:client_keys", "read:logs",
"read:client_keys", "read:logs", "read:users", "update:users",
}

// RequiredScopes returns the scopes used for login.
Expand Down
2 changes: 2 additions & 0 deletions internal/auth0/auth0.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type API struct {
Log LogAPI
ResourceServer ResourceServerAPI
Rule RuleAPI
User UserAPI
}

func NewAPI(m *management.Management) *API {
Expand All @@ -28,6 +29,7 @@ func NewAPI(m *management.Management) *API {
Log: m.Log,
ResourceServer: m.ResourceServer,
Rule: m.Rule,
User: m.User,
}
}

Expand Down
14 changes: 14 additions & 0 deletions internal/auth0/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:generate mockgen -source=user.go -destination=user_mock.go -package=auth0

package auth0

import "gopkg.in/auth0.v5/management"

type UserAPI interface {
// Retrieves a list of blocked IP addresses of a particular user.
Blocks(id string, opts ...management.RequestOption) ([]*management.UserBlock, error)

// Unblock a user that was blocked due to an excessive amount of incorrectly
// provided credentials.
Unblock(id string, opts ...management.RequestOption) error
}
1 change: 1 addition & 0 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ func Execute() {
// so add new commands in a place that reflect its relevance or relation with other commands:
rootCmd.AddCommand(loginCmd(cli))
rootCmd.AddCommand(tenantsCmd(cli))
rootCmd.AddCommand(usersCmd(cli))
rootCmd.AddCommand(appsCmd(cli))
rootCmd.AddCommand(rulesCmd(cli))
rootCmd.AddCommand(apisCmd(cli))
Expand Down
124 changes: 124 additions & 0 deletions internal/cli/users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package cli

import (
"fmt"

"github.com/auth0/auth0-cli/internal/ansi"
"github.com/spf13/cobra"
"gopkg.in/auth0.v5/management"
)

var (
userID = Argument{
Name: "User ID",
Help: "Id of the user.",
}
)

func usersCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "users",
Short: "Manage resources for users",
}

cmd.SetUsageTemplate(resourceUsageTemplate())
cmd.AddCommand(userBlocksCmd(cli))
cmd.AddCommand(deleteUserBlocksCmd(cli))
return cmd
}

func userBlocksCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "blocks",
Short: "Manage brute-force protection user blocks.",
}

cmd.SetUsageTemplate(resourceUsageTemplate())
cmd.AddCommand(listUserBlocksCmd(cli))
return cmd
}

func listUserBlocksCmd(cli *cli) *cobra.Command {
var inputs struct {
userID string
}

cmd := &cobra.Command{
Use: "list",
Args: cobra.MaximumNArgs(1),
Short: "List brute-force protection blocks for a given user",
Long: `List brute-force protection blocks for a given user:
auth0 users blocks list <user-id>
`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
if err := userID.Ask(cmd, &inputs.userID); err != nil {
return err
}
} else {
inputs.userID = args[0]
}

var userBlocks []*management.UserBlock

err := ansi.Waiting(func() error {
var err error
userBlocks, err = cli.api.User.Blocks(inputs.userID)
return err
})

if err != nil {
return fmt.Errorf("Unable to load user blocks %v, error: %w", inputs.userID, err)
}

cli.renderer.UserBlocksList(userBlocks)
return nil
},
}

return cmd
}

func deleteUserBlocksCmd(cli *cli) *cobra.Command {
var inputs struct {
userID string
}

cmd := &cobra.Command{
Use: "unblock",
Args: cobra.MaximumNArgs(1),
Short: "Delete brute-force protection blocks for a given user",
Long: `Delete brute-force protection blocks for a given user:
auth0 users unblock <user-id>
`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
if err := userID.Ask(cmd, &inputs.userID); err != nil {
return err
}
} else {
inputs.userID = args[0]
}

err := ansi.Spinner("Deleting blocks for user...", func() error {
return cli.api.User.Unblock(inputs.userID)
})

if err != nil {
return err
}

return nil
},
}

return cmd
}
48 changes: 48 additions & 0 deletions internal/display/user_blocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package display

import (
"gopkg.in/auth0.v5/management"
)

type userBlockView struct {
Identifier string
IP string
}

func (v *userBlockView) AsTableHeader() []string {
return []string{"Identifier", "IP"}
}

func (v *userBlockView) AsTableRow() []string {
return []string{v.Identifier, v.IP}
}

func (v *userBlockView) KeyValues() [][]string {
return [][]string{
[]string{"Identifier", v.Identifier},
[]string{"IP", v.IP},
}
}

func (r *Renderer) UserBlocksList(userBlocks []*management.UserBlock) {
resource := "user blocks"

r.Heading(resource)

if len(userBlocks) == 0 {
r.EmptyState(resource)
return
}

var res []View

for _, userBlock := range userBlocks {
res = append(res, &userBlockView{
Identifier: *userBlock.Identifier,
IP: *userBlock.IP,
})
}

r.Results(res)

}

0 comments on commit 7263e5a

Please sign in to comment.