Skip to content

Commit 81696f4

Browse files
committed
chore: put ui components together
1 parent d873973 commit 81696f4

File tree

13 files changed

+122
-75
lines changed

13 files changed

+122
-75
lines changed

cmd/login.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/numtide/nix-auth/internal/config"
99
"github.com/numtide/nix-auth/internal/provider"
10+
"github.com/numtide/nix-auth/internal/ui"
1011

1112
"github.com/spf13/cobra"
1213
)
@@ -96,10 +97,11 @@ func runLogin(cmd *cobra.Command, args []string) error {
9697

9798
existingToken, _ := cfg.GetToken(host)
9899
if existingToken != "" && !loginForce {
99-
fmt.Printf("A token for %s already exists. Do you want to replace it? [y/N] ", host)
100-
var response string
101-
fmt.Scanln(&response)
102-
if response != "y" && response != "Y" {
100+
confirm, err := ui.ReadYesNo(fmt.Sprintf("A token for %s already exists. Do you want to replace it? [y/N] ", host))
101+
if err != nil {
102+
return fmt.Errorf("failed to read confirmation: %w", err)
103+
}
104+
if !confirm {
103105
fmt.Println("Login cancelled.")
104106
return nil
105107
}

cmd/logout.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package cmd
22

33
import (
44
"fmt"
5+
"strconv"
56
"strings"
67

78
"github.com/numtide/nix-auth/internal/config"
89
"github.com/numtide/nix-auth/internal/provider"
10+
"github.com/numtide/nix-auth/internal/ui"
911

1012
"github.com/spf13/cobra"
1113
)
@@ -45,12 +47,19 @@ func runLogout(cmd *cobra.Command, args []string) error {
4547
for i, host := range hosts {
4648
fmt.Printf(" %d. %s\n", i+1, host)
4749
}
48-
fmt.Print("\nEnter number (or 0 to cancel): ")
4950

50-
var choice int
51-
fmt.Scanln(&choice)
51+
response, err := ui.ReadInput("\nEnter number (or 0 to cancel): ")
52+
if err != nil {
53+
return fmt.Errorf("failed to read choice: %w", err)
54+
}
55+
56+
choice, err := strconv.Atoi(response)
57+
if err != nil || choice < 0 || choice > len(hosts) {
58+
fmt.Println("Invalid choice. Logout cancelled.")
59+
return nil
60+
}
5261

53-
if choice == 0 || choice > len(hosts) {
62+
if choice == 0 {
5463
fmt.Println("Logout cancelled.")
5564
return nil
5665
}

cmd/set_token.go

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package cmd
22

33
import (
4-
"bufio"
54
"context"
65
"fmt"
7-
"os"
8-
"strings"
9-
"syscall"
106

117
"github.com/numtide/nix-auth/internal/config"
128
"github.com/numtide/nix-auth/internal/provider"
13-
"github.com/numtide/nix-auth/internal/util"
9+
"github.com/numtide/nix-auth/internal/ui"
1410
"github.com/spf13/cobra"
15-
"golang.org/x/term"
1611
)
1712

1813
var (
@@ -66,13 +61,14 @@ If a provider is specified or detected, the token will be validated before savin
6661
if tokenExists && !setTokenForce {
6762
existingToken, err := cfg.GetToken(host)
6863
if err == nil && existingToken != "" {
69-
maskedExisting := util.MaskToken(existingToken)
64+
maskedExisting := ui.MaskToken(existingToken)
7065
fmt.Printf("Token already exists for %s: %s\n", host, maskedExisting)
71-
fmt.Print("Replace it? (y/N): ")
7266

73-
var response string
74-
fmt.Scanln(&response)
75-
if response != "y" && response != "Y" {
67+
confirm, err := ui.ReadYesNo("Replace it? (y/N): ")
68+
if err != nil {
69+
return fmt.Errorf("failed to read confirmation: %w", err)
70+
}
71+
if !confirm {
7672
fmt.Println("Operation cancelled")
7773
return nil
7874
}
@@ -84,30 +80,14 @@ If a provider is specified or detected, the token will be validated before savin
8480
if len(args) == 2 {
8581
token = args[1]
8682
} else {
87-
fmt.Printf("Enter token for %s: ", host)
88-
89-
// Check if stdin is a terminal
90-
if term.IsTerminal(int(syscall.Stdin)) {
91-
// Use secure password input for terminals
92-
byteToken, err := term.ReadPassword(int(syscall.Stdin))
93-
fmt.Println() // Add newline after password input
94-
if err != nil {
95-
return fmt.Errorf("failed to read token: %w", err)
96-
}
97-
token = string(byteToken)
98-
} else {
99-
// For non-terminal input (like tests or piped input)
100-
reader := bufio.NewReader(os.Stdin)
101-
tokenBytes, err := reader.ReadString('\n')
102-
if err != nil {
103-
return fmt.Errorf("failed to read token: %w", err)
104-
}
105-
token = strings.TrimSuffix(tokenBytes, "\n")
83+
var err error
84+
token, err = ui.ReadSecureInput(fmt.Sprintf("Enter token for %s: ", host))
85+
if err != nil {
86+
return fmt.Errorf("failed to read token: %w", err)
10687
}
10788
}
10889

109-
// Trim whitespace
110-
token = strings.TrimSpace(token)
90+
// Check if token is empty
11191
if token == "" {
11292
return fmt.Errorf("token cannot be empty")
11393
}
@@ -152,7 +132,7 @@ If a provider is specified or detected, the token will be validated before savin
152132
return fmt.Errorf("failed to set token: %w", err)
153133
}
154134

155-
maskedToken := util.MaskToken(token)
135+
maskedToken := ui.MaskToken(token)
156136
fmt.Printf("Successfully set token for %s: %s\n", host, maskedToken)
157137
fmt.Printf("Config saved to: %s\n", cfg.GetPath())
158138

cmd/set_token_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,4 +462,4 @@ func TestSetTokenCommandArgs(t *testing.T) {
462462
}
463463
})
464464
}
465-
}
465+
}

cmd/status.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
"github.com/numtide/nix-auth/internal/config"
1111
"github.com/numtide/nix-auth/internal/provider"
12-
"github.com/numtide/nix-auth/internal/util"
12+
"github.com/numtide/nix-auth/internal/ui"
1313

1414
"github.com/spf13/cobra"
1515
)
@@ -76,7 +76,7 @@ func runStatus(cmd *cobra.Command, args []string) error {
7676
// Validate token and get user info
7777
var statusStr string
7878
validationStatus, validationErr := prov.ValidateToken(ctx, token)
79-
79+
8080
switch validationStatus {
8181
case provider.ValidationStatusValid:
8282
statusStr = "✓ Valid"
@@ -100,7 +100,7 @@ func runStatus(cmd *cobra.Command, args []string) error {
100100
}
101101

102102
// Mask token for security
103-
maskedToken := util.MaskToken(token)
103+
maskedToken := ui.MaskToken(token)
104104
fmt.Fprintf(w, " Token\t%s\n", maskedToken)
105105

106106
// Show token scopes

internal/provider/detection_helpers.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
func detectGiteaOrForgejo(ctx context.Context, client *http.Client, host string) (Provider, error) {
1313
// Known hosts
1414
lowerHost := strings.ToLower(host)
15-
15+
1616
// Codeberg is known to be Forgejo
1717
if lowerHost == "codeberg.org" {
1818
return &ForgejoProvider{
@@ -23,7 +23,7 @@ func detectGiteaOrForgejo(ctx context.Context, client *http.Client, host string)
2323
},
2424
}, nil
2525
}
26-
26+
2727
// Gitea.com and gitea.io are known Gitea instances
2828
if lowerHost == "gitea.com" || lowerHost == "gitea.io" {
2929
return &GiteaProvider{
@@ -55,7 +55,7 @@ func detectGiteaOrForgejo(ctx context.Context, client *http.Client, host string)
5555
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
5656
return nil, nil // Not a Gitea/Forgejo instance
5757
}
58-
58+
5959
// Check if it's Forgejo (includes "forgejo" in version string)
6060
if strings.Contains(strings.ToLower(data.Version), "forgejo") {
6161
return &ForgejoProvider{
@@ -66,7 +66,7 @@ func detectGiteaOrForgejo(ctx context.Context, client *http.Client, host string)
6666
},
6767
}, nil
6868
}
69-
69+
7070
// Otherwise it's Gitea
7171
if data.Version != "" {
7272
return &GiteaProvider{
@@ -80,4 +80,4 @@ func detectGiteaOrForgejo(ctx context.Context, client *http.Client, host string)
8080
}
8181

8282
return nil, nil // Not a Gitea/Forgejo instance
83-
}
83+
}

internal/provider/device_flow.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import (
44
"fmt"
55

66
"github.com/cli/browser"
7+
"github.com/numtide/nix-auth/internal/ui"
78
)
89

910
// DisplayDeviceCode shows the device code and prompts the user to copy it
1011
func DisplayDeviceCode(code string) {
1112
fmt.Println()
1213
fmt.Printf("One-time code: %s\n", code)
1314
fmt.Println()
14-
fmt.Printf("Copy the code above and press Enter to continue...")
15-
fmt.Scanln()
15+
_, _ = ui.ReadInput("Copy the code above and press Enter to continue...")
1616
}
1717

1818
// DisplayURLAndOpenBrowser shows the authorization URL and attempts to open it in the browser

internal/provider/forgejo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ func NewForgejoProviderForHost(ctx context.Context, client *http.Client, host st
4545
if err != nil {
4646
return nil, err
4747
}
48-
48+
4949
// Check if it's actually a Forgejo provider
5050
if provider != nil && provider.Name() == "forgejo" {
5151
return provider, nil
5252
}
53-
53+
5454
return nil, nil // Not a Forgejo instance
5555
}
5656

internal/provider/gitea.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ func NewGiteaProviderForHost(ctx context.Context, client *http.Client, host stri
2929
if err != nil {
3030
return nil, err
3131
}
32-
32+
3333
// Check if it's actually a Gitea provider
3434
if provider != nil && provider.Name() == "gitea" {
3535
return provider, nil
3636
}
37-
37+
3838
return nil, nil // Not a Gitea instance
3939
}
4040

internal/provider/pat_provider.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99

1010
"github.com/cli/browser"
11+
"github.com/numtide/nix-auth/internal/ui"
1112
)
1213

1314
// PersonalAccessTokenProvider provides common functionality for providers that use Personal Access Tokens
@@ -70,8 +71,7 @@ func (p *PersonalAccessTokenProvider) Authenticate(ctx context.Context) (string,
7071
fmt.Println("5. Copy the generated token")
7172
fmt.Println()
7273

73-
fmt.Println("Press Enter to open your browser and continue...")
74-
fmt.Scanln()
74+
_, _ = ui.ReadInput("Press Enter to open your browser and continue...")
7575

7676
tokenURL := fmt.Sprintf("%s/user/settings/applications", p.getBaseURL())
7777
fmt.Printf("Opening %s in your browser...\n", tokenURL)
@@ -82,14 +82,12 @@ func (p *PersonalAccessTokenProvider) Authenticate(ctx context.Context) (string,
8282
}
8383

8484
fmt.Println()
85-
var token string
86-
fmt.Print("Enter your Personal Access Token: ")
8785
// Don't use the context here - user input should not be subject to timeout
88-
if _, err := fmt.Scanln(&token); err != nil {
86+
token, err := ui.ReadSecureInput("Enter your Personal Access Token: ")
87+
if err != nil {
8988
return "", fmt.Errorf("failed to read token: %w", err)
9089
}
9190

92-
token = strings.TrimSpace(token)
9391
if token == "" {
9492
return "", fmt.Errorf("token cannot be empty")
9593
}

0 commit comments

Comments
 (0)