@@ -2,20 +2,30 @@ package cli
2
2
3
3
import (
4
4
"fmt"
5
+ "io/ioutil"
5
6
"net/url"
7
+ "os/exec"
6
8
"os/user"
9
+ "runtime"
7
10
"strings"
8
11
9
12
"github.com/fatih/color"
10
13
"github.com/go-playground/validator/v10"
11
14
"github.com/manifoldco/promptui"
15
+ "github.com/pkg/browser"
12
16
"github.com/spf13/cobra"
13
17
"golang.org/x/xerrors"
14
18
15
19
"github.com/coder/coder/coderd"
16
20
"github.com/coder/coder/codersdk"
17
21
)
18
22
23
+ const (
24
+ goosWindows = "windows"
25
+ goosLinux = "linux"
26
+ goosDarwin = "darwin"
27
+ )
28
+
19
29
func login () * cobra.Command {
20
30
return & cobra.Command {
21
31
Use : "login <url>" ,
@@ -116,21 +126,99 @@ func login() *cobra.Command {
116
126
if err != nil {
117
127
return xerrors .Errorf ("login with password: %w" , err )
118
128
}
119
- config := createConfig (cmd )
120
- err = config .Session ().Write (resp .SessionToken )
121
- if err != nil {
122
- return xerrors .Errorf ("write session token: %w" , err )
123
- }
124
- err = config .URL ().Write (serverURL .String ())
129
+
130
+ err = saveSessionToken (cmd , client , resp .SessionToken , serverURL )
125
131
if err != nil {
126
- return xerrors .Errorf ("write server url : %w" , err )
132
+ return xerrors .Errorf ("save session token : %w" , err )
127
133
}
128
134
129
- _ , _ = fmt .Fprintf (cmd .OutOrStdout (), "%s Welcome to Coder, %s! You're authenticated.\n " , color .HiBlackString (">" ), color .HiCyanString (username ))
130
135
return nil
131
136
}
132
137
138
+ authURL := * serverURL
139
+ authURL .Path = serverURL .Path + "/cli-auth"
140
+ if err := openURL (authURL .String ()); err != nil {
141
+ _ , _ = fmt .Fprintf (cmd .OutOrStdout (), "Open the following in your browser:\n \n \t %s\n \n " , authURL .String ())
142
+ } else {
143
+ _ , _ = fmt .Fprintf (cmd .OutOrStdout (), "Your browser has been opened to visit:\n \n \t %s\n \n " , authURL .String ())
144
+ }
145
+
146
+ apiKey , err := prompt (cmd , & promptui.Prompt {
147
+ Label : "Paste your token here:" ,
148
+ Validate : func (token string ) error {
149
+ client .SessionToken = token
150
+ _ , err := client .User (cmd .Context (), "me" )
151
+ if err != nil {
152
+ return xerrors .New ("That's not a valid token!" )
153
+ }
154
+ return err
155
+ },
156
+ })
157
+ if err != nil {
158
+ return xerrors .Errorf ("specify email prompt: %w" , err )
159
+ }
160
+
161
+ err = saveSessionToken (cmd , client , apiKey , serverURL )
162
+ if err != nil {
163
+ return xerrors .Errorf ("save session token after login: %w" , err )
164
+ }
165
+
133
166
return nil
134
167
},
135
168
}
136
169
}
170
+
171
+ func saveSessionToken (cmd * cobra.Command , client * codersdk.Client , sessionToken string , serverURL * url.URL ) error {
172
+ // Login to get user data - verify it is OK before persisting
173
+ client .SessionToken = sessionToken
174
+ resp , err := client .User (cmd .Context (), "me" )
175
+ if err != nil {
176
+ return xerrors .Errorf ("get user: " , err )
177
+ }
178
+
179
+ config := createConfig (cmd )
180
+ err = config .Session ().Write (sessionToken )
181
+ if err != nil {
182
+ return xerrors .Errorf ("write session token: %w" , err )
183
+ }
184
+ err = config .URL ().Write (serverURL .String ())
185
+ if err != nil {
186
+ return xerrors .Errorf ("write server url: %w" , err )
187
+ }
188
+
189
+ _ , _ = fmt .Fprintf (cmd .OutOrStdout (), "%s Welcome to Coder, %s! You're authenticated.\n " , color .HiBlackString (">" ), color .HiCyanString (resp .Username ))
190
+ return nil
191
+ }
192
+
193
+ // isWSL determines if coder-cli is running within Windows Subsystem for Linux
194
+ func isWSL () (bool , error ) {
195
+ if runtime .GOOS == goosDarwin || runtime .GOOS == goosWindows {
196
+ return false , nil
197
+ }
198
+ data , err := ioutil .ReadFile ("/proc/version" )
199
+ if err != nil {
200
+ return false , xerrors .Errorf ("read /proc/version: %w" , err )
201
+ }
202
+ return strings .Contains (strings .ToLower (string (data )), "microsoft" ), nil
203
+ }
204
+
205
+ // openURL opens the provided URL via user's default browser
206
+ func openURL (url string ) error {
207
+ var cmd string
208
+ var args []string
209
+
210
+ wsl , err := isWSL ()
211
+ if err != nil {
212
+ return xerrors .Errorf ("test running Windows Subsystem for Linux: %w" , err )
213
+ }
214
+
215
+ if wsl {
216
+ cmd = "cmd.exe"
217
+ args = []string {"/c" , "start" }
218
+ url = strings .ReplaceAll (url , "&" , "^&" )
219
+ args = append (args , url )
220
+ return exec .Command (cmd , args ... ).Start ()
221
+ }
222
+
223
+ return browser .OpenURL (url )
224
+ }
0 commit comments