-
Notifications
You must be signed in to change notification settings - Fork 76
Expand file tree
/
Copy pathlogin.go
More file actions
118 lines (96 loc) · 3.5 KB
/
Copy pathlogin.go
File metadata and controls
118 lines (96 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"context"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
)
func init() {
usage := `'src login' helps you authenticate 'src' to access a Sourcegraph instance with your user credentials.
Usage:
src login SOURCEGRAPH_URL
Examples:
Authenticate to a Sourcegraph instance at https://sourcegraph.example.com:
$ src login https://sourcegraph.example.com
Authenticate to Sourcegraph.com:
$ src login https://sourcegraph.com
`
flagSet := flag.NewFlagSet("login", flag.ExitOnError)
usageFunc := func() {
fmt.Fprintln(flag.CommandLine.Output(), usage)
}
handler := func(args []string) error {
if err := flagSet.Parse(args); err != nil {
return err
}
if len(args) != 1 {
return &usageError{errors.New("expected exactly one argument: the Sourcegraph URL")}
}
endpointArg := args[0]
return loginCmd(context.Background(), cfg, endpointArg, os.Stdout)
}
commands = append(commands, &command{
flagSet: flagSet,
handler: handler,
usageFunc: usageFunc,
})
}
var exitCode1 = &exitCodeError{exitCode: 1}
func loginCmd(ctx context.Context, cfg *config, endpointArg string, out io.Writer) error {
endpointArg = cleanEndpoint(endpointArg)
printProblem := func(problem string) {
fmt.Fprintf(out, "❌ Problem: %s\n", problem)
}
createAccessTokenMessage := fmt.Sprintf("\n"+`🛠 To fix: Create an access token at %s/user/settings/tokens, then set the following environment variables:
SRC_ENDPOINT=%s
SRC_ACCESS_TOKEN=(the access token you just created)
To verify that it's working, run this command again.
`, endpointArg, endpointArg)
if cfg.ConfigFilePath != "" {
fmt.Fprintln(out)
fmt.Fprintf(out, "⚠️ Warning: Configuring src with a JSON file is deprecated. Please migrate to using the env vars SRC_ENDPOINT and SRC_ACCESS_TOKEN instead, and then remove %s. See https://github.com/sourcegraph/src-cli#readme for more information.\n", cfg.ConfigFilePath)
}
noToken := cfg.AccessToken == ""
endpointConflict := endpointArg != cfg.Endpoint
if noToken || endpointConflict {
fmt.Fprintln(out)
switch {
case noToken:
printProblem("No access token is configured.")
case endpointConflict:
printProblem(fmt.Sprintf("The configured endpoint is %s, not %s.", cfg.Endpoint, endpointArg))
}
fmt.Fprintln(out, createAccessTokenMessage)
return exitCode1
}
// See if the user is already authenticated.
query := `query CurrentUser { currentUser { username } }`
var result struct {
CurrentUser *struct{ Username string }
}
client := cfg.apiClient(nil, ioutil.Discard)
if _, err := client.NewRequest(query, nil).Do(ctx, &result); err != nil {
if strings.HasPrefix(err.Error(), "error: 401 Unauthorized") || strings.HasPrefix(err.Error(), "error: 403 Forbidden") {
printProblem("Invalid access token.")
} else {
printProblem(fmt.Sprintf("Error communicating with %s: %s", endpointArg, err))
}
fmt.Fprintln(out, createAccessTokenMessage)
fmt.Fprintln(out, " (If you need to supply custom HTTP request headers, see information about SRC_HEADER_* env vars at https://github.com/sourcegraph/src-cli/blob/main/AUTH_PROXY.md.)")
return exitCode1
}
if result.CurrentUser == nil {
// This should never happen; we verified there is an access token, so there should always be
// a user.
printProblem(fmt.Sprintf("Unable to determine user on %s.", endpointArg))
return exitCode1
}
fmt.Fprintln(out)
fmt.Fprintf(out, "✔️ Authenticated as %s on %s\n", result.CurrentUser.Username, endpointArg)
fmt.Fprintln(out)
return nil
}