Skip to content

Commit ba04bd6

Browse files
committed
Combine browser and auth-wait prompts in auth flow
1 parent 9c14931 commit ba04bd6

File tree

12 files changed

+367
-91
lines changed

12 files changed

+367
-91
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ require (
1111
github.com/docker/docker v28.5.2+incompatible
1212
github.com/docker/go-connections v0.6.0
1313
github.com/muesli/termenv v0.16.0
14-
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
1514
github.com/spf13/cobra v1.10.2
1615
github.com/spf13/viper v1.21.0
1716
github.com/stretchr/testify v1.11.1

go.sum

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw
121121
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
122122
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
123123
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
124-
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
125-
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
126124
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
127125
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
128126
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -184,7 +182,6 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQz
184182
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
185183
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
186184
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
187-
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
188185
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
189186
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
190187
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=

internal/auth/auth.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@ func (a *Auth) GetToken(ctx context.Context) (string, error) {
4141
return "", fmt.Errorf("authentication required: set LOCALSTACK_AUTH_TOKEN or run in interactive mode")
4242
}
4343

44-
output.EmitLog(a.sink, "No existing credentials found. Please log in:")
44+
output.EmitSecondaryLog(a.sink, "> Welcome to LSTK, LocalStack's command-line interface")
45+
output.EmitLog(a.sink, "")
4546
token, err := a.login.Login(ctx)
4647
if err != nil {
48+
if errors.Is(err, context.Canceled) {
49+
return "", err
50+
}
4751
output.EmitWarning(a.sink, "Authentication failed.")
4852
return "", err
4953
}

internal/auth/login.go

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/localstack/lstk/internal/api"
1010
"github.com/localstack/lstk/internal/env"
1111
"github.com/localstack/lstk/internal/output"
12-
"github.com/pkg/browser"
1312
)
1413

1514
type LoginProvider interface {
@@ -35,41 +34,23 @@ func (l *loginProvider) Login(ctx context.Context) (string, error) {
3534
}
3635

3736
authURL := fmt.Sprintf("%s/auth/request/%s", getWebAppURL(), authReq.ID)
38-
output.EmitLog(l.sink, fmt.Sprintf("Visit: %s", authURL))
39-
output.EmitLog(l.sink, fmt.Sprintf("Verification code: %s", authReq.Code))
37+
output.EmitLog(l.sink, "1. Open this link in your browser and sign in")
38+
output.EmitHighlightLog(l.sink, authURL)
4039

41-
// Ask whether to open the browser; ENTER or Y accepts (default yes), N skips
42-
browserCh := make(chan output.InputResponse, 1)
43-
output.EmitUserInputRequest(l.sink, output.UserInputRequestEvent{
44-
Prompt: "Open browser now?",
45-
Options: []output.InputOption{{Key: "y", Label: "Y"}, {Key: "n", Label: "n"}},
46-
ResponseCh: browserCh,
47-
})
48-
49-
select {
50-
case resp := <-browserCh:
51-
if resp.Cancelled {
52-
return "", context.Canceled
53-
}
54-
if resp.SelectedKey != "n" {
55-
if err := browser.OpenURL(authURL); err != nil {
56-
output.EmitLog(l.sink, fmt.Sprintf("Warning: Failed to open browser: %v", err))
57-
}
58-
}
59-
case <-ctx.Done():
60-
return "", ctx.Err()
61-
}
40+
output.EmitLog(l.sink, "")
41+
output.EmitLog(l.sink, "2. Enter this one-time verification code after you log in")
42+
output.EmitHighlightLog(l.sink, authReq.Code)
43+
output.EmitLog(l.sink, "")
6244

63-
// Wait for the user to complete authentication in the browser
64-
enterCh := make(chan output.InputResponse, 1)
45+
responseCh := make(chan output.InputResponse, 1)
6546
output.EmitUserInputRequest(l.sink, output.UserInputRequestEvent{
66-
Prompt: "Waiting for authentication",
67-
Options: []output.InputOption{{Key: "enter", Label: "Press ENTER when complete"}},
68-
ResponseCh: enterCh,
47+
Prompt: "Waiting for authentication... (Press ENTER when complete)",
48+
Options: []output.InputOption{{Key: "enter", Label: ""}},
49+
ResponseCh: responseCh,
6950
})
7051

7152
select {
72-
case resp := <-enterCh:
53+
case resp := <-responseCh:
7354
if resp.Cancelled {
7455
return "", context.Canceled
7556
}

internal/output/events.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package output
22

33
type Event interface {
4-
LogEvent | WarningEvent | ContainerStatusEvent | ProgressEvent | UserInputRequestEvent | ContainerLogLineEvent
4+
LogEvent | HighlightLogEvent | SecondaryLogEvent | WarningEvent | ContainerStatusEvent | ProgressEvent | UserInputRequestEvent | ContainerLogLineEvent
55
}
66

77
type Sink interface {
@@ -22,6 +22,14 @@ type LogEvent struct {
2222
Message string
2323
}
2424

25+
type HighlightLogEvent struct {
26+
Message string
27+
}
28+
29+
type SecondaryLogEvent struct {
30+
Message string
31+
}
32+
2533
type WarningEvent struct {
2634
Message string
2735
}
@@ -72,6 +80,14 @@ func EmitLog(sink Sink, message string) {
7280
Emit(sink, LogEvent{Message: message})
7381
}
7482

83+
func EmitHighlightLog(sink Sink, message string) {
84+
Emit(sink, HighlightLogEvent{Message: message})
85+
}
86+
87+
func EmitSecondaryLog(sink Sink, message string) {
88+
Emit(sink, SecondaryLogEvent{Message: message})
89+
}
90+
7591
func EmitWarning(sink Sink, message string) {
7692
Emit(sink, WarningEvent{Message: message})
7793
}

internal/output/format.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ func FormatEventLine(event any) (string, bool) {
1010
switch e := event.(type) {
1111
case LogEvent:
1212
return e.Message, true
13+
case HighlightLogEvent:
14+
return e.Message, true
15+
case SecondaryLogEvent:
16+
return e.Message, true
1317
case WarningEvent:
1418
return fmt.Sprintf("Warning: %s", e.Message), true
1519
case ContainerStatusEvent:
@@ -58,16 +62,30 @@ func formatProgressLine(e ProgressEvent) (string, bool) {
5862
}
5963

6064
func formatUserInputRequest(e UserInputRequestEvent) string {
61-
switch len(e.Options) {
65+
lines := strings.Split(e.Prompt, "\n")
66+
firstLine := lines[0]
67+
rest := lines[1:]
68+
labels := make([]string, 0, len(e.Options))
69+
for _, opt := range e.Options {
70+
if opt.Label != "" {
71+
labels = append(labels, opt.Label)
72+
}
73+
}
74+
75+
switch len(labels) {
6276
case 0:
63-
return e.Prompt
77+
if len(rest) == 0 {
78+
return firstLine
79+
}
80+
return strings.Join(append([]string{firstLine}, rest...), "\n")
6481
case 1:
65-
return fmt.Sprintf("%s (%s)", e.Prompt, e.Options[0].Label)
82+
firstLine = fmt.Sprintf("%s (%s)", firstLine, labels[0])
6683
default:
67-
labels := make([]string, len(e.Options))
68-
for i, opt := range e.Options {
69-
labels[i] = opt.Label
70-
}
71-
return fmt.Sprintf("%s [%s]", e.Prompt, strings.Join(labels, "/"))
84+
firstLine = fmt.Sprintf("%s [%s]", firstLine, strings.Join(labels, "/"))
85+
}
86+
87+
if len(rest) == 0 {
88+
return firstLine
7289
}
90+
return strings.Join(append([]string{firstLine}, rest...), "\n")
7391
}

0 commit comments

Comments
 (0)