Skip to content

Commit 4aa05ae

Browse files
authored
refactor: use some colors in CLI output (#962)
1 parent 440a3a3 commit 4aa05ae

9 files changed

Lines changed: 583 additions & 348 deletions

File tree

‎.gitignore‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ config.certify.yml
5353
/.deepsec
5454

5555
# jetbrains
56-
/.idea/
56+
/.idea/

‎cmd/tinyauth/config.go‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package main
22

33
import (
4-
"encoding/json"
54
"fmt"
5+
"strings"
66

77
"github.com/tinyauthapp/paerser/cli"
88
"github.com/tinyauthapp/tinyauth/internal/model"
@@ -11,15 +11,21 @@ import (
1111
func configCmd(tconfig *model.Config, loaders []cli.ResourceLoader) *cli.Command {
1212
return &cli.Command{
1313
Name: "config",
14-
Description: "Print the configuration of Tinyauth",
14+
Description: "Dump the current configuration in YAML format, useful for debugging",
1515
Configuration: tconfig,
1616
Resources: loaders,
1717
Run: func(_ []string) error {
18-
jsonBytes, err := json.MarshalIndent(tconfig, "", " ")
18+
buf := strings.Builder{}
19+
20+
fmt.Fprint(&buf, "Your current configuration in YAML is:\n\n")
21+
22+
err := renderYamlToBuf(&buf, tconfig)
23+
1924
if err != nil {
20-
return fmt.Errorf("failed to marshal configuration: %w", err)
25+
return fmt.Errorf("failed to render yaml config: %w", err)
2126
}
22-
fmt.Println(string(jsonBytes))
27+
28+
fmt.Print(buf.String())
2329
return nil
2430
},
2531
}

‎cmd/tinyauth/create_oidc_client.go‎

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import (
77
"strings"
88

99
"github.com/google/uuid"
10-
"github.com/tinyauthapp/tinyauth/internal/utils"
1110
"github.com/tinyauthapp/paerser/cli"
11+
"github.com/tinyauthapp/tinyauth/internal/model"
12+
"github.com/tinyauthapp/tinyauth/internal/utils"
1213
)
1314

1415
func createOidcClientCmd() *cli.Command {
@@ -31,40 +32,84 @@ func createOidcClientCmd() *cli.Command {
3132
return errors.New("client name can only contain alphanumeric characters and hyphens")
3233
}
3334

34-
uuid := uuid.New()
35-
clientId := uuid.String()
35+
u := uuid.New()
36+
clientId := u.String()
3637
clientSecret := "ta-" + utils.GenerateString(61)
3738

3839
uclientName := strings.ToUpper(clientName)
3940
lclientName := strings.ToLower(clientName)
4041

41-
builder := strings.Builder{}
42+
buf := strings.Builder{}
4243

4344
// header
44-
fmt.Fprintf(&builder, "Created credentials for client %s\n\n", clientName)
45+
fmt.Fprintf(&buf, "Created '%s' OIDC client.\n\n", clientName)
4546

4647
// credentials
47-
fmt.Fprintf(&builder, "Client Name: %s\n", clientName)
48-
fmt.Fprintf(&builder, "Client ID: %s\n", clientId)
49-
fmt.Fprintf(&builder, "Client Secret: %s\n\n", clientSecret)
48+
fmt.Fprintf(&buf, "Credentials:\n\n")
49+
fmt.Fprintf(&buf, "Client Name: %s\n", clientName)
50+
fmt.Fprintf(&buf, "Client ID: %s\n", clientId)
51+
fmt.Fprintf(&buf, "Client Secret: %s\n\n", clientSecret)
5052

51-
// env variables
52-
fmt.Fprint(&builder, "Environment variables:\n\n")
53-
fmt.Fprintf(&builder, "TINYAUTH_OIDC_CLIENTS_%s_CLIENTID=%s\n", uclientName, clientId)
54-
fmt.Fprintf(&builder, "TINYAUTH_OIDC_CLIENTS_%s_CLIENTSECRET=%s\n", uclientName, clientSecret)
55-
fmt.Fprintf(&builder, "TINYAUTH_OIDC_CLIENTS_%s_NAME=%s\n\n", uclientName, utils.Capitalize(lclientName))
53+
// end variables
54+
fmt.Fprintf(&buf, "Environment variables:\n\n")
55+
renderToBuf(&buf, []kv{
56+
{
57+
k: fmt.Sprintf("TINYAUTH_OIDC_CLIENTS_%s_CLIENTID", uclientName),
58+
v: clientId,
59+
},
60+
{
61+
k: fmt.Sprintf("TINYAUTH_OIDC_CLIENTS_%s_CLIENTSECRET", uclientName),
62+
v: clientSecret,
63+
},
64+
{
65+
k: fmt.Sprintf("TINYAUTH_OIDC_CLIENTS_%s_NAME", uclientName),
66+
v: utils.Capitalize(lclientName),
67+
},
68+
}, "=")
69+
fmt.Fprintf(&buf, "\n")
5670

5771
// cli flags
58-
fmt.Fprint(&builder, "CLI flags:\n\n")
59-
fmt.Fprintf(&builder, "--oidc.clients.%s.clientid=%s\n", lclientName, clientId)
60-
fmt.Fprintf(&builder, "--oidc.clients.%s.clientsecret=%s\n", lclientName, clientSecret)
61-
fmt.Fprintf(&builder, "--oidc.clients.%s.name=%s\n\n", lclientName, utils.Capitalize(lclientName))
72+
fmt.Fprintf(&buf, "CLI flags:\n\n")
73+
renderToBuf(&buf, []kv{
74+
{
75+
k: fmt.Sprintf("--oidc.clients.%s.clientid", lclientName),
76+
v: clientId,
77+
},
78+
{
79+
k: fmt.Sprintf("--oidc.clients.%s.clientsecret", lclientName),
80+
v: clientSecret,
81+
},
82+
{
83+
k: fmt.Sprintf("--oidc.clients.%s.name", lclientName),
84+
v: utils.Capitalize(lclientName),
85+
},
86+
}, "=")
87+
fmt.Fprintf(&buf, "\n")
88+
89+
// yaml config
90+
fmt.Fprintf(&buf, "YAML config:\n\n")
91+
92+
err = renderYamlToBuf(&buf, &model.OIDCConfig{
93+
Clients: map[string]model.OIDCClientConfig{
94+
lclientName: {
95+
ClientID: clientId,
96+
ClientSecret: clientSecret,
97+
Name: utils.Capitalize(lclientName),
98+
},
99+
},
100+
})
101+
102+
if err != nil {
103+
return fmt.Errorf("failed to render yaml config: %w", err)
104+
}
105+
106+
buf.WriteString("\n")
62107

63108
// footer
64-
fmt.Fprintln(&builder, "You can use either option to configure your OIDC client. Make sure to save these credentials as there is no way to regenerate them.")
109+
fmt.Fprintln(&buf, "You can use any of the above options to configure your OIDC client. Make sure to save these credentials as there is no way to regenerate them.")
65110

66111
// print
67-
out := builder.String()
112+
out := buf.String()
68113
fmt.Print(out)
69114
return nil
70115
},

‎cmd/tinyauth/create_user.go‎

Lines changed: 93 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ package main
33
import (
44
"errors"
55
"fmt"
6+
"os"
67
"strings"
78

89
"charm.land/huh/v2"
910
"github.com/tinyauthapp/paerser/cli"
10-
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
11+
"github.com/tinyauthapp/tinyauth/internal/model"
1112
"golang.org/x/crypto/bcrypt"
1213
)
1314

@@ -34,62 +35,107 @@ func createUserCmd() *cli.Command {
3435
&cli.FlagLoader{},
3536
}
3637

37-
return &cli.Command{
38+
cmd := &cli.Command{
3839
Name: "create",
3940
Description: "Create a user",
4041
Configuration: tCfg,
4142
Resources: loaders,
42-
Run: func(_ []string) error {
43-
log := logger.NewLogger().WithSimpleConfig()
44-
log.Init()
45-
46-
if tCfg.Interactive {
47-
form := huh.NewForm(
48-
huh.NewGroup(
49-
huh.NewInput().Title("Username").Value(&tCfg.Username).Validate((func(s string) error {
50-
if s == "" {
51-
return errors.New("username cannot be empty")
52-
}
53-
return nil
54-
})),
55-
huh.NewInput().Title("Password").Value(&tCfg.Password).Validate((func(s string) error {
56-
if s == "" {
57-
return errors.New("password cannot be empty")
58-
}
59-
return nil
60-
})),
61-
huh.NewSelect[bool]().Title("Format the output for Docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&tCfg.Docker),
62-
),
63-
)
64-
65-
theme := new(themeBase)
66-
err := form.WithTheme(theme).Run()
67-
68-
if err != nil {
69-
return fmt.Errorf("failed to run interactive prompt: %w", err)
70-
}
71-
}
43+
}
7244

73-
if tCfg.Username == "" || tCfg.Password == "" {
74-
return errors.New("username and password cannot be empty")
45+
cmd.Run = func(_ []string) error {
46+
if tCfg.Interactive {
47+
form := huh.NewForm(
48+
huh.NewGroup(
49+
huh.NewInput().Title("Username").Value(&tCfg.Username).Validate(func(s string) error {
50+
if s == "" {
51+
return errors.New("username cannot be empty")
52+
}
53+
if strings.Contains(s, ":") {
54+
return errors.New("username cannot contain ':'")
55+
}
56+
return nil
57+
}),
58+
huh.NewInput().Title("Password").Value(&tCfg.Password).Validate(func(s string) error {
59+
if s == "" {
60+
return errors.New("password cannot be empty")
61+
}
62+
return nil
63+
}),
64+
huh.NewSelect[bool]().Title("Format the output for Docker?").Options(huh.NewOption("Yes", true), huh.NewOption("No", false)).Value(&tCfg.Docker),
65+
),
66+
)
67+
68+
theme := new(themeBase)
69+
70+
err := form.WithTheme(theme).Run()
71+
if err != nil {
72+
return fmt.Errorf("failed to run interactive prompt: %w", err)
7573
}
74+
}
7675

77-
log.App.Info().Str("username", tCfg.Username).Msg("Creating user")
76+
if tCfg.Username == "" || tCfg.Password == "" {
77+
cmd.PrintHelp(os.Stdout)
78+
return errors.New("username and password cannot be empty")
79+
}
7880

79-
passwd, err := bcrypt.GenerateFromPassword([]byte(tCfg.Password), bcrypt.DefaultCost)
80-
if err != nil {
81-
return fmt.Errorf("failed to hash password: %w", err)
82-
}
81+
if strings.Contains(tCfg.Username, ":") {
82+
return errors.New("username cannot contain ':'")
83+
}
8384

84-
// If docker format is enabled, escape the dollar sign
85-
passwdStr := string(passwd)
86-
if tCfg.Docker {
87-
passwdStr = strings.ReplaceAll(passwdStr, "$", "$$")
88-
}
85+
passwd, err := bcrypt.GenerateFromPassword([]byte(tCfg.Password), bcrypt.DefaultCost)
86+
if err != nil {
87+
return fmt.Errorf("failed to hash password: %w", err)
88+
}
89+
90+
// Only the docker compose output needs $ escaped, the raw hash is correct everywhere else
91+
passwdStr := string(passwd)
92+
outputStr := passwdStr
93+
94+
if tCfg.Docker {
95+
outputStr = strings.ReplaceAll(passwdStr, "$", "$$")
96+
}
97+
98+
user := fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)
99+
escapedUser := fmt.Sprintf("%s:%s", tCfg.Username, outputStr)
89100

90-
log.App.Info().Str("user", fmt.Sprintf("%s:%s", tCfg.Username, passwdStr)).Msg("User created")
101+
buf := strings.Builder{}
91102

92-
return nil
93-
},
103+
// header
104+
fmt.Fprintf(&buf, "Created user '%s'.\n\n", tCfg.Username)
105+
106+
// environment variable
107+
fmt.Fprint(&buf, "Environment variable:\n\n")
108+
renderToBuf(&buf, []kv{
109+
{"TINYAUTH_AUTH_USERS", escapedUser},
110+
}, "=")
111+
112+
// cli flags
113+
fmt.Fprint(&buf, "\nCLI flags:\n\n")
114+
renderToBuf(&buf, []kv{
115+
{"--auth.users", user},
116+
}, "=")
117+
118+
// yaml config
119+
fmt.Fprint(&buf, "\nYAML config:\n\n")
120+
121+
err = renderYamlToBuf(&buf, &model.Config{
122+
Auth: model.AuthConfig{
123+
Users: []string{user},
124+
},
125+
})
126+
127+
if err != nil {
128+
return fmt.Errorf("failed to render yaml config: %w", err)
129+
}
130+
131+
buf.WriteString("\n")
132+
133+
// footer
134+
fmt.Fprint(&buf, "Use your config option of choice to add the user to Tinyauth and then restart.")
135+
136+
fmt.Println(buf.String())
137+
return nil
94138
}
139+
140+
return cmd
95141
}

0 commit comments

Comments
 (0)