diff --git a/cli/login.go b/cli/login.go index 834ba73ce38a0..dd11d4e22b883 100644 --- a/cli/login.go +++ b/cli/login.go @@ -151,9 +151,12 @@ func (r *RootCmd) login() *serpent.Command { useTokenForSession bool ) cmd := &serpent.Command{ - Use: "login []", - Short: "Authenticate with Coder deployment", - Middleware: serpent.RequireRangeArgs(0, 1), + Use: "login []", + Short: "Authenticate with Coder deployment", + Middleware: serpent.Chain( + serpent.RequireRangeArgs(0, 1), + r.CheckExistingUserSession(), + ), Handler: func(inv *serpent.Invocation) error { ctx := inv.Context() rawURL := "" diff --git a/cli/login_test.go b/cli/login_test.go index 0428c332d02b0..ba6d56232f0c5 100644 --- a/cli/login_test.go +++ b/cli/login_test.go @@ -442,4 +442,48 @@ func TestLogin(t *testing.T) { require.NoError(t, err) require.Equal(t, selected, first.OrganizationID.String()) }) + + t.Run("ExistingUserValidTokenTTYWarnReloggin", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, nil) + coderdtest.CreateFirstUser(t, client) + + doneChan := make(chan struct{}) + root, _ := clitest.New(t, "login", "--force-tty", client.URL.String(), "--no-open") + pty := ptytest.New(t).Attach(root) + go func() { + defer close(doneChan) + err := root.Run() + assert.NoError(t, err) + }() + + pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with argument URL: '%s'", client.URL.String())) + pty.ExpectMatch("Paste your token here:") + pty.WriteLine(client.SessionToken()) + if runtime.GOOS != "windows" { + // For some reason, the match does not show up on Windows. + pty.ExpectMatch(client.SessionToken()) + } + pty.ExpectMatch("Welcome to Coder") + <-doneChan + + doneChan = make(chan struct{}) + root, _ = clitest.New(t, "login", "--force-tty", client.URL.String(), "--no-open") + pty = ptytest.New(t).Attach(root) + go func() { + defer close(doneChan) + err := root.Run() + assert.NoError(t, err) + }() + pty.ExpectMatch(fmt.Sprintf("You are already logged in to '%s'!", client.URL.String())) + pty.ExpectMatch(fmt.Sprintf("Attempting to authenticate with argument URL: '%s'", client.URL.String())) + pty.ExpectMatch("Paste your token here:") + pty.WriteLine(client.SessionToken()) + if runtime.GOOS != "windows" { + // For some reason, the match does not show up on Windows. + pty.ExpectMatch(client.SessionToken()) + } + pty.ExpectMatch("Welcome to Coder") + <-doneChan + }) } diff --git a/cli/root.go b/cli/root.go index 22d153c00f7f1..02f5715a2251d 100644 --- a/cli/root.go +++ b/cli/root.go @@ -546,6 +546,50 @@ func (r *RootCmd) InitClient(client *codersdk.Client) serpent.MiddlewareFunc { } } +func (r *RootCmd) CheckExistingUserSession() serpent.MiddlewareFunc { + return func(next serpent.HandlerFunc) serpent.HandlerFunc { + return func(inv *serpent.Invocation) error { + conf := r.createConfig() + var err error + // Read the client URL stored on disk. + if r.clientURL == nil || r.clientURL.String() == "" { + rawURL, err := conf.URL().Read() + // If the configuration files are absent, the user is logged out + if os.IsNotExist(err) { + return next(inv) + } + if err != nil { + return err + } + + r.clientURL, err = url.Parse(strings.TrimSpace(rawURL)) + if err != nil { + return err + } + } + // Read the token stored on disk. + if r.token == "" { + r.token, err = conf.Session().Read() + // Even if there isn't a token, we don't care. + if err != nil && !os.IsNotExist(err) { + return next(inv) + } + } + + // IF r.token and r.clientUR, exists then print warning "You are already logged in to $" + if r.token != "" && r.clientURL.String() != "" { + _, _ = fmt.Fprintf(inv.Stderr, Caret+"%s!\n", pretty.Sprint(cliui.DefaultStyles.Warn, "You are already logged in to "+r.clientURL.String()+"!")) + } + + // We remove the token and clientURL from the RootCmd, so the user can still go ahead and login + r.clientURL = nil + r.token = "" + + return next(inv) + } + } +} + // HeaderTransport creates a new transport that executes `--header-command` // if it is set to add headers for all outbound requests. func (r *RootCmd) HeaderTransport(ctx context.Context, serverURL *url.URL) (*codersdk.HeaderTransport, error) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy