Skip to content

Commit

Permalink
Add tenants open and apis open [CLI-101] [CLI-133] (#253)
Browse files Browse the repository at this point in the history
* Add `tenants open` and `apis open`

* Update internal/cli/tenants.go

Co-authored-by: Jorge L. Fatta <jorge.fatta@auth0.com>

* Address review feedback

* Remove excess whitespace

* Replace spaces with a tab

Co-authored-by: Jorge L. Fatta <jorge.fatta@auth0.com>
  • Loading branch information
Widcket and jfatta authored Apr 19, 2021
1 parent cd70733 commit 6c564a6
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 35 deletions.
73 changes: 67 additions & 6 deletions internal/cli/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/auth0/auth0-cli/internal/ansi"
"github.com/auth0/auth0-cli/internal/prompt"
"github.com/spf13/cobra"
"gopkg.in/auth0.v5"
"gopkg.in/auth0.v5/management"
)

Expand Down Expand Up @@ -53,6 +54,7 @@ func apisCmd(cli *cli) *cobra.Command {
cmd.AddCommand(showApiCmd(cli))
cmd.AddCommand(updateApiCmd(cli))
cmd.AddCommand(deleteApiCmd(cli))
cmd.AddCommand(openApiCmd(cli))
cmd.AddCommand(scopesCmd(cli))

return cmd
Expand Down Expand Up @@ -111,7 +113,7 @@ func showApiCmd(cli *cli) *cobra.Command {
Short: "Show an API",
Long: "Show an API.",
Example: `auth0 apis show
auth0 apis show <id>`,
auth0 apis show <id|audience>`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
Expand Down Expand Up @@ -214,8 +216,8 @@ func updateApiCmd(cli *cli) *cobra.Command {
Short: "Update an API",
Long: "Update an API.",
Example: `auth0 apis update
auth0 apis update <id>
auth0 apis update <id> --name myapi`,
auth0 apis update <id|audience>
auth0 apis update <id|audience> --name myapi`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
Expand Down Expand Up @@ -289,7 +291,7 @@ func deleteApiCmd(cli *cli) *cobra.Command {
Short: "Delete an API",
Long: "Delete an API.",
Example: `auth0 apis delete
auth0 apis delete <id>`,
auth0 apis delete <id|audience>`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
Expand Down Expand Up @@ -324,6 +326,58 @@ auth0 apis delete <id>`,
return cmd
}

func openApiCmd(cli *cli) *cobra.Command {
var inputs struct {
ID string
}

cmd := &cobra.Command{
Use: "open",
Args: cobra.MaximumNArgs(1),
Short: "Open API settings page in Auth0 Manage",
Long: "Open API settings page in Auth0 Manage.",
Example: `auth0 apis open
auth0 apis open <id|audience>`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := apiID.Pick(cmd, &inputs.ID, cli.apiPickerOptions)
if err != nil {
return err
}
} else {
inputs.ID = args[0]
}

// Heuristics to determine if this a valid ID, or an audience value
// Audiences are usually URLs, but not necessarily. Whereas IDs have a length of 24
// So here if the value is not a URL, we then check if has the length of an ID
// If the length check fails, we know it's a non-URL audience value
// This will fail for non-URL audience values with the same length as the ID
// But it should cover the vast majority of users
if _, err := url.ParseRequestURI(inputs.ID); err == nil || len(inputs.ID) != 24 {
if err := ansi.Waiting(func() error {
api, err := cli.api.ResourceServer.Read(url.PathEscape(inputs.ID))
if err != nil {
return err
}
inputs.ID = auth0.StringValue(api.ID)
return nil
}); err != nil {
return fmt.Errorf("An unexpected error occurred while trying to get the API Id for '%s': %w", inputs.ID, err)
}
}

openManageURL(cli, cli.config.DefaultTenant, formatApiSettingsPath(inputs.ID))
return nil
},
}

return cmd
}

func listScopesCmd(cli *cli) *cobra.Command {
var inputs struct {
ID string
Expand All @@ -336,7 +390,7 @@ func listScopesCmd(cli *cli) *cobra.Command {
Short: "List the scopes of an API",
Long: "List the scopes of an API.",
Example: `auth0 apis scopes list
auth0 apis scopes ls <id>`,
auth0 apis scopes ls <id|audience>`,
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
Expand All @@ -354,7 +408,7 @@ auth0 apis scopes ls <id>`,

if err := ansi.Waiting(func() error {
var err error
api, err = cli.api.ResourceServer.Read(inputs.ID)
api, err = cli.api.ResourceServer.Read(url.PathEscape(inputs.ID))
return err
}); err != nil {
return fmt.Errorf("An unexpected error occurred while getting scopes for an API with Id '%s': %w", inputs.ID, err)
Expand All @@ -368,6 +422,13 @@ auth0 apis scopes ls <id>`,
return cmd
}

func formatApiSettingsPath(id string) string {
if len(id) == 0 {
return ""
}
return fmt.Sprintf("apis/%s/settings", id)
}

func apiScopesFor(scopes []string) []*management.ResourceServerScope {
models := []*management.ResourceServerScope{}

Expand Down
34 changes: 5 additions & 29 deletions internal/cli/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/auth0/auth0-cli/internal/ansi"
"github.com/auth0/auth0-cli/internal/auth0"
"github.com/auth0/auth0-cli/internal/open"
"github.com/auth0/auth0-cli/internal/prompt"
"github.com/spf13/cobra"
"gopkg.in/auth0.v5/management"
Expand All @@ -22,7 +21,6 @@ const (
appTypeRegularWeb = "regular_web"
appTypeNonInteractive = "non_interactive"
appDefaultURL = "http://localhost:3000"
manageDomain = "https://manage.auth0.com"
)

var (
Expand Down Expand Up @@ -669,7 +667,7 @@ func openAppCmd(cli *cli) *cobra.Command {
Args: cobra.MaximumNArgs(1),
Short: "Open application settings page in Auth0 Manage",
Long: "Open application settings page in Auth0 Manage.",
Example: `auth0 apps open <id>`,
Example: "auth0 apps open <id>",
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
Expand All @@ -683,41 +681,19 @@ func openAppCmd(cli *cli) *cobra.Command {
inputs.ID = args[0]
}

manageUrl := formatManageURL(cli.config, inputs.ID)
if manageUrl == "" {
cli.renderer.Warnf("Unable to format the correct URL, please ensure you have run auth0 login and try again.")
return nil
}
if err := open.URL(manageUrl); err != nil {
cli.renderer.Warnf("Couldn't open the URL, please do it manually: %s.", manageUrl)
}
openManageURL(cli, cli.config.DefaultTenant, formatAppSettingsPath(inputs.ID))
return nil
},
}

return cmd
}

func formatManageURL(cfg config, id string) string {
if cfg.DefaultTenant == "" || id == "" {
return ""
}
// ex: dev-tti06f6y.us.auth0.com
s := strings.Split(cfg.DefaultTenant, ".")
if len(s) < 4 {
func formatAppSettingsPath(id string) string {
if len(id) == 0 {
return ""
}
region := s[len(s)-3]
tenant := cfg.Tenants[cfg.DefaultTenant].Name
if tenant == "" {
return ""
}
return fmt.Sprintf("%s/dashboard/%s/%s/applications/%s/settings",
manageDomain,
region,
tenant,
id,
)
return fmt.Sprintf("applications/%s/settings", id)
}

func apiTypeFor(v string) string {
Expand Down
70 changes: 70 additions & 0 deletions internal/cli/tenants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import (
"github.com/spf13/cobra"
)

var (
tenantDomain = Argument{
Name: "Tenant",
Help: "Tenant to select",
}
)

func tenantsCmd(cli *cli) *cobra.Command {
cmd := &cobra.Command{
Use: "tenants",
Expand All @@ -17,6 +24,7 @@ func tenantsCmd(cli *cli) *cobra.Command {
cmd.SetUsageTemplate(resourceUsageTemplate())
cmd.AddCommand(useTenantCmd(cli))
cmd.AddCommand(listTenantCmd(cli))
cmd.AddCommand(openTenantCmd(cli))
return cmd
}

Expand Down Expand Up @@ -93,3 +101,65 @@ func useTenantCmd(cli *cli) *cobra.Command {

return cmd
}

func openTenantCmd(cli *cli) *cobra.Command {
var inputs struct {
Domain string
}

cmd := &cobra.Command{
Use: "open",
Args: cobra.MaximumNArgs(1),
Short: "Open tenant settings page in Auth0 Manage",
Long: "Open tenant settings page in Auth0 Manage.",
Example: "auth0 tenants open <tenant>",
PreRun: func(cmd *cobra.Command, args []string) {
prepareInteractivity(cmd)
},
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
err := tenantDomain.Pick(cmd, &inputs.Domain, cli.tenantPickerOptions)
if err != nil {
return err
}
} else {
inputs.Domain = args[0]

if _, ok := cli.config.Tenants[inputs.Domain]; !ok {
return fmt.Errorf("Unable to find tenant %s; run 'auth0 login' to configure a new tenant", inputs.Domain)
}
}

openManageURL(cli, inputs.Domain, "tenant/general")
return nil
},
}

return cmd
}

func (c *cli) tenantPickerOptions() (pickerOptions, error) {
tens, err := c.listTenants()
if err != nil {
return nil, fmt.Errorf("Unable to load tenants due to an unexpected error: %w", err)
}

var priorityOpts, opts pickerOptions

for _, t := range tens {
opt := pickerOption{value: t.Domain, label: t.Domain}

// check if this is currently the default tenant.
if t.Domain == c.config.DefaultTenant {
priorityOpts = append(priorityOpts, opt)
} else {
opts = append(opts, opt)
}
}

if len(opts)+len(priorityOpts) == 0 {
return nil, errNoApps
}

return append(priorityOpts, opts...), nil
}
42 changes: 42 additions & 0 deletions internal/cli/utils_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"crypto/rand"
"fmt"
"strings"

"encoding/base64"
"encoding/json"
Expand All @@ -24,6 +25,7 @@ const (
cliLoginTestingCallbackURL string = "http://localhost:8484"
cliLoginTestingInitiateLoginURI string = "https://cli.auth0.com"
cliLoginTestingStateSize int = 64
manageURL string = "https://manage.auth0.com"
)

var (
Expand Down Expand Up @@ -272,3 +274,43 @@ func containsStr(s []interface{}, u string) bool {
}
return false
}

func openManageURL(cli *cli, tenant string, path string) {
manageTenantURL := formatManageTenantURL(tenant, cli.config)
if len(manageTenantURL) == 0 || len(path) == 0 {
cli.renderer.Warnf("Unable to format the correct URL, please ensure you have run 'auth0 login' and try again.")
return
}
if err := open.URL(fmt.Sprintf("%s%s", manageTenantURL, path)); err != nil {
cli.renderer.Warnf("Couldn't open the URL, please do it manually: %s.", manageTenantURL)
}
}

func formatManageTenantURL(tenant string, cfg config) string {
if len(tenant) == 0 {
return ""
}
// ex: dev-tti06f6y.us.auth0.com
s := strings.Split(tenant, ".")

if len(s) < 3 {
return ""
}

var region string
if len(s) == 3 { // It's a PUS1 tenant, ex: dev-tti06f6y.auth0.com
region = "us"
} else {
region = s[len(s)-3]
}

tenantName := cfg.Tenants[tenant].Name
if len(tenantName) == 0 {
return ""
}
return fmt.Sprintf("%s/dashboard/%s/%s/",
manageURL,
region,
tenantName,
)
}

0 comments on commit 6c564a6

Please sign in to comment.