113 lines
2.5 KiB
Go
113 lines
2.5 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"flag"
|
||
|
"log"
|
||
|
"mime/multipart"
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"github.com/google/subcommands"
|
||
|
"github.com/manifoldco/promptui"
|
||
|
)
|
||
|
|
||
|
type loginCmd struct {
|
||
|
username string
|
||
|
}
|
||
|
|
||
|
func (loginCmd) Name() string { return "login" }
|
||
|
func (loginCmd) Synopsis() string { return "logs into wasmcloud" }
|
||
|
func (loginCmd) Usage() string {
|
||
|
return `wasmc login [options]
|
||
|
|
||
|
$ wasmc login -username Cadey
|
||
|
|
||
|
Logs into the wasmcloud API server and saves credentials to the global
|
||
|
configuration file. The password is always prompted by standard input.
|
||
|
|
||
|
Flags:
|
||
|
`
|
||
|
}
|
||
|
|
||
|
func (l *loginCmd) SetFlags(fs *flag.FlagSet) {
|
||
|
fs.StringVar(&l.username, "username", "", "wasmcloud username")
|
||
|
}
|
||
|
|
||
|
func (l *loginCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||
|
http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||
|
return http.ErrUseLastResponse
|
||
|
}
|
||
|
|
||
|
cfg, err := loadConfig()
|
||
|
if err != nil {
|
||
|
log.Printf("error loading config: %v", err)
|
||
|
return subcommands.ExitFailure
|
||
|
}
|
||
|
|
||
|
if l.username == "" {
|
||
|
prompt := promptui.Prompt{
|
||
|
Label: "Username",
|
||
|
}
|
||
|
|
||
|
result, err := prompt.Run()
|
||
|
if err != nil {
|
||
|
log.Printf("error reading username: %v", err)
|
||
|
return subcommands.ExitFailure
|
||
|
}
|
||
|
|
||
|
l.username = result
|
||
|
}
|
||
|
|
||
|
prompt := promptui.Prompt{
|
||
|
Label: "Password",
|
||
|
Mask: '*',
|
||
|
}
|
||
|
password, err := prompt.Run()
|
||
|
|
||
|
body := &bytes.Buffer{}
|
||
|
writer := multipart.NewWriter(body)
|
||
|
writer.WriteField("username", l.username)
|
||
|
writer.WriteField("password", password)
|
||
|
writer.Close()
|
||
|
|
||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, *apiServer+"/login", body)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||
|
|
||
|
resp, err := http.DefaultClient.Do(req)
|
||
|
if err != nil {
|
||
|
log.Printf("can't log into server %s: %v", *apiServer, err)
|
||
|
return subcommands.ExitFailure
|
||
|
}
|
||
|
|
||
|
if resp.StatusCode != http.StatusSeeOther {
|
||
|
log.Printf("wanted %d but got %d, see above", http.StatusSeeOther, resp.StatusCode)
|
||
|
return subcommands.ExitFailure
|
||
|
}
|
||
|
|
||
|
var cookie *http.Cookie
|
||
|
for _, ck := range resp.Cookies() {
|
||
|
if ck.Name == "wasmcloud-token" {
|
||
|
cookie = ck
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if cookie == nil {
|
||
|
log.Printf("impossible state? server didn't send us a token")
|
||
|
return subcommands.ExitFailure
|
||
|
}
|
||
|
|
||
|
cfg.Token = cookie.Value
|
||
|
|
||
|
log.Printf("success! Logged in as %s, token expires at %s", l.username, cookie.Expires.Format(time.RFC3339))
|
||
|
|
||
|
saveConfig(cfg)
|
||
|
|
||
|
return subcommands.ExitSuccess
|
||
|
}
|