wasmcloud/cmd/wasmcloud/login.go

115 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 init() {
http.DefaultClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
}
func (l *loginCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
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
}