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 }