Files
jira/jiracli/password.go
T
Justin Ko 225e1dcc05 Allow reading password from stdin
Allow reading password from stdin in `jira login`. This is useful for
combining the jira tool with other command-line utilities.
2019-06-05 14:08:09 -07:00

143 lines
3.7 KiB
Go

package jiracli
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
"gopkg.in/AlecAivazis/survey.v1"
"gopkg.in/Netflix-Skunkworks/go-jira.v1/jiradata"
)
func (o *GlobalOptions) ProvideAuthParams() *jiradata.AuthParams {
return &jiradata.AuthParams{
Username: o.Login.Value,
Password: o.GetPass(),
}
}
func (o *GlobalOptions) keyName() string {
user := o.Login.Value
if o.AuthMethod() == "api-token" {
user = "api-token:" + user
}
if o.PasswordSource.Value == "pass" {
if o.PasswordName.Value != "" {
return o.PasswordName.Value
}
return fmt.Sprintf("GoJira/%s", user)
}
return user
}
func (o *GlobalOptions) GetPass() string {
passwd := ""
if o.PasswordSource.Value != "" {
if o.PasswordSource.Value == "keyring" {
var err error
passwd, err = keyringGet(o.keyName())
if err != nil {
panic(err)
}
} else if o.PasswordSource.Value == "pass" {
if o.PasswordDirectory.Value != "" {
orig := os.Getenv("PASSWORD_STORE_DIR")
os.Setenv("PASSWORD_STORE_DIR", o.PasswordDirectory.Value)
defer os.Setenv("PASSWORD_STORE_DIR", orig)
}
if bin, err := exec.LookPath("pass"); err == nil {
buf := bytes.NewBufferString("")
cmd := exec.Command(bin, o.keyName())
cmd.Stdout = buf
cmd.Stderr = buf
if err := cmd.Run(); err == nil {
passwd = strings.TrimSpace(buf.String())
}
}
} else if o.PasswordSource.Value == "stdin" {
allBytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
panic(fmt.Sprintf("unable to read bytes from stdin: %s", err))
}
passwd = string(allBytes)
} else {
log.Warningf("Unknown password-source: %s", o.PasswordSource)
}
}
if passwd != "" {
return passwd
}
if passwd = os.Getenv("JIRA_API_TOKEN"); passwd != "" && o.AuthMethod() == "api-token" {
return passwd
}
prompt := fmt.Sprintf("Jira Password [%s]: ", o.Login)
help := ""
if o.AuthMethod() == "api-token" {
prompt = fmt.Sprintf("Jira API-Token [%s]: ", o.Login)
help = "API Tokens may be required by your Jira service endpoint: https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth/"
}
err := survey.AskOne(
&survey.Password{
Message: prompt,
Help: help,
},
&passwd,
nil,
)
if err != nil {
log.Errorf("%s", err)
panic(Exit{Code: 1})
}
o.SetPass(passwd)
return passwd
}
func (o *GlobalOptions) SetPass(passwd string) error {
if o.PasswordSource.Value == "keyring" {
// save password in keychain so that it can be used for subsequent http requests
err := keyringSet(o.keyName(), passwd)
if err != nil {
log.Errorf("Failed to set password in keyring: %s", err)
return err
}
} else if o.PasswordSource.Value == "pass" {
if o.PasswordDirectory.Value != "" {
orig := os.Getenv("PASSWORD_STORE_DIR")
os.Setenv("PASSWORD_STORE_DIR", o.PasswordDirectory.Value)
defer os.Setenv("PASSWORD_STORE_DIR", orig)
}
if bin, err := exec.LookPath("pass"); err == nil {
log.Debugf("using %s", bin)
passName := o.keyName()
if passwd != "" {
in := bytes.NewBufferString(fmt.Sprintf("%s\n%s\n", passwd, passwd))
out := bytes.NewBufferString("")
cmd := exec.Command(bin, "insert", "--force", passName)
cmd.Stdin = in
cmd.Stdout = out
cmd.Stderr = out
if err := cmd.Run(); err != nil {
return fmt.Errorf("Failed to insert password: %s", out.String())
}
} else {
// clear the `pass` entry on empty password
if err := exec.Command(bin, "rm", "--force", passName).Run(); err != nil {
return fmt.Errorf("Failed to clear password for %s", passName)
}
}
}
} else if o.PasswordSource.Value != "" {
return fmt.Errorf("Unknown password-source: %s", o.PasswordSource)
}
return nil
}