Skip to content

Commit

Permalink
refactor password source, allow for "pass" to be used, update tests t…
Browse files Browse the repository at this point in the history
…o use `password-source: pass`
  • Loading branch information
coryb committed Dec 18, 2016
1 parent 09f8029 commit 5a71939
Show file tree
Hide file tree
Showing 17 changed files with 322 additions and 30 deletions.
8 changes: 2 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
sudo: true
before_install:
- sudo apt-get update && sudo apt-get install -y libgnome-keyring-dev
- sudo apt-get update && sudo apt-get install -y pass gnupg

language: go

Expand All @@ -14,8 +14,4 @@ script:
- make vet
- make lint
- make
- JIRACLOUD=1 ./t/100basic.t -w -a 2>&1

cache:
directories:
- t/.maven-cache
- export GNUPGHOME=$(pwd)/t/.gnupg && export PASSWORD_STORE_DIR=$(pwd)/t/.password-store && export JIRACLOUD=1 && ./t/100basic.t -w -a 2>&1
7 changes: 3 additions & 4 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"time"

"github.com/kballard/go-shellquote"
"github.com/tmc/keyring"
"gopkg.in/coryb/yaml.v2"
"gopkg.in/op/go-logging.v1"
)
Expand Down Expand Up @@ -215,11 +214,11 @@ func (c *Cli) makeRequest(req *http.Request) (resp *http.Response, err error) {
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")

if val, ok := c.opts["password-keyring"].(bool); ok && val && !strings.HasSuffix(req.URL.Path, "/rest/auth/1/session") {
if source, ok := c.opts["password-source"]; ok && !strings.HasSuffix(req.URL.Path, "/rest/auth/1/session") {
user, _ := c.opts["user"].(string)
password, _ := keyring.Get("go-jira", user)
password := c.GetPass(user)
if password == "" {
log.Warning("No password for user %s in keyring, please run the 'login' command first", user)
log.Warning("No password for user %s in %s, please run the 'login' command first", user, source)
} else {
req.SetBasicAuth(user, password)
}
Expand Down
19 changes: 3 additions & 16 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"os"
"strings"

"github.com/howeyc/gopass"
"github.com/tmc/keyring"
"gopkg.in/Netflix-Skunkworks/go-jira.v0/data"
// "github.com/kr/pretty"
)
Expand All @@ -23,13 +21,7 @@ func (c *Cli) CmdLogin() error {
req, _ := http.NewRequest("GET", uri, nil)
user, _ := c.opts["user"].(string)

fmt.Printf("Jira Password [%s]: ", user)
pw, err := gopass.GetPasswdMasked()
if err != nil {
return err
}
passwd := string(pw)

passwd := c.GetPass(user)
req.SetBasicAuth(user, passwd)

resp, err := c.makeRequest(req)
Expand All @@ -55,13 +47,8 @@ func (c *Cli) CmdLogin() error {
log.Warning("Authentication Failed: %s", reason)
continue
}
if val, ok := c.opts["password-keyring"].(bool); ok && val {
// save password in keychain so that it can be used for subsequent http requests
err := keyring.Set("go-jira", user, passwd)
if err != nil {
log.Errorf("Failed to set password in keyring: %s", err)
return err
}
if _, ok := c.opts["password-source"]; ok {
return c.SetPass(user, passwd)
}
break
} else {
Expand Down
71 changes: 71 additions & 0 deletions password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package jira

import (
"bytes"
"fmt"
"os/exec"
"strings"

"github.com/howeyc/gopass"
"github.com/tmc/keyring"
)

func (c *Cli) GetPass(user string) string {
passwd := ""
if source, ok := c.opts["password-source"].(string); ok {
if source == "keyring" {
passwd, _ = keyring.Get("go-jira", user)
} else if source == "pass" {
if bin, err := exec.LookPath("pass"); err == nil {
buf := bytes.NewBufferString("")
cmd := exec.Command(bin, fmt.Sprintf("GoJira/%s", user))
cmd.Stdout = buf
cmd.Stderr = buf
if err := cmd.Run(); err == nil {
passwd = strings.TrimSpace(buf.String())
}
}
} else {
log.Warningf("Unknown password-source: %s", source)
}
}

if passwd != "" {
return passwd
}
fmt.Printf("Jira Password [%s]: ", user)
pw, err := gopass.GetPasswdMasked()
if err != nil {
return ""
}
passwd = string(pw)
return passwd
}

func (c *Cli) SetPass(user, passwd string) error {
if source, ok := c.opts["password-source"].(string); ok {
if source == "keyring" {
// save password in keychain so that it can be used for subsequent http requests
err := keyring.Set("go-jira", user, passwd)
if err != nil {
log.Errorf("Failed to set password in keyring: %s", err)
return err
}
} else if source == "pass" {
if bin, err := exec.LookPath("pass"); err == nil {
in := bytes.NewBufferString(fmt.Sprintf("%s\n%s\n", passwd, passwd))
out := bytes.NewBufferString("")
cmd := exec.Command(bin, "insert", fmt.Sprintf("GoJira/%s", user))
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 {
return fmt.Errorf("Unknown password-source: %s", source)
}
}
return nil
}
236 changes: 236 additions & 0 deletions t/.gnupg/gpg.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# Options for GnuPG
# Copyright 1998, 1999, 2000, 2001, 2002, 2003,
# 2010 Free Software Foundation, Inc.
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Unless you specify which option file to use (with the command line
# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
# by default.
#
# An options file can contain any long options which are available in
# GnuPG. If the first non white space character of a line is a '#',
# this line is ignored. Empty lines are also ignored.
#
# See the man page for a list of options.

# Uncomment the following option to get rid of the copyright notice

#no-greeting

# If you have more than 1 secret key in your keyring, you may want to
# uncomment the following option and set your preferred keyid.

#default-key 621CC013

# If you do not pass a recipient to gpg, it will ask for one. Using
# this option you can encrypt to a default key. Key validation will
# not be done in this case. The second form uses the default key as
# default recipient.

#default-recipient some-user-id
#default-recipient-self

# Use --encrypt-to to add the specified key as a recipient to all
# messages. This is useful, for example, when sending mail through a
# mail client that does not automatically encrypt mail to your key.
# In the example, this option allows you to read your local copy of
# encrypted mail that you've sent to others.

#encrypt-to some-key-id

# By default GnuPG creates version 4 signatures for data files as
# specified by OpenPGP. Some earlier (PGP 6, PGP 7) versions of PGP
# require the older version 3 signatures. Setting this option forces
# GnuPG to create version 3 signatures.

#force-v3-sigs

# Because some mailers change lines starting with "From " to ">From "
# it is good to handle such lines in a special way when creating
# cleartext signatures; all other PGP versions do it this way too.

#no-escape-from-lines

# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
# GnuPG which is the native character set. Please check the man page
# for supported character sets. This character set is only used for
# metadata and not for the actual message which does not undergo any
# translation. Note that future version of GnuPG will change to UTF-8
# as default character set. In most cases this option is not required
# as GnuPG is able to figure out the correct charset at runtime.

#charset utf-8

# Group names may be defined like this:
# group mynames = paige 0x12345678 joe patti
#
# Any time "mynames" is a recipient (-r or --recipient), it will be
# expanded to the names "paige", "joe", and "patti", and the key ID
# "0x12345678". Note there is only one level of expansion - you
# cannot make an group that points to another group. Note also that
# if there are spaces in the recipient name, this will appear as two
# recipients. In these cases it is better to use the key ID.

#group mynames = paige 0x12345678 joe patti

# Lock the file only once for the lifetime of a process. If you do
# not define this, the lock will be obtained and released every time
# it is needed, which is usually preferable.

#lock-once

# GnuPG can send and receive keys to and from a keyserver. These
# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
# support).
#
# Example HKP keyserver:
# hkp://keys.gnupg.net
# hkp://subkeys.pgp.net
#
# Example email keyserver:
# mailto:[email protected]
#
# Example LDAP keyservers:
# ldap://keyserver.pgp.com
#
# Regular URL syntax applies, and you can set an alternate port
# through the usual method:
# hkp://keyserver.example.net:22742
#
# Most users just set the name and type of their preferred keyserver.
# Note that most servers (with the notable exception of
# ldap://keyserver.pgp.com) synchronize changes with each other. Note
# also that a single server name may actually point to multiple
# servers via DNS round-robin. hkp://keys.gnupg.net is an example of
# such a "server", which spreads the load over a number of physical
# servers. To see the IP address of the server actually used, you may use
# the "--keyserver-options debug".

keyserver hkp://keys.gnupg.net
#keyserver mailto:[email protected]
#keyserver ldap://keyserver.pgp.com

# Common options for keyserver functions:
#
# include-disabled : when searching, include keys marked as "disabled"
# on the keyserver (not all keyservers support this).
#
# no-include-revoked : when searching, do not include keys marked as
# "revoked" on the keyserver.
#
# verbose : show more information as the keys are fetched.
# Can be used more than once to increase the amount
# of information shown.
#
# use-temp-files : use temporary files instead of a pipe to talk to the
# keyserver. Some platforms (Win32 for one) always
# have this on.
#
# keep-temp-files : do not delete temporary files after using them
# (really only useful for debugging)
#
# http-proxy="proxy" : set the proxy to use for HTTP and HKP keyservers.
# This overrides the "http_proxy" environment variable,
# if any.
#
# auto-key-retrieve : automatically fetch keys as needed from the keyserver
# when verifying signatures or when importing keys that
# have been revoked by a revocation key that is not
# present on the keyring.
#
# no-include-attributes : do not include attribute IDs (aka "photo IDs")
# when sending keys to the keyserver.

#keyserver-options auto-key-retrieve

# Display photo user IDs in key listings

# list-options show-photos

# Display photo user IDs when a signature from a key with a photo is
# verified

# verify-options show-photos

# Use this program to display photo user IDs
#
# %i is expanded to a temporary file that contains the photo.
# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
# %k is expanded to the key ID of the key.
# %K is expanded to the long OpenPGP key ID of the key.
# %t is expanded to the extension of the image (e.g. "jpg").
# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
# %f is expanded to the fingerprint of the key.
# %% is %, of course.
#
# If %i or %I are not present, then the photo is supplied to the
# viewer on standard input. If your platform supports it, standard
# input is the best way to do this as it avoids the time and effort in
# generating and then cleaning up a secure temp file.
#
# If no photo-viewer is provided, GnuPG will look for xloadimage, eog,
# or display (ImageMagick). On Mac OS X and Windows, the default is
# to use your regular JPEG image viewer.
#
# Some other viewers:
# photo-viewer "qiv %i"
# photo-viewer "ee %i"
#
# This one saves a copy of the photo ID in your home directory:
# photo-viewer "cat > ~/photoid-for-key-%k.%t"
#
# Use your MIME handler to view photos:
# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"

# Passphrase agent
#
# We support the old experimental passphrase agent protocol as well as
# the new Assuan based one (currently available in the "newpg" package
# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
# you have to run an agent as daemon and use the option
#
# use-agent
#
# which tries to use the agent but will fallback to the regular mode
# if there is a problem connecting to the agent. The normal way to
# locate the agent is by looking at the environment variable
# GPG_AGENT_INFO which should have been set during gpg-agent startup.
# In certain situations the use of this variable is not possible, thus
# the option
#
# --gpg-agent-info=<path>:<pid>:1
#
# may be used to override it.

# Automatic key location
#
# GnuPG can automatically locate and retrieve keys as needed using the
# auto-key-locate option. This happens when encrypting to an email
# address (in the "[email protected]" form), and there are no
# [email protected] keys on the local keyring. This option takes the
# following arguments, in the order they are to be tried:
#
# cert = locate a key using DNS CERT, as specified in RFC-4398.
# GnuPG can handle both the PGP (key) and IPGP (URL + fingerprint)
# CERT methods.
#
# pka = locate a key using DNS PKA.
#
# ldap = locate a key using the PGP Universal method of checking
# "ldap://keys.(thedomain)". For example, encrypting to
# [email protected] will check ldap://keys.example.com.
#
# keyserver = locate a key using whatever keyserver is defined using
# the keyserver option.
#
# You may also list arbitrary keyservers here by URL.
#
# Try CERT, then PKA, then LDAP, then hkp://subkeys.net:
#auto-key-locate cert pka ldap hkp://subkeys.pgp.net
Binary file added t/.gnupg/pubring.gpg
Binary file not shown.
Binary file added t/.gnupg/random_seed
Binary file not shown.
Binary file added t/.gnupg/secring.gpg
Binary file not shown.
Binary file added t/.gnupg/trustdb.gpg
Binary file not shown.
2 changes: 1 addition & 1 deletion t/.jira.d/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/sh
echo password-source: pass
if [ -z "$JIRACLOUD" ]; then
echo endpoint: http://localhost:8080
echo user: gojira
echo password-keyring: true
else
echo endpoint: https://go-jira.atlassian.net
echo user: [email protected]
Expand Down
Loading

0 comments on commit 5a71939

Please sign in to comment.